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 }