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