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 package org.graalvm.compiler.hotspot.test;
  24 
  25 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
  26 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
  27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
  28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
  29 
  30 import java.util.function.Consumer;
  31 
  32 import org.graalvm.compiler.code.CompilationResult;
  33 import org.graalvm.compiler.core.common.LIRKind;
  34 import org.graalvm.compiler.core.common.type.StampFactory;
  35 import org.graalvm.compiler.core.test.GraalCompilerTest;
  36 import org.graalvm.compiler.debug.DebugHandlersFactory;
  37 import org.graalvm.compiler.debug.DebugContext;
  38 import org.graalvm.compiler.debug.DebugContext.Scope;
  39 import org.graalvm.compiler.graph.NodeClass;
  40 import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
  41 import org.graalvm.compiler.lir.FullInfopointOp;
  42 import org.graalvm.compiler.lir.LIRFrameState;
  43 import org.graalvm.compiler.lir.LIRInstruction;
  44 import org.graalvm.compiler.lir.LIRInstructionClass;
  45 import org.graalvm.compiler.lir.Variable;
  46 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
  47 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
  48 import org.graalvm.compiler.nodeinfo.NodeInfo;
  49 import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
  50 import org.graalvm.compiler.nodes.StructuredGraph;
  51 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  52 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  53 import org.junit.Test;
  54 
  55 import jdk.vm.ci.code.BytecodeFrame;
  56 import jdk.vm.ci.code.CodeCacheProvider;
  57 import jdk.vm.ci.code.VirtualObject;
  58 import jdk.vm.ci.code.site.InfopointReason;
  59 import jdk.vm.ci.common.JVMCIError;
  60 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
  61 import jdk.vm.ci.meta.AllocatableValue;
  62 import jdk.vm.ci.meta.JavaConstant;
  63 import jdk.vm.ci.meta.JavaKind;
  64 import jdk.vm.ci.meta.JavaValue;
  65 import jdk.vm.ci.meta.PlatformKind;
  66 import jdk.vm.ci.meta.ResolvedJavaMethod;
  67 import jdk.vm.ci.meta.ResolvedJavaType;
  68 import jdk.vm.ci.meta.Value;
  69 
  70 public 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 }