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