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