1 /* 2 * Copyright (c) 2014, 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.replacements.test; 26 27 import static org.graalvm.compiler.debug.DebugOptions.DumpOnError; 28 import static org.graalvm.compiler.java.BytecodeParserOptions.InlinePartialIntrinsicExitDuringParsing; 29 30 import java.util.function.Function; 31 32 import org.graalvm.compiler.api.directives.GraalDirectives; 33 import org.graalvm.compiler.api.replacements.ClassSubstitution; 34 import org.graalvm.compiler.api.replacements.MethodSubstitution; 35 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 36 import org.graalvm.compiler.bytecode.BytecodeProvider; 37 import org.graalvm.compiler.core.common.LIRKind; 38 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 39 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 40 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; 41 import org.graalvm.compiler.core.common.type.Stamp; 42 import org.graalvm.compiler.core.common.type.StampFactory; 43 import org.graalvm.compiler.debug.DebugContext; 44 import org.graalvm.compiler.debug.GraalError; 45 import org.graalvm.compiler.graph.GraalGraphError; 46 import org.graalvm.compiler.graph.Node.ConstantNodeParameter; 47 import org.graalvm.compiler.graph.Node.NodeIntrinsic; 48 import org.graalvm.compiler.java.BytecodeParser.BytecodeParserError; 49 import org.graalvm.compiler.nodes.FrameState; 50 import org.graalvm.compiler.nodes.PiNode; 51 import org.graalvm.compiler.nodes.StructuredGraph; 52 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 53 import org.graalvm.compiler.nodes.StructuredGraph.Builder; 54 import org.graalvm.compiler.nodes.ValueNode; 55 import org.graalvm.compiler.nodes.extended.ForeignCallNode; 56 import org.graalvm.compiler.nodes.extended.OpaqueNode; 57 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; 58 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; 59 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; 60 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; 61 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; 62 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory; 63 import org.graalvm.compiler.nodes.spi.LoweringTool; 64 import org.graalvm.compiler.options.OptionValues; 65 import org.graalvm.compiler.phases.common.CanonicalizerPhase; 66 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; 67 import org.graalvm.compiler.phases.common.FloatingReadPhase; 68 import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; 69 import org.graalvm.compiler.phases.common.GuardLoweringPhase; 70 import org.graalvm.compiler.phases.common.LoweringPhase; 71 import org.graalvm.compiler.phases.tiers.HighTierContext; 72 import org.graalvm.compiler.test.GraalTest; 73 import jdk.internal.vm.compiler.word.LocationIdentity; 74 import org.junit.Assert; 75 import org.junit.Assume; 76 import org.junit.BeforeClass; 77 import org.junit.Test; 78 79 import jdk.vm.ci.code.InstalledCode; 80 import jdk.vm.ci.meta.JavaKind; 81 import jdk.vm.ci.meta.ResolvedJavaMethod; 82 83 /** 84 * Tests for expected behavior when parsing snippets and intrinsics. 85 */ 86 public class ReplacementsParseTest extends ReplacementsTest { 87 88 private static final String IN_COMPILED_HANDLER_MARKER = "*** in compiled handler ***"; 89 90 /** 91 * Marker value to indicate an exception handler was interpreted. We cannot use a complex string 92 * expression in this context without risking non-deterministic behavior dependent on whether 93 * String intrinsics are applied or whether String expression evaluation hit an uncommon trap 94 * when executed by C1 or C2 (and thus potentially altering the profile such that the exception 95 * handler is *not* compiled by Graal even when we want it to be). 96 */ 97 private static final String IN_INTERPRETED_HANDLER_MARKER = "*** in interpreted handler ***"; 98 99 private InlineInvokePlugin.InlineInfo inlineInvokeDecision; 100 private String inlineInvokeMethodName = null; 101 102 @SuppressWarnings("serial") 103 static class CustomError extends Error { 104 CustomError(String message) { 105 super(message); 106 } 107 } 108 109 static final Object THROW_EXCEPTION_MARKER = new Object() { 110 @Override 111 public String toString() { 112 return "THROW_EXCEPTION_MARKER"; 113 } 114 }; 115 116 static int copyFirstBody(byte[] left, byte[] right, boolean left2right) { 117 if (left2right) { 118 byte e = left[0]; 119 right[0] = e; 120 return e; 121 } else { 122 byte e = right[0]; 123 left[0] = e; 124 return e; 125 } 126 } 127 128 static int copyFirstL2RBody(byte[] left, byte[] right) { 129 byte e = left[0]; 130 right[0] = e; 131 return e; 132 } 133 134 static class TestObject { 135 static double next(double v) { 136 return Math.nextAfter(v, 1.0); 137 } 138 139 static double next2(double v) { 140 return Math.nextAfter(v, 1.0); 141 } 142 143 static double nextAfter(double x, double d) { 144 return Math.nextAfter(x, d); 145 } 146 147 TestObject() { 148 this(null); 149 } 150 151 TestObject(Object id) { 152 this.id = id; 153 } 154 155 final Object id; 156 157 String stringizeId() { 158 Object res = id; 159 if (res == THROW_EXCEPTION_MARKER) { 160 // Tests exception throwing from partial intrinsification 161 throw new CustomError("ex"); 162 } 163 return String.valueOf(res); 164 } 165 166 static String stringize(Object obj) { 167 Object res = obj; 168 if (res == THROW_EXCEPTION_MARKER) { 169 // Tests exception throwing from partial intrinsification 170 throw new CustomError("ex"); 171 } 172 return String.valueOf(res); 173 } 174 175 static String identity(String s) { 176 return s; 177 } 178 179 /** 180 * @see TestObjectSubstitutions#copyFirst(byte[], byte[], boolean) 181 */ 182 static int copyFirst(byte[] left, byte[] right, boolean left2right) { 183 return copyFirstBody(left, right, left2right); 184 } 185 186 /** 187 * @see TestObjectSubstitutions#copyFirstL2R(byte[], byte[]) 188 */ 189 static int copyFirstL2R(byte[] left, byte[] right) { 190 return copyFirstL2RBody(left, right); 191 } 192 193 static int nonVoidIntrinsicWithCall(@SuppressWarnings("unused") int x, int y) { 194 return y; 195 } 196 197 static int nonVoidIntrinsicWithOptimizedSplit(int x) { 198 return x; 199 } 200 201 static int div(int x, int y) { 202 return x / y; 203 } 204 } 205 206 @ClassSubstitution(TestObject.class) 207 static class TestObjectSubstitutions { 208 209 @MethodSubstitution(isStatic = true) 210 static double nextAfter(double x, double d) { 211 double xx = (x == -0.0 ? 0.0 : x); 212 return Math.nextAfter(xx, d); 213 } 214 215 /** 216 * Tests conditional intrinsification of a static method. 217 */ 218 @MethodSubstitution 219 static String stringize(Object obj) { 220 if (obj != null && obj.getClass() == String.class) { 221 return asNonNullString(obj); 222 } else { 223 // A recursive call denotes exiting/deoptimizing 224 // out of the partial intrinsification to the 225 // slow/uncommon case. 226 return stringize(obj); 227 } 228 } 229 230 /** 231 * Tests conditional intrinsification of a non-static method. 232 */ 233 @MethodSubstitution(isStatic = false) 234 static String stringizeId(TestObject thisObj) { 235 if (thisObj.id != null && thisObj.id.getClass() == String.class) { 236 return asNonNullString(thisObj.id); 237 } else { 238 // A recursive call denotes exiting/deoptimizing 239 // out of the partial intrinsification to the 240 // slow/uncommon case. 241 return outOfLinePartialIntrinsification(thisObj); 242 } 243 } 244 245 static String outOfLinePartialIntrinsification(TestObject thisObj) { 246 return stringizeId(thisObj); 247 } 248 249 public static String asNonNullString(Object object) { 250 return asNonNullStringIntrinsic(object, String.class, true, true); 251 } 252 253 @NodeIntrinsic(PiNode.class) 254 private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull); 255 256 /** 257 * An valid intrinsic as the frame state associated with the merge should prevent the frame 258 * states associated with the array stores from being associated with subsequent 259 * deoptimizing nodes. 260 */ 261 @MethodSubstitution 262 static int copyFirst(byte[] left, byte[] right, boolean left2right) { 263 return copyFirstBody(left, right, left2right); 264 } 265 266 /** 267 * An invalid intrinsic as the frame state associated with the array assignment can leak out 268 * to subsequent deoptimizing nodes. 269 */ 270 @MethodSubstitution 271 static int copyFirstL2R(byte[] left, byte[] right) { 272 return copyFirstL2RBody(left, right); 273 } 274 275 /** 276 * Tests that non-capturing lambdas are folded away. 277 */ 278 @MethodSubstitution 279 static String identity(String value) { 280 return apply(s -> s, value); 281 } 282 283 private static String apply(Function<String, String> f, String value) { 284 return f.apply(value); 285 } 286 287 @MethodSubstitution(isStatic = true) 288 static int nonVoidIntrinsicWithCall(int x, int y) { 289 nonVoidIntrinsicWithCallStub(x); 290 return y; 291 } 292 293 @MethodSubstitution(isStatic = true) 294 static int nonVoidIntrinsicWithOptimizedSplit(int x) { 295 if (x == GraalDirectives.opaque(x)) { 296 nonVoidIntrinsicWithCallStub(x); 297 } 298 return x; 299 } 300 301 @MethodSubstitution 302 static int div(int x, int y) { 303 assert y != 0; 304 return x / y; 305 } 306 307 public static void nonVoidIntrinsicWithCallStub(int zLen) { 308 nonVoidIntrinsicWithCallStub(STUB_CALL, zLen); 309 } 310 311 static final ForeignCallDescriptor STUB_CALL = new ForeignCallDescriptor("stubCall", void.class, int.class); 312 313 @NodeIntrinsic(ForeignCallNode.class) 314 private static native void nonVoidIntrinsicWithCallStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, int zLen); 315 316 } 317 318 @Override 319 protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { 320 BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider(); 321 Registration r = new Registration(invocationPlugins, TestObject.class, replacementBytecodeProvider); 322 NodeIntrinsicPluginFactory.InjectionProvider injections = new DummyInjectionProvider(); 323 new PluginFactory_ReplacementsParseTest().registerPlugins(invocationPlugins, injections); 324 r.registerMethodSubstitution(TestObjectSubstitutions.class, "nextAfter", double.class, double.class); 325 r.registerMethodSubstitution(TestObjectSubstitutions.class, "stringize", Object.class); 326 r.registerMethodSubstitution(TestObjectSubstitutions.class, "stringizeId", Receiver.class); 327 r.registerMethodSubstitution(TestObjectSubstitutions.class, "copyFirst", byte[].class, byte[].class, boolean.class); 328 r.registerMethodSubstitution(TestObjectSubstitutions.class, "copyFirstL2R", byte[].class, byte[].class); 329 r.registerMethodSubstitution(TestObjectSubstitutions.class, "nonVoidIntrinsicWithCall", int.class, int.class); 330 r.registerMethodSubstitution(TestObjectSubstitutions.class, "nonVoidIntrinsicWithOptimizedSplit", int.class); 331 r.registerMethodSubstitution(TestObjectSubstitutions.class, "div", int.class, int.class); 332 333 if (replacementBytecodeProvider.supportsInvokedynamic()) { 334 r.registerMethodSubstitution(TestObjectSubstitutions.class, "identity", String.class); 335 } 336 super.registerInvocationPlugins(invocationPlugins); 337 } 338 339 @BeforeClass 340 public static void warmupProfiles() { 341 for (int i = 0; i < 40000; i++) { 342 callCopyFirst(new byte[16], new byte[16], true); 343 callCopyFirstL2R(new byte[16], new byte[16]); 344 } 345 } 346 347 /** 348 * Ensure that calling the original method from the substitution binds correctly. 349 */ 350 @Test 351 public void test1() { 352 test("test1Snippet", 1.0); 353 } 354 355 public double test1Snippet(double d) { 356 return TestObject.next(d); 357 } 358 359 /** 360 * Ensure that calling the substitution method binds to the original method properly. 361 */ 362 @Test 363 public void test2() { 364 test("test2Snippet", 1.0); 365 } 366 367 public double test2Snippet(double d) { 368 return TestObject.next2(d); 369 } 370 371 /** 372 * Ensure that substitution methods with assertions in them don't complain when the exception 373 * constructor is deleted. 374 */ 375 376 @Test 377 public void testNextAfter() { 378 Assume.assumeFalse(GraalTest.Java8OrEarlier); 379 double[] inArray = new double[1024]; 380 double[] outArray = new double[1024]; 381 for (int i = 0; i < inArray.length; i++) { 382 inArray[i] = -0.0; 383 } 384 test("doNextAfter", inArray, outArray); 385 } 386 387 public void doNextAfter(double[] outArray, double[] inArray) { 388 for (int i = 0; i < inArray.length; i++) { 389 double direction = (i & 1) == 0 ? Double.POSITIVE_INFINITY : -Double.NEGATIVE_INFINITY; 390 outArray[i] = TestObject.nextAfter(inArray[i], direction); 391 } 392 } 393 394 private void testWithDifferentReturnValues(OptionValues options, String standardReturnValue, String compiledReturnValue, String name, Object... args) { 395 ResolvedJavaMethod method = getResolvedJavaMethod(name); 396 Object receiver = null; 397 398 Result expect = executeExpected(method, receiver, args); 399 Assert.assertEquals(standardReturnValue, expect.returnValue); 400 expect = new Result(compiledReturnValue, null); 401 testAgainstExpected(options, method, expect, receiver, args); 402 } 403 404 @Override 405 protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) { 406 return super.getCode(installedCodeOwner, graph, forceCompileOverride, installAsDefault, options); 407 } 408 409 boolean forceCompileOverride; 410 411 @Test 412 public void testCallStringize() { 413 test("callStringize", "a string"); 414 test("callStringize", Boolean.TRUE); 415 // Unset 'exception seen' bit if testCallStringizeWithoutInlinePartialIntrinsicExit 416 // is executed before this test 417 getResolvedJavaMethod("callStringize").reprofile(); 418 forceCompileOverride = true; 419 String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER; 420 String compiledReturnValue = IN_COMPILED_HANDLER_MARKER; 421 testWithDifferentReturnValues(getInitialOptions(), standardReturnValue, compiledReturnValue, "callStringize", THROW_EXCEPTION_MARKER); 422 } 423 424 @Test 425 public void testCallStringizeWithoutInlinePartialIntrinsicExit() { 426 OptionValues options = new OptionValues(getInitialOptions(), InlinePartialIntrinsicExitDuringParsing, false); 427 test(options, "callStringize", "a string"); 428 test(options, "callStringize", Boolean.TRUE); 429 String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER; 430 String compiledReturnValue = IN_COMPILED_HANDLER_MARKER; 431 forceCompileOverride = true; 432 inlineInvokeDecision = InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION; 433 inlineInvokeMethodName = "stringizeId"; 434 try { 435 testWithDifferentReturnValues(options, standardReturnValue, compiledReturnValue, "callStringize", THROW_EXCEPTION_MARKER); 436 } finally { 437 inlineInvokeDecision = null; 438 inlineInvokeMethodName = null; 439 } 440 } 441 442 @Test 443 public void testCallStringizeId() { 444 test("callStringizeId", new TestObject("a string")); 445 test("callStringizeId", new TestObject(Boolean.TRUE)); 446 // Unset 'exception seen' bit if testCallStringizeIdWithoutInlinePartialIntrinsicExit 447 // is executed before this test 448 getResolvedJavaMethod("callStringize").reprofile(); 449 forceCompileOverride = true; 450 String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER; 451 String compiledReturnValue = IN_COMPILED_HANDLER_MARKER; 452 testWithDifferentReturnValues(getInitialOptions(), standardReturnValue, compiledReturnValue, "callStringizeId", new TestObject(THROW_EXCEPTION_MARKER)); 453 } 454 455 @Test 456 public void testCallStringizeIdWithoutInlinePartialIntrinsicExit() { 457 OptionValues options = new OptionValues(getInitialOptions(), InlinePartialIntrinsicExitDuringParsing, false); 458 test(options, "callStringizeId", new TestObject("a string")); 459 test(options, "callStringizeId", new TestObject(Boolean.TRUE)); 460 TestObject exceptionTestObject = new TestObject(THROW_EXCEPTION_MARKER); 461 String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER; 462 String compiledReturnValue = IN_COMPILED_HANDLER_MARKER; 463 forceCompileOverride = true; 464 inlineInvokeDecision = InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION; 465 inlineInvokeMethodName = "stringizeId"; 466 try { 467 testWithDifferentReturnValues(options, standardReturnValue, compiledReturnValue, "callStringizeId", exceptionTestObject); 468 } finally { 469 inlineInvokeDecision = null; 470 inlineInvokeMethodName = null; 471 } 472 } 473 474 public static Object callStringize(Object obj) { 475 try { 476 return TestObject.stringize(obj); 477 } catch (CustomError e) { 478 if (GraalDirectives.inCompiledCode()) { 479 return IN_COMPILED_HANDLER_MARKER; 480 } 481 return IN_INTERPRETED_HANDLER_MARKER; 482 } 483 } 484 485 public static Object callStringizeId(TestObject testObj) { 486 try { 487 return testObj.stringizeId(); 488 } catch (CustomError e) { 489 if (GraalDirectives.inCompiledCode()) { 490 return IN_COMPILED_HANDLER_MARKER; 491 } 492 return IN_INTERPRETED_HANDLER_MARKER; 493 } 494 } 495 496 @Test 497 public void testRootCompileStringize() { 498 ResolvedJavaMethod method = getResolvedJavaMethod(TestObject.class, "stringize"); 499 test(method, null, "a string"); 500 test(method, null, Boolean.TRUE); 501 test(method, null, THROW_EXCEPTION_MARKER); 502 } 503 504 @Test 505 public void testLambda() { 506 test("callLambda", (String) null); 507 test("callLambda", "a string"); 508 } 509 510 public static String callLambda(String value) { 511 return TestObject.identity(value); 512 } 513 514 public static int callCopyFirst(byte[] in, byte[] out, boolean left2right) { 515 int res = TestObject.copyFirst(in, out, left2right); 516 if (res == 17) { 517 // A node after the intrinsic that needs a frame state. 518 GraalDirectives.deoptimize(); 519 } 520 return res; 521 } 522 523 public static int callCopyFirstWrapper(byte[] in, byte[] out, boolean left2right) { 524 return callCopyFirst(in, out, left2right); 525 } 526 527 public static int callCopyFirstL2R(byte[] in, byte[] out) { 528 int res = TestObject.copyFirstL2R(in, out); 529 if (res == 17) { 530 // A node after the intrinsic that needs a frame state. 531 GraalDirectives.deoptimize(); 532 } 533 return res; 534 } 535 536 @Test 537 public void testCallCopyFirst() { 538 byte[] in = {0, 1, 2, 3, 4}; 539 byte[] out = new byte[in.length]; 540 test("callCopyFirst", in, out, true); 541 test("callCopyFirst", in, out, false); 542 } 543 544 @SuppressWarnings("try") 545 @Test 546 public void testCallCopyFirstL2R() { 547 byte[] in = {0, 1, 2, 3, 4}; 548 byte[] out = new byte[in.length]; 549 try { 550 test("callCopyFirstL2R", in, out); 551 } catch (GraalGraphError e) { 552 assertTrue(e.getMessage().startsWith("Invalid frame state")); 553 } 554 } 555 556 @Override 557 protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { 558 if (inlineInvokeMethodName == null || inlineInvokeMethodName.equals(method.getName())) { 559 return inlineInvokeDecision; 560 } 561 return null; 562 } 563 564 @Test 565 public void testCallCopyFirstWithoutInlinePartialIntrinsicExit() { 566 OptionValues options = new OptionValues(getInitialOptions(), InlinePartialIntrinsicExitDuringParsing, false); 567 inlineInvokeDecision = InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION; 568 try { 569 byte[] in = {0, 1, 2, 3, 4}; 570 byte[] out = new byte[in.length]; 571 test(options, "callCopyFirstWrapper", in, out, true); 572 test(options, "callCopyFirstWrapper", in, out, false); 573 } finally { 574 inlineInvokeDecision = null; 575 } 576 } 577 578 public static int nonVoidIntrinsicWithCall(int x, int y) { 579 if (TestObject.nonVoidIntrinsicWithCall(x, y) == x) { 580 GraalDirectives.deoptimize(); 581 } 582 return y; 583 } 584 585 /** 586 * This tests the case where an intrinsic ends with a runtime call but returns some kind of 587 * value. This requires that a FrameState is available after the {@link ForeignCallNode} since 588 * the return value must be computed on return from the call. 589 */ 590 @Test 591 public void testNonVoidIntrinsicWithCall() { 592 testGraph("nonVoidIntrinsicWithCall"); 593 } 594 595 public static int nonVoidIntrinsicWithOptimizedSplit(int x) { 596 if (TestObject.nonVoidIntrinsicWithOptimizedSplit(x) == x) { 597 GraalDirectives.deoptimize(); 598 } 599 return x; 600 } 601 602 /** 603 * This is similar to {@link #testNonVoidIntrinsicWithCall()} but has a merge after the call 604 * which would normally capture the {@link FrameState} but in this case we force the merge to be 605 * optimized away. 606 */ 607 @Test 608 public void testNonVoidIntrinsicWithOptimizedSplit() { 609 testGraph("nonVoidIntrinsicWithOptimizedSplit"); 610 } 611 612 public static int div(int x, int y) { 613 return TestObject.div(x, y); 614 } 615 616 @Test 617 public void testAssertionInMethodSubstitution() { 618 try { 619 ResolvedJavaMethod method = getResolvedJavaMethod("div"); 620 // avoid dumping graphs and printing exception since and exception is expected 621 OptionValues options = new OptionValues(getInitialOptions(), DumpOnError, false); 622 parse(new Builder(options, getDebugContext(options, null, method), AllowAssumptions.YES).method(method).compilationId(getCompilationId(method)), getEagerGraphBuilderSuite()); 623 throw GraalError.shouldNotReachHere("BytecodeParser should have complained about using assertion in an intrinsic."); 624 } catch (BytecodeParserError e) { 625 // Expected behavior 626 } 627 } 628 629 @SuppressWarnings("try") 630 private void testGraph(String name) { 631 StructuredGraph graph = parseEager(name, StructuredGraph.AllowAssumptions.YES); 632 try (DebugContext.Scope s0 = graph.getDebug().scope(name, graph)) { 633 for (OpaqueNode node : graph.getNodes().filter(OpaqueNode.class)) { 634 node.remove(); 635 } 636 HighTierContext context = getDefaultHighTierContext(); 637 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); 638 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); 639 new FloatingReadPhase().apply(graph); 640 canonicalizer.apply(graph, context); 641 new DeadCodeEliminationPhase().apply(graph); 642 new GuardLoweringPhase().apply(graph, getDefaultMidTierContext()); 643 new FrameStateAssignmentPhase().apply(graph); 644 } catch (Throwable e) { 645 throw graph.getDebug().handle(e); 646 } 647 } 648 649 private class DummyInjectionProvider implements NodeIntrinsicPluginFactory.InjectionProvider { 650 @SuppressWarnings("unchecked") 651 @Override 652 public <T> T getInjectedArgument(Class<T> type) { 653 if (type == ForeignCallsProvider.class) { 654 return (T) new ForeignCallsProvider() { 655 @Override 656 public LIRKind getValueKind(JavaKind javaKind) { 657 return null; 658 } 659 660 @Override 661 public boolean isReexecutable(ForeignCallDescriptor descriptor) { 662 return false; 663 } 664 665 @Override 666 public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) { 667 return new LocationIdentity[0]; 668 } 669 670 @Override 671 public boolean canDeoptimize(ForeignCallDescriptor descriptor) { 672 return false; 673 } 674 675 @Override 676 public boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor) { 677 return false; 678 } 679 680 @Override 681 public ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) { 682 return null; 683 } 684 }; 685 } 686 if (type == SnippetReflectionProvider.class) { 687 return (T) getSnippetReflection(); 688 } 689 return null; 690 } 691 692 @Override 693 public Stamp getInjectedStamp(Class<?> type, boolean nonNull) { 694 JavaKind kind = JavaKind.fromJavaClass(type); 695 return StampFactory.forKind(kind); 696 } 697 } 698 }