001/* 002 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.asm; 024 025import java.nio.*; 026import java.util.*; 027 028import jdk.internal.jvmci.code.*; 029 030/** 031 * The platform-independent base class for the assembler. 032 */ 033public abstract class Assembler { 034 035 public final TargetDescription target; 036 private List<LabelHint> jumpDisplacementHints; 037 038 /** 039 * Backing code buffer. 040 */ 041 private final Buffer codeBuffer; 042 043 public Assembler(TargetDescription target) { 044 this.target = target; 045 if (target.arch.getByteOrder() == ByteOrder.BIG_ENDIAN) { 046 this.codeBuffer = new Buffer.BigEndian(); 047 } else { 048 this.codeBuffer = new Buffer.LittleEndian(); 049 } 050 } 051 052 /** 053 * Returns the current position of the underlying code buffer. 054 * 055 * @return current position in code buffer 056 */ 057 public int position() { 058 return codeBuffer.position(); 059 } 060 061 public final void emitByte(int x) { 062 codeBuffer.emitByte(x); 063 } 064 065 public final void emitShort(int x) { 066 codeBuffer.emitShort(x); 067 } 068 069 public final void emitInt(int x) { 070 codeBuffer.emitInt(x); 071 } 072 073 public final void emitLong(long x) { 074 codeBuffer.emitLong(x); 075 } 076 077 public final void emitByte(int b, int pos) { 078 codeBuffer.emitByte(b, pos); 079 } 080 081 public final void emitShort(int b, int pos) { 082 codeBuffer.emitShort(b, pos); 083 } 084 085 public final void emitInt(int b, int pos) { 086 codeBuffer.emitInt(b, pos); 087 } 088 089 public final void emitLong(long b, int pos) { 090 codeBuffer.emitLong(b, pos); 091 } 092 093 public final int getByte(int pos) { 094 return codeBuffer.getByte(pos); 095 } 096 097 public final int getShort(int pos) { 098 return codeBuffer.getShort(pos); 099 } 100 101 public final int getInt(int pos) { 102 return codeBuffer.getInt(pos); 103 } 104 105 private static final String NEWLINE = System.getProperty("line.separator"); 106 107 /** 108 * Some GPU architectures have a text based encoding. 109 */ 110 public final void emitString(String x) { 111 emitString0("\t"); // XXX REMOVE ME pretty-printing 112 emitString0(x); 113 emitString0(NEWLINE); 114 } 115 116 // XXX for pretty-printing 117 public final void emitString0(String x) { 118 codeBuffer.emitBytes(x.getBytes(), 0, x.length()); 119 } 120 121 public void emitString(String s, int pos) { 122 codeBuffer.emitBytes(s.getBytes(), pos); 123 } 124 125 /** 126 * Closes this assembler. No extra data can be written to this assembler after this call. 127 * 128 * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not 129 * including) {@code position()} is returned 130 * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true} 131 */ 132 public byte[] close(boolean trimmedCopy) { 133 return codeBuffer.close(trimmedCopy); 134 } 135 136 public void bind(Label l) { 137 assert !l.isBound() : "can bind label only once"; 138 l.bind(position()); 139 l.patchInstructions(this); 140 } 141 142 public abstract void align(int modulus); 143 144 public abstract void jmp(Label l); 145 146 protected abstract void patchJumpTarget(int branch, int jumpTarget); 147 148 private Map<Label, String> nameMap; 149 150 /** 151 * Creates a name for a label. 152 * 153 * @param l the label for which a name is being created 154 * @param id a label identifier that is unique with the scope of this assembler 155 * @return a label name in the form of "L123" 156 */ 157 protected String createLabelName(Label l, int id) { 158 return "L" + id; 159 } 160 161 /** 162 * Gets a name for a label, creating it if it does not yet exist. By default, the returned name 163 * is only unique with the scope of this assembler. 164 */ 165 public String nameOf(Label l) { 166 if (nameMap == null) { 167 nameMap = new HashMap<>(); 168 } 169 String name = nameMap.get(l); 170 if (name == null) { 171 name = createLabelName(l, nameMap.size()); 172 nameMap.put(l, name); 173 } 174 return name; 175 } 176 177 /** 178 * This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an 179 * {@link AbstractAddress}. 180 */ 181 public abstract AbstractAddress makeAddress(Register base, int displacement); 182 183 /** 184 * Returns a target specific placeholder address that can be used for code patching. 185 */ 186 public abstract AbstractAddress getPlaceholder(); 187 188 /** 189 * Emits a NOP instruction to advance the current PC. 190 */ 191 public abstract void ensureUniquePC(); 192 193 public void reset() { 194 codeBuffer.reset(); 195 captureLabelPositions(); 196 } 197 198 private void captureLabelPositions() { 199 if (jumpDisplacementHints == null) { 200 return; 201 } 202 for (LabelHint request : this.jumpDisplacementHints) { 203 request.capture(); 204 } 205 } 206 207 public LabelHint requestLabelHint(Label label) { 208 if (jumpDisplacementHints == null) { 209 jumpDisplacementHints = new ArrayList<>(); 210 } 211 LabelHint hint = new LabelHint(label, position()); 212 this.jumpDisplacementHints.add(hint); 213 return hint; 214 } 215 216 public InstructionCounter getInstructionCounter() { 217 throw new UnsupportedOperationException("Instruction counter is not implemented for " + this); 218 } 219 220 public static class LabelHint { 221 private Label label; 222 private int forPosition; 223 private int capturedTarget = -1; 224 225 protected LabelHint(Label label, int lastPosition) { 226 super(); 227 this.label = label; 228 this.forPosition = lastPosition; 229 } 230 231 protected void capture() { 232 this.capturedTarget = label.position(); 233 } 234 235 public int getTarget() { 236 assert isValid(); 237 return capturedTarget; 238 } 239 240 public int getPosition() { 241 assert isValid(); 242 return forPosition; 243 } 244 245 public boolean isValid() { 246 return capturedTarget >= 0; 247 } 248 } 249 250 /** 251 * Instruction counter class which gives the user of the assembler to count different kinds of 252 * instructions in the generated assembler code. 253 */ 254 public interface InstructionCounter { 255 String[] getSupportedInstructionTypes(); 256 257 int[] countInstructions(String[] instructionTypes, int beginPc, int endPc); 258 } 259}