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 private void checkAndClearLabelsWithPatches() throws InternalError { 166 Label label = labelsWithPatches; 167 while (label != null) { 168 if (label.patchPositions != null) { 169 throw new GraalError("Label used by instructions at following offsets has not been bound: %s", label.patchPositions); 170 } 171 Label next = label.nextWithPatches; 172 label.nextWithPatches = null; 173 label = next; 174 } 175 labelsWithPatches = null; 176 } 177 178 public void bind(Label l) { 179 assert !l.isBound() : "can bind label only once"; 180 l.bind(position(), this); 181 } 182 183 public abstract void align(int modulus); 184 185 public abstract void jmp(Label l); 186 187 protected abstract void patchJumpTarget(int branch, int jumpTarget); 188 189 private Map<Label, String> nameMap; 190 191 /** 192 * Creates a name for a label. 193 * 194 * @param l the label for which a name is being created 195 * @param id a label identifier that is unique with the scope of this assembler 196 * @return a label name in the form of "L123" 197 */ 198 protected String createLabelName(Label l, int id) { 199 return "L" + id; 200 } 201 202 /** 203 * Gets a name for a label, creating it if it does not yet exist. By default, the returned name 204 * is only unique with the scope of this assembler. 205 */ 206 public String nameOf(Label l) { 207 if (nameMap == null) { 208 nameMap = new HashMap<>(); 209 } 210 String name = nameMap.get(l); 211 if (name == null) { 212 name = createLabelName(l, nameMap.size()); 213 nameMap.put(l, name); 214 } 215 return name; 216 } 217 218 /** 219 * This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an 220 * {@link AbstractAddress}. 221 */ 222 public abstract AbstractAddress makeAddress(Register base, int displacement); 223 224 /** 225 * Returns a target specific placeholder address that can be used for code patching. 226 * 227 * @param instructionStartPosition The start of the instruction, i.e., the value that is used as 228 * the key for looking up placeholder patching information. 229 */ 230 public abstract AbstractAddress getPlaceholder(int instructionStartPosition); 231 232 /** 233 * Emits a NOP instruction to advance the current PC. 234 */ 235 public abstract void ensureUniquePC(); 236 237 public void reset() { 238 codeBuffer.reset(); 239 captureLabelPositions(); 240 } 241 242 private void captureLabelPositions() { 243 if (jumpDisplacementHints == null) { 244 return; 245 } 246 for (LabelHint request : this.jumpDisplacementHints) { 247 request.capture(); 248 } 249 } 250 251 public LabelHint requestLabelHint(Label label) { 252 if (jumpDisplacementHints == null) { 253 jumpDisplacementHints = new ArrayList<>(); 254 } 255 LabelHint hint = new LabelHint(label, position()); 256 this.jumpDisplacementHints.add(hint); 257 return hint; 258 } 259 260 public InstructionCounter getInstructionCounter() { 261 throw new UnsupportedOperationException("Instruction counter is not implemented for " + this); 262 } 263 264 public static class LabelHint { 265 private Label label; 266 private int forPosition; 267 private int capturedTarget = -1; 268 269 protected LabelHint(Label label, int lastPosition) { 270 super(); 271 this.label = label; 272 this.forPosition = lastPosition; 273 } 274 275 protected void capture() { 276 this.capturedTarget = label.position(); 277 } 278 279 public int getTarget() { 280 assert isValid(); 281 return capturedTarget; 282 } 283 284 public int getPosition() { 285 assert isValid(); 286 return forPosition; 287 } 288 289 public boolean isValid() { 290 return capturedTarget >= 0; 291 } 292 } 293 294 /** 295 * Instruction counter class which gives the user of the assembler to count different kinds of 296 * instructions in the generated assembler code. 297 */ 298 public interface InstructionCounter { 299 String[] getSupportedInstructionTypes(); 300 301 int[] countInstructions(String[] instructionTypes, int beginPc, int endPc); 302 } 303 }