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 }