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 }