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