TestAssembler.java revision 12573:9e0a7b1cbdef
1/*
2 * Copyright (c) 2015, 2016, 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
24package jdk.vm.ci.code.test;
25
26import jdk.vm.ci.code.CallingConvention;
27import jdk.vm.ci.code.CodeCacheProvider;
28import jdk.vm.ci.code.DebugInfo;
29import jdk.vm.ci.code.Register;
30import jdk.vm.ci.code.StackSlot;
31import jdk.vm.ci.code.ValueKindFactory;
32import jdk.vm.ci.code.site.Call;
33import jdk.vm.ci.code.site.ConstantReference;
34import jdk.vm.ci.code.site.DataPatch;
35import jdk.vm.ci.code.site.DataSectionReference;
36import jdk.vm.ci.code.site.Infopoint;
37import jdk.vm.ci.code.site.InfopointReason;
38import jdk.vm.ci.code.site.Mark;
39import jdk.vm.ci.code.site.Reference;
40import jdk.vm.ci.code.site.Site;
41import jdk.vm.ci.hotspot.HotSpotCompiledCode;
42import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
43import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
44import jdk.vm.ci.hotspot.HotSpotConstant;
45import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
46import jdk.vm.ci.meta.AllocatableValue;
47import jdk.vm.ci.meta.Assumptions.Assumption;
48import jdk.vm.ci.meta.InvokeTarget;
49import jdk.vm.ci.meta.JavaKind;
50import jdk.vm.ci.meta.PlatformKind;
51import jdk.vm.ci.meta.ResolvedJavaMethod;
52import jdk.vm.ci.meta.VMConstant;
53import jdk.vm.ci.meta.ValueKind;
54
55import java.nio.ByteBuffer;
56import java.nio.ByteOrder;
57import java.util.ArrayList;
58import java.util.Arrays;
59
60/**
61 * Simple assembler used by the code installation tests.
62 */
63public abstract class TestAssembler {
64
65    /**
66     * Emit the method prologue code (e.g. building the new stack frame).
67     */
68    public abstract void emitPrologue();
69
70    /**
71     * Emit the method epilogue code (e.g. the deopt handler).
72     */
73    public abstract void emitEpilogue();
74
75    /**
76     * Emit code to grow the stack frame.
77     *
78     * @param size the size in bytes that the stack should grow
79     */
80    public abstract void emitGrowStack(int size);
81
82    /**
83     * Get the register containing the first 32-bit integer argument.
84     */
85    public abstract Register emitIntArg0();
86
87    /**
88     * Get the register containing the second 32-bit integer argument.
89     */
90    public abstract Register emitIntArg1();
91
92    /**
93     * Emit code to add two 32-bit integer registers. May reuse one of the argument registers.
94     */
95    public abstract Register emitIntAdd(Register a, Register b);
96
97    /**
98     * Emit code to load a constant 32-bit integer to a register.
99     */
100    public abstract Register emitLoadInt(int value);
101
102    /**
103     * Emit code to load a constant 64-bit integer to a register.
104     */
105    public abstract Register emitLoadLong(long value);
106
107    /**
108     * Emit code to load a constant single-precision float to a register.
109     */
110    public abstract Register emitLoadFloat(float value);
111
112    /**
113     * Emit code to load a constant oop or metaspace pointer to a register. The pointer may be wide
114     * or narrow, depending on {@link HotSpotConstant#isCompressed() c.isCompressed()}.
115     */
116    public abstract Register emitLoadPointer(HotSpotConstant c);
117
118    /**
119     * Emit code to load a wide pointer from the {@link HotSpotCompiledCode#dataSection} to a
120     * register.
121     */
122    public abstract Register emitLoadPointer(DataSectionReference ref);
123
124    /**
125     * Emit code to load a narrow pointer from the {@link HotSpotCompiledCode#dataSection} to a
126     * register.
127     */
128    public abstract Register emitLoadNarrowPointer(DataSectionReference ref);
129
130    /**
131     * Emit code to load a (wide) pointer from a memory location to a register.
132     */
133    public abstract Register emitLoadPointer(Register base, int offset);
134
135    /**
136     * Emit code to store a 32-bit integer from a register to a new stack slot.
137     */
138    public abstract StackSlot emitIntToStack(Register a);
139
140    /**
141     * Emit code to store a 64-bit integer from a register to a new stack slot.
142     */
143    public abstract StackSlot emitLongToStack(Register a);
144
145    /**
146     * Emit code to store a single-precision float from a register to a new stack slot.
147     */
148    public abstract StackSlot emitFloatToStack(Register a);
149
150    /**
151     * Emit code to store a double-precision float from a register to a new stack slot.
152     */
153    public abstract StackSlot emitDoubleToStack(Register a);
154
155    /**
156     * Emit code to store a wide pointer from a register to a new stack slot.
157     */
158    public abstract StackSlot emitPointerToStack(Register a);
159
160    /**
161     * Emit code to store a narrow pointer from a register to a new stack slot.
162     */
163    public abstract StackSlot emitNarrowPointerToStack(Register a);
164
165    /**
166     * Emit code to uncompress a narrow pointer. The input pointer is guaranteed to be non-null.
167     */
168    public abstract Register emitUncompressPointer(Register compressed, long base, int shift);
169
170    /**
171     * Emit code to return from a function, returning a 32-bit integer.
172     */
173    public abstract void emitIntRet(Register a);
174
175    /**
176     * Emit code to return from a function, returning a single precision float.
177     */
178    public abstract void emitFloatRet(Register a);
179
180    /**
181     * Emit code to return from a function, returning a wide oop pointer.
182     */
183    public abstract void emitPointerRet(Register a);
184
185    /**
186     * Emit code that traps, forcing a deoptimization.
187     */
188    public abstract void emitTrap(DebugInfo info);
189
190    public final ValueKind<?> narrowOopKind;
191
192    protected final Buffer code;
193    protected final Buffer data;
194    private final ArrayList<Site> sites;
195    private final ArrayList<DataPatch> dataPatches;
196
197    protected final CodeCacheProvider codeCache;
198    protected final TestHotSpotVMConfig config;
199
200    private final Register[] registers;
201    private int nextRegister;
202
203    protected int frameSize;
204    private int stackAlignment;
205    private int curStackSlot;
206
207    private StackSlot deoptRescue;
208
209    public ValueKindFactory<TestValueKind> valueKindFactory = new ValueKindFactory<TestAssembler.TestValueKind>() {
210        public TestValueKind getValueKind(JavaKind javaKind) {
211            return (TestValueKind) TestAssembler.this.getValueKind(javaKind);
212        }
213    };
214
215    static class TestValueKind extends ValueKind<TestValueKind> {
216
217        TestValueKind(PlatformKind kind) {
218            super(kind);
219        }
220
221        @Override
222        public TestValueKind changeType(PlatformKind kind) {
223            return new TestValueKind(kind);
224        }
225    }
226
227    protected TestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config, int initialFrameSize, int stackAlignment, PlatformKind narrowOopKind, Register... registers) {
228        this.narrowOopKind = new TestValueKind(narrowOopKind);
229
230        this.code = new Buffer();
231        this.data = new Buffer();
232        this.sites = new ArrayList<>();
233        this.dataPatches = new ArrayList<>();
234
235        this.codeCache = codeCache;
236        this.config = config;
237
238        this.registers = registers;
239        this.nextRegister = 0;
240
241        this.frameSize = initialFrameSize;
242        this.stackAlignment = stackAlignment;
243        this.curStackSlot = initialFrameSize;
244    }
245
246    public ValueKind<?> getValueKind(JavaKind kind) {
247        return new TestValueKind(codeCache.getTarget().arch.getPlatformKind(kind));
248    }
249
250    protected Register newRegister() {
251        return registers[nextRegister++];
252    }
253
254    protected StackSlot newStackSlot(PlatformKind kind) {
255        growFrame(kind.getSizeInBytes());
256        return StackSlot.get(new TestValueKind(kind), -curStackSlot, true);
257    }
258
259    public int getOffset(StackSlot slot) {
260        return slot.getOffset(frameSize);
261    }
262
263    protected void growFrame(int sizeInBytes) {
264        curStackSlot += sizeInBytes;
265        if (curStackSlot > frameSize) {
266            int newFrameSize = curStackSlot;
267            if (newFrameSize % stackAlignment != 0) {
268                newFrameSize += stackAlignment - (newFrameSize % stackAlignment);
269            }
270            emitGrowStack(newFrameSize - frameSize);
271            frameSize = newFrameSize;
272        }
273    }
274
275    protected void setDeoptRescueSlot(StackSlot deoptRescue) {
276        this.deoptRescue = deoptRescue;
277    }
278
279    protected void recordCall(InvokeTarget target, int size, boolean direct, DebugInfo debugInfo) {
280        sites.add(new Call(target, code.position(), size, direct, debugInfo));
281    }
282
283    protected void recordMark(Object id) {
284        sites.add(new Mark(code.position(), id));
285    }
286
287    protected void recordImplicitException(DebugInfo info) {
288        sites.add(new Infopoint(code.position(), info, InfopointReason.IMPLICIT_EXCEPTION));
289    }
290
291    protected void recordDataPatchInCode(Reference ref) {
292        sites.add(new DataPatch(code.position(), ref));
293    }
294
295    protected void recordDataPatchInData(Reference ref) {
296        dataPatches.add(new DataPatch(data.position(), ref));
297    }
298
299    public DataSectionReference emitDataItem(HotSpotConstant c) {
300        DataSectionReference ref = new DataSectionReference();
301        ref.setOffset(data.position());
302
303        recordDataPatchInData(new ConstantReference((VMConstant) c));
304        if (c.isCompressed()) {
305            data.emitInt(0xDEADDEAD);
306        } else {
307            data.emitLong(0xDEADDEADDEADDEADL);
308        }
309
310        return ref;
311    }
312
313    public HotSpotCompiledCode finish(HotSpotResolvedJavaMethod method) {
314        int id = method.allocateCompileId(0);
315        byte[] finishedCode = code.finish();
316        Site[] finishedSites = sites.toArray(new Site[0]);
317        byte[] finishedData = data.finish();
318        DataPatch[] finishedDataPatches = dataPatches.toArray(new DataPatch[0]);
319        return new HotSpotCompiledNmethod(method.getName(), finishedCode, finishedCode.length, finishedSites, new Assumption[0], new ResolvedJavaMethod[]{method}, new Comment[0], finishedData, 16,
320                        finishedDataPatches, false, frameSize, deoptRescue, method, 0, id, 0L, false);
321    }
322
323    protected static class Buffer {
324
325        private ByteBuffer data = ByteBuffer.allocate(32).order(ByteOrder.nativeOrder());
326
327        private void ensureSize(int length) {
328            if (length >= data.limit()) {
329                byte[] newBuf = Arrays.copyOf(data.array(), length * 4);
330                ByteBuffer newData = ByteBuffer.wrap(newBuf);
331                newData.order(data.order());
332                newData.position(data.position());
333                data = newData;
334            }
335        }
336
337        public int position() {
338            return data.position();
339        }
340
341        public void emitByte(int b) {
342            ensureSize(data.position() + 1);
343            data.put((byte) (b & 0xFF));
344        }
345
346        public void emitShort(int b) {
347            ensureSize(data.position() + 2);
348            data.putShort((short) b);
349        }
350
351        public void emitInt(int b) {
352            ensureSize(data.position() + 4);
353            data.putInt(b);
354        }
355
356        public void emitLong(long b) {
357            ensureSize(data.position() + 8);
358            data.putLong(b);
359        }
360
361        public void emitFloat(float f) {
362            ensureSize(data.position() + 4);
363            data.putFloat(f);
364        }
365
366        public void emitDouble(double f) {
367            ensureSize(data.position() + 8);
368            data.putDouble(f);
369        }
370
371        public void align(int alignment) {
372            int pos = data.position();
373            int misaligned = pos % alignment;
374            if (misaligned != 0) {
375                pos += alignment - misaligned;
376                data.position(pos);
377            }
378        }
379
380        private byte[] finish() {
381            return Arrays.copyOf(data.array(), data.position());
382        }
383    }
384
385    /**
386     * Loads a primitive into the Allocatable <code>av</code>. Implementors may only implement
387     * primitive types.
388     */
389    public abstract void emitLoad(AllocatableValue av, Object prim);
390
391    /**
392     * Emit a call to a fixed address <code>addr</code>
393     */
394    public abstract void emitCall(long addr);
395
396    /**
397     * Emit code which is necessary to call a method with {@link CallingConvention} <code>cc</code>
398     * and arguments <coe>prim</code>.
399     */
400    public abstract void emitCallPrologue(CallingConvention cc, Object... prim);
401
402    /**
403     * Emit code which is necessary after calling a method with CallingConvention <code>cc</code>.
404     */
405    public abstract void emitCallEpilogue(CallingConvention cc);
406
407}
408