1 /* 2 * Copyright (c) 2009, 2019, 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 CodeAnnotation(int instructionStartPosition)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 * Labels with instructions to be patched when it is {@linkplain Label#bind bound}. 58 */ 59 Label labelsWithPatches; 60 61 /** 62 * Backing code buffer. 63 */ 64 private final Buffer codeBuffer; 65 66 protected Consumer<CodeAnnotation> codePatchingAnnotationConsumer; 67 Assembler(TargetDescription target)68 public Assembler(TargetDescription target) { 69 this.target = target; 70 this.codeBuffer = new Buffer(target.arch.getByteOrder()); 71 } 72 setCodePatchingAnnotationConsumer(Consumer<CodeAnnotation> codeAnnotationConsumer)73 public void setCodePatchingAnnotationConsumer(Consumer<CodeAnnotation> codeAnnotationConsumer) { 74 assert this.codePatchingAnnotationConsumer == null : "overwriting existing value"; 75 this.codePatchingAnnotationConsumer = codeAnnotationConsumer; 76 } 77 78 /** 79 * Returns the current position of the underlying code buffer. 80 * 81 * @return current position in code buffer 82 */ position()83 public int position() { 84 return codeBuffer.position(); 85 } 86 emitByte(int x)87 public final void emitByte(int x) { 88 codeBuffer.emitByte(x); 89 } 90 emitShort(int x)91 public final void emitShort(int x) { 92 codeBuffer.emitShort(x); 93 } 94 emitInt(int x)95 public final void emitInt(int x) { 96 codeBuffer.emitInt(x); 97 } 98 emitLong(long x)99 public final void emitLong(long x) { 100 codeBuffer.emitLong(x); 101 } 102 emitByte(int b, int pos)103 public final void emitByte(int b, int pos) { 104 codeBuffer.emitByte(b, pos); 105 } 106 emitShort(int b, int pos)107 public final void emitShort(int b, int pos) { 108 codeBuffer.emitShort(b, pos); 109 } 110 emitInt(int b, int pos)111 public final void emitInt(int b, int pos) { 112 codeBuffer.emitInt(b, pos); 113 } 114 emitLong(long b, int pos)115 public final void emitLong(long b, int pos) { 116 codeBuffer.emitLong(b, pos); 117 } 118 getByte(int pos)119 public final int getByte(int pos) { 120 return codeBuffer.getByte(pos); 121 } 122 getShort(int pos)123 public final int getShort(int pos) { 124 return codeBuffer.getShort(pos); 125 } 126 getInt(int pos)127 public final int getInt(int pos) { 128 return codeBuffer.getInt(pos); 129 } 130 131 private static final String NEWLINE = System.lineSeparator(); 132 133 /** 134 * Some GPU architectures have a text based encoding. 135 */ emitString(String x)136 public final void emitString(String x) { 137 emitString0("\t"); // XXX REMOVE ME pretty-printing 138 emitString0(x); 139 emitString0(NEWLINE); 140 } 141 142 // XXX for pretty-printing emitString0(String x)143 public final void emitString0(String x) { 144 codeBuffer.emitBytes(x.getBytes(), 0, x.length()); 145 } 146 emitString(String s, int pos)147 public void emitString(String s, int pos) { 148 codeBuffer.emitBytes(s.getBytes(), pos); 149 } 150 151 /** 152 * Closes this assembler. No extra data can be written to this assembler after this call. 153 * 154 * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not 155 * including) {@code position()} is returned 156 * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true} 157 */ close(boolean trimmedCopy)158 public byte[] close(boolean trimmedCopy) { 159 checkAndClearLabelsWithPatches(); 160 return codeBuffer.close(trimmedCopy); 161 } 162 checkAndClearLabelsWithPatches()163 private void checkAndClearLabelsWithPatches() throws InternalError { 164 Label label = labelsWithPatches; 165 while (label != null) { 166 if (label.patchPositions != null) { 167 throw new InternalError("Label used by instructions at following offsets has not been bound: " + label.patchPositions); 168 } 169 Label next = label.nextWithPatches; 170 label.nextWithPatches = null; 171 label = next; 172 } 173 labelsWithPatches = null; 174 } 175 bind(Label l)176 public void bind(Label l) { 177 assert !l.isBound() : "can bind label only once"; 178 l.bind(position(), this); 179 } 180 align(int modulus)181 public abstract void align(int modulus); 182 jmp(Label l)183 public abstract void jmp(Label l); 184 patchJumpTarget(int branch, int jumpTarget)185 protected abstract void patchJumpTarget(int branch, int jumpTarget); 186 187 private Map<Label, String> nameMap; 188 189 /** 190 * Creates a name for a label. 191 * 192 * @param l the label for which a name is being created 193 * @param id a label identifier that is unique with the scope of this assembler 194 * @return a label name in the form of "L123" 195 */ createLabelName(Label l, int id)196 protected String createLabelName(Label l, int id) { 197 return "L" + id; 198 } 199 200 /** 201 * Gets a name for a label, creating it if it does not yet exist. By default, the returned name 202 * is only unique with the scope of this assembler. 203 */ nameOf(Label l)204 public String nameOf(Label l) { 205 if (nameMap == null) { 206 nameMap = new HashMap<>(); 207 } 208 String name = nameMap.get(l); 209 if (name == null) { 210 name = createLabelName(l, nameMap.size()); 211 nameMap.put(l, name); 212 } 213 return name; 214 } 215 216 /** 217 * This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an 218 * {@link AbstractAddress}. 219 */ makeAddress(Register base, int displacement)220 public abstract AbstractAddress makeAddress(Register base, int displacement); 221 222 /** 223 * Returns a target specific placeholder address that can be used for code patching. 224 * 225 * @param instructionStartPosition The start of the instruction, i.e., the value that is used as 226 * the key for looking up placeholder patching information. 227 */ getPlaceholder(int instructionStartPosition)228 public abstract AbstractAddress getPlaceholder(int instructionStartPosition); 229 230 /** 231 * Emits a NOP instruction to advance the current PC. 232 */ ensureUniquePC()233 public abstract void ensureUniquePC(); 234 reset()235 public void reset() { 236 codeBuffer.reset(); 237 captureLabelPositions(); 238 } 239 captureLabelPositions()240 private void captureLabelPositions() { 241 if (jumpDisplacementHints == null) { 242 return; 243 } 244 for (LabelHint request : this.jumpDisplacementHints) { 245 request.capture(); 246 } 247 } 248 requestLabelHint(Label label)249 public LabelHint requestLabelHint(Label label) { 250 if (jumpDisplacementHints == null) { 251 jumpDisplacementHints = new ArrayList<>(); 252 } 253 LabelHint hint = new LabelHint(label, position()); 254 this.jumpDisplacementHints.add(hint); 255 return hint; 256 } 257 getInstructionCounter()258 public InstructionCounter getInstructionCounter() { 259 throw new UnsupportedOperationException("Instruction counter is not implemented for " + this); 260 } 261 262 public static class LabelHint { 263 private Label label; 264 private int forPosition; 265 private int capturedTarget = -1; 266 LabelHint(Label label, int lastPosition)267 protected LabelHint(Label label, int lastPosition) { 268 super(); 269 this.label = label; 270 this.forPosition = lastPosition; 271 } 272 capture()273 protected void capture() { 274 this.capturedTarget = label.position(); 275 } 276 getTarget()277 public int getTarget() { 278 assert isValid(); 279 return capturedTarget; 280 } 281 getPosition()282 public int getPosition() { 283 assert isValid(); 284 return forPosition; 285 } 286 isValid()287 public boolean isValid() { 288 return capturedTarget >= 0; 289 } 290 } 291 292 /** 293 * Instruction counter class which gives the user of the assembler to count different kinds of 294 * instructions in the generated assembler code. 295 */ 296 public interface InstructionCounter { getSupportedInstructionTypes()297 String[] getSupportedInstructionTypes(); 298 countInstructions(String[] instructionTypes, int beginPc, int endPc)299 int[] countInstructions(String[] instructionTypes, int beginPc, int endPc); 300 } 301 } 302