1 /* 2 * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.asm; 26 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.function.Consumer; 32 33 import jdk.vm.ci.code.Register; 34 import jdk.vm.ci.code.StackSlot; 35 import jdk.vm.ci.code.TargetDescription; 36 37 /** 38 * The platform-independent base class for the assembler. 39 */ 40 public abstract class Assembler { 41 42 public abstract static class CodeAnnotation { 43 /** 44 * The position (bytes from the beginning of the method) of the annotated instruction. 45 */ 46 public final int instructionPosition; 47 48 protected CodeAnnotation(int instructionStartPosition) { 49 this.instructionPosition = instructionStartPosition; 50 } 51 } 52 53 public final TargetDescription target; 54 private List<LabelHint> jumpDisplacementHints; 55 56 /** 57 * Backing code buffer. 58 */ 59 private final Buffer codeBuffer; 60 61 protected Consumer<CodeAnnotation> codePatchingAnnotationConsumer; 62 63 public Assembler(TargetDescription target) { 64 this.target = target; 65 this.codeBuffer = new Buffer(target.arch.getByteOrder()); 66 } 67 68 public void setCodePatchingAnnotationConsumer(Consumer<CodeAnnotation> codeAnnotationConsumer) { 69 assert this.codePatchingAnnotationConsumer == null : "overwriting existing value"; 70 this.codePatchingAnnotationConsumer = codeAnnotationConsumer; 71 } 72 73 /** 74 * Returns the current position of the underlying code buffer. 75 * 76 * @return current position in code buffer 77 */ 78 public int position() { 79 return codeBuffer.position(); 80 } 81 82 public final void emitByte(int x) { 83 codeBuffer.emitByte(x); 84 } 85 86 public final void emitShort(int x) { 87 codeBuffer.emitShort(x); 88 } 89 90 public final void emitInt(int x) { 91 codeBuffer.emitInt(x); 92 } 93 94 public final void emitLong(long x) { 95 codeBuffer.emitLong(x); 96 } 97 98 public final void emitByte(int b, int pos) { 99 codeBuffer.emitByte(b, pos); 100 } 101 102 public final void emitShort(int b, int pos) { 103 codeBuffer.emitShort(b, pos); 104 } 105 106 public final void emitInt(int b, int pos) { 107 codeBuffer.emitInt(b, pos); 108 } 109 110 public final void emitLong(long b, int pos) { 111 codeBuffer.emitLong(b, pos); 112 } 113 114 public final int getByte(int pos) { 115 return codeBuffer.getByte(pos); 116 } 117 118 public final int getShort(int pos) { 119 return codeBuffer.getShort(pos); 120 } 121 122 public final int getInt(int pos) { 123 return codeBuffer.getInt(pos); 124 } 125 126 private static final String NEWLINE = System.getProperty("line.separator"); 127 128 /** 129 * Some GPU architectures have a text based encoding. 130 */ 131 public final void emitString(String x) { 132 emitString0("\t"); // XXX REMOVE ME pretty-printing 133 emitString0(x); 134 emitString0(NEWLINE); 135 } 136 137 // XXX for pretty-printing 138 public final void emitString0(String x) { 139 codeBuffer.emitBytes(x.getBytes(), 0, x.length()); 140 } 141 142 public void emitString(String s, int pos) { 143 codeBuffer.emitBytes(s.getBytes(), pos); 144 } 145 146 /** 147 * Closes this assembler. No extra data can be written to this assembler after this call. 148 * 149 * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not 150 * including) {@code position()} is returned 151 * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true} 152 */ 153 public byte[] close(boolean trimmedCopy) { 154 return codeBuffer.close(trimmedCopy); 155 } 156 157 public void bind(Label l) { 158 assert !l.isBound() : "can bind label only once"; 159 l.bind(position()); 160 l.patchInstructions(this); 161 } 162 163 public abstract void align(int modulus); 164 165 public abstract void jmp(Label l); 166 167 protected abstract void patchJumpTarget(int branch, int jumpTarget); 168 169 private Map<Label, String> nameMap; 170 171 /** 172 * Creates a name for a label. 173 * 174 * @param l the label for which a name is being created 175 * @param id a label identifier that is unique with the scope of this assembler 176 * @return a label name in the form of "L123" 177 */ 178 protected String createLabelName(Label l, int id) { 179 return "L" + id; 180 } 181 182 /** 183 * Gets a name for a label, creating it if it does not yet exist. By default, the returned name 184 * is only unique with the scope of this assembler. 185 */ 186 public String nameOf(Label l) { 187 if (nameMap == null) { 188 nameMap = new HashMap<>(); 189 } 190 String name = nameMap.get(l); 191 if (name == null) { 192 name = createLabelName(l, nameMap.size()); 193 nameMap.put(l, name); 194 } 195 return name; 196 } 197 198 /** 199 * This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an 200 * {@link AbstractAddress}. 201 */ 202 public abstract AbstractAddress makeAddress(Register base, int displacement); 203 204 /** 205 * Returns a target specific placeholder address that can be used for code patching. 206 * 207 * @param instructionStartPosition The start of the instruction, i.e., the value that is used as 208 * the key for looking up placeholder patching information. 209 */ 210 public abstract AbstractAddress getPlaceholder(int instructionStartPosition); 211 212 /** 213 * Emits a NOP instruction to advance the current PC. 214 */ 215 public abstract void ensureUniquePC(); 216 217 public void reset() { 218 codeBuffer.reset(); 219 captureLabelPositions(); 220 } 221 222 private void captureLabelPositions() { 223 if (jumpDisplacementHints == null) { 224 return; 225 } 226 for (LabelHint request : this.jumpDisplacementHints) { 227 request.capture(); 228 } 229 } 230 231 public LabelHint requestLabelHint(Label label) { 232 if (jumpDisplacementHints == null) { 233 jumpDisplacementHints = new ArrayList<>(); 234 } 235 LabelHint hint = new LabelHint(label, position()); 236 this.jumpDisplacementHints.add(hint); 237 return hint; 238 } 239 240 public InstructionCounter getInstructionCounter() { 241 throw new UnsupportedOperationException("Instruction counter is not implemented for " + this); 242 } 243 244 public static class LabelHint { 245 private Label label; 246 private int forPosition; 247 private int capturedTarget = -1; 248 249 protected LabelHint(Label label, int lastPosition) { 250 super(); 251 this.label = label; 252 this.forPosition = lastPosition; 253 } 254 255 protected void capture() { 256 this.capturedTarget = label.position(); 257 } 258 259 public int getTarget() { 260 assert isValid(); 261 return capturedTarget; 262 } 263 264 public int getPosition() { 265 assert isValid(); 266 return forPosition; 267 } 268 269 public boolean isValid() { 270 return capturedTarget >= 0; 271 } 272 } 273 274 /** 275 * Instruction counter class which gives the user of the assembler to count different kinds of 276 * instructions in the generated assembler code. 277 */ 278 public interface InstructionCounter { 279 String[] getSupportedInstructionTypes(); 280 281 int[] countInstructions(String[] instructionTypes, int beginPc, int endPc); 282 } 283 }