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