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}