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 }