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