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 */
23package org.graalvm.compiler.hotspot.test;
24
25import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
26import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
27import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
28import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
29
30import java.util.function.Consumer;
31
32import org.graalvm.compiler.code.CompilationResult;
33import org.graalvm.compiler.core.common.LIRKind;
34import org.graalvm.compiler.core.common.type.StampFactory;
35import org.graalvm.compiler.core.test.GraalCompilerTest;
36import org.graalvm.compiler.debug.DebugHandlersFactory;
37import org.graalvm.compiler.debug.DebugContext;
38import org.graalvm.compiler.debug.DebugContext.Scope;
39import org.graalvm.compiler.graph.NodeClass;
40import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
41import org.graalvm.compiler.lir.FullInfopointOp;
42import org.graalvm.compiler.lir.LIRFrameState;
43import org.graalvm.compiler.lir.LIRInstruction;
44import org.graalvm.compiler.lir.LIRInstructionClass;
45import org.graalvm.compiler.lir.Variable;
46import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
47import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
48import org.graalvm.compiler.nodeinfo.NodeInfo;
49import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
50import org.graalvm.compiler.nodes.StructuredGraph;
51import org.graalvm.compiler.nodes.spi.LIRLowerable;
52import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
53import org.junit.Test;
54
55import jdk.vm.ci.code.BytecodeFrame;
56import jdk.vm.ci.code.CodeCacheProvider;
57import jdk.vm.ci.code.VirtualObject;
58import jdk.vm.ci.code.site.InfopointReason;
59import jdk.vm.ci.common.JVMCIError;
60import jdk.vm.ci.hotspot.HotSpotCompiledCode;
61import jdk.vm.ci.meta.AllocatableValue;
62import jdk.vm.ci.meta.JavaConstant;
63import jdk.vm.ci.meta.JavaKind;
64import jdk.vm.ci.meta.JavaValue;
65import jdk.vm.ci.meta.PlatformKind;
66import jdk.vm.ci.meta.ResolvedJavaMethod;
67import jdk.vm.ci.meta.ResolvedJavaType;
68import jdk.vm.ci.meta.Value;
69
70public class JVMCIInfopointErrorTest extends GraalCompilerTest {
71
72    private static class ValueDef extends LIRInstruction {
73        private static final LIRInstructionClass<ValueDef> TYPE = LIRInstructionClass.create(ValueDef.class);
74
75        @Def({REG, STACK}) AllocatableValue value;
76
77        ValueDef(AllocatableValue value) {
78            super(TYPE);
79            this.value = value;
80        }
81
82        @Override
83        public void emitCode(CompilationResultBuilder crb) {
84        }
85    }
86
87    private static class ValueUse extends LIRInstruction {
88        private static final LIRInstructionClass<ValueUse> TYPE = LIRInstructionClass.create(ValueUse.class);
89
90        @Use({REG, STACK}) AllocatableValue value;
91
92        ValueUse(AllocatableValue value) {
93            super(TYPE);
94            this.value = value;
95        }
96
97        @Override
98        public void emitCode(CompilationResultBuilder crb) {
99        }
100    }
101
102    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
103    private static class TestNode extends DeoptimizingFixedWithNextNode implements LIRLowerable {
104        private static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
105
106        private final TestSpec spec;
107
108        protected TestNode(TestSpec spec) {
109            super(TYPE, StampFactory.forVoid());
110            this.spec = spec;
111        }
112
113        @Override
114        public boolean canDeoptimize() {
115            return true;
116        }
117
118        @Override
119        public void generate(NodeLIRBuilderTool gen) {
120            LIRGeneratorTool tool = gen.getLIRGeneratorTool();
121            LIRFrameState state = gen.state(this);
122            spec.spec(tool, state, st -> {
123                tool.append(new FullInfopointOp(st, InfopointReason.SAFEPOINT));
124            });
125        }
126    }
127
128    @FunctionalInterface
129    private interface TestSpec {
130        void spec(LIRGeneratorTool tool, LIRFrameState state, Consumer<LIRFrameState> safepoint);
131    }
132
133    public static void testMethod() {
134    }
135
136    private void test(TestSpec spec) {
137        test(getDebugContext(), spec);
138    }
139
140    private void test(DebugContext debug, TestSpec spec) {
141        ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
142
143        StructuredGraph graph = parseForCompile(method, debug);
144        TestNode test = graph.add(new TestNode(spec));
145        graph.addAfterFixed(graph.start(), test);
146
147        CompilationResult compResult = compile(method, graph);
148        CodeCacheProvider codeCache = getCodeCache();
149        HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, method, null, compResult);
150        codeCache.addCode(method, compiledCode, null, null);
151    }
152
153    @Test(expected = JVMCIError.class)
154    public void testInvalidShortOop() {
155        test((tool, state, safepoint) -> {
156            PlatformKind kind = tool.target().arch.getPlatformKind(JavaKind.Short);
157            LIRKind lirKind = LIRKind.reference(kind);
158
159            Variable var = tool.newVariable(lirKind);
160            tool.append(new ValueDef(var));
161            safepoint.accept(state);
162            tool.append(new ValueUse(var));
163        });
164    }
165
166    @Test(expected = JVMCIError.class)
167    public void testInvalidShortDerivedOop() {
168        test((tool, state, safepoint) -> {
169            Variable baseOop = tool.newVariable(LIRKind.fromJavaKind(tool.target().arch, JavaKind.Object));
170            tool.append(new ValueDef(baseOop));
171
172            PlatformKind kind = tool.target().arch.getPlatformKind(JavaKind.Short);
173            LIRKind lirKind = LIRKind.derivedReference(kind, baseOop);
174
175            Variable var = tool.newVariable(lirKind);
176            tool.append(new ValueDef(var));
177            safepoint.accept(state);
178            tool.append(new ValueUse(var));
179        });
180    }
181
182    private static LIRFrameState modifyTopFrame(LIRFrameState state, JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks) {
183        return modifyTopFrame(state, null, values, slotKinds, locals, stack, locks);
184    }
185
186    private static LIRFrameState modifyTopFrame(LIRFrameState state, VirtualObject[] vobj, JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks) {
187        BytecodeFrame top = state.topFrame;
188        top = new BytecodeFrame(top.caller(), top.getMethod(), top.getBCI(), top.rethrowException, top.duringCall, values, slotKinds, locals, stack, locks);
189        return new LIRFrameState(top, vobj, state.exceptionEdge);
190    }
191
192    @Test(expected = JVMCIError.class)
193    public void testUnexpectedScopeValuesLength() {
194        test((tool, state, safepoint) -> {
195            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.FALSE}, new JavaKind[0], 0, 0, 0);
196            safepoint.accept(newState);
197        });
198    }
199
200    @Test(expected = JVMCIError.class)
201    public void testUnexpectedScopeSlotKindsLength() {
202        test((tool, state, safepoint) -> {
203            LIRFrameState newState = modifyTopFrame(state, new JavaValue[0], new JavaKind[]{JavaKind.Boolean}, 0, 0, 0);
204            safepoint.accept(newState);
205        });
206    }
207
208    @Test(expected = JVMCIError.class)
209    public void testWrongMonitorType() {
210        test((tool, state, safepoint) -> {
211            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.INT_0}, new JavaKind[]{}, 0, 0, 1);
212            safepoint.accept(newState);
213        });
214    }
215
216    @Test(expected = JVMCIError.class)
217    public void testUnexpectedIllegalValue() {
218        test((tool, state, safepoint) -> {
219            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{Value.ILLEGAL}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
220            safepoint.accept(newState);
221        });
222    }
223
224    @Test(expected = JVMCIError.class)
225    public void testUnexpectedTypeInRegister() {
226        test((tool, state, safepoint) -> {
227            Variable var = tool.newVariable(LIRKind.fromJavaKind(tool.target().arch, JavaKind.Int));
228            tool.append(new ValueDef(var));
229            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{var}, new JavaKind[]{JavaKind.Illegal}, 1, 0, 0);
230            safepoint.accept(newState);
231        });
232    }
233
234    @Test(expected = JVMCIError.class)
235    public void testWrongConstantType() {
236        test((tool, state, safepoint) -> {
237            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.INT_0}, new JavaKind[]{JavaKind.Object}, 1, 0, 0);
238            safepoint.accept(newState);
239        });
240    }
241
242    @Test(expected = JVMCIError.class)
243    public void testUnsupportedConstantType() {
244        test((tool, state, safepoint) -> {
245            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.forShort((short) 0)}, new JavaKind[]{JavaKind.Short}, 1, 0, 0);
246            safepoint.accept(newState);
247        });
248    }
249
250    @Test(expected = JVMCIError.class)
251    public void testUnexpectedNull() {
252        test((tool, state, safepoint) -> {
253            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.NULL_POINTER}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
254            safepoint.accept(newState);
255        });
256    }
257
258    @Test(expected = JVMCIError.class)
259    public void testUnexpectedObject() {
260        JavaValue wrapped = getSnippetReflection().forObject(this);
261        test((tool, state, safepoint) -> {
262            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{wrapped}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
263            safepoint.accept(newState);
264        });
265    }
266
267    private static class UnknownJavaValue implements JavaValue {
268    }
269
270    @SuppressWarnings("try")
271    @Test(expected = Error.class)
272    public void testUnknownJavaValue() {
273        DebugContext debug = DebugContext.create(getInitialOptions(), DebugHandlersFactory.LOADER);
274        try (Scope s = debug.disable()) {
275            /*
276             * Expected: either AssertionError or GraalError, depending on whether the unit test run
277             * is with assertions enabled or disabled.
278             */
279            test(debug, (tool, state, safepoint) -> {
280                LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{new UnknownJavaValue()}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
281                safepoint.accept(newState);
282            });
283        }
284    }
285
286    @Test(expected = Error.class)
287    public void testMissingIllegalAfterDouble() {
288        /*
289         * Expected: either AssertionError or GraalError, depending on whether the unit test run is
290         * with assertions enabled or disabled.
291         */
292        test((tool, state, safepoint) -> {
293            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.DOUBLE_0, JavaConstant.INT_0}, new JavaKind[]{JavaKind.Double, JavaKind.Int}, 2, 0, 0);
294            safepoint.accept(newState);
295        });
296    }
297
298    @Test(expected = JVMCIError.class)
299    public void testInvalidVirtualObjectId() {
300        ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class);
301        test((tool, state, safepoint) -> {
302            VirtualObject o = VirtualObject.get(obj, 5);
303            o.setValues(new JavaValue[0], new JavaKind[0]);
304
305            safepoint.accept(new LIRFrameState(state.topFrame, new VirtualObject[]{o}, state.exceptionEdge));
306        });
307    }
308
309    @Test(expected = JVMCIError.class)
310    public void testDuplicateVirtualObject() {
311        ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class);
312        test((tool, state, safepoint) -> {
313            VirtualObject o1 = VirtualObject.get(obj, 0);
314            o1.setValues(new JavaValue[0], new JavaKind[0]);
315
316            VirtualObject o2 = VirtualObject.get(obj, 0);
317            o2.setValues(new JavaValue[0], new JavaKind[0]);
318
319            safepoint.accept(new LIRFrameState(state.topFrame, new VirtualObject[]{o1, o2}, state.exceptionEdge));
320        });
321    }
322
323    @Test(expected = JVMCIError.class)
324    public void testUnexpectedVirtualObject() {
325        ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class);
326        test((tool, state, safepoint) -> {
327            VirtualObject o = VirtualObject.get(obj, 0);
328            o.setValues(new JavaValue[0], new JavaKind[0]);
329
330            LIRFrameState newState = modifyTopFrame(state, new VirtualObject[]{o}, new JavaValue[]{o}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
331            safepoint.accept(newState);
332        });
333    }
334
335    @Test(expected = JVMCIError.class)
336    public void testUndefinedVirtualObject() {
337        ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class);
338        test((tool, state, safepoint) -> {
339            VirtualObject o0 = VirtualObject.get(obj, 0);
340            o0.setValues(new JavaValue[0], new JavaKind[0]);
341
342            VirtualObject o1 = VirtualObject.get(obj, 1);
343            o1.setValues(new JavaValue[0], new JavaKind[0]);
344
345            LIRFrameState newState = modifyTopFrame(state, new VirtualObject[]{o0}, new JavaValue[]{o1}, new JavaKind[]{JavaKind.Object}, 1, 0, 0);
346            safepoint.accept(newState);
347        });
348    }
349}
350