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 }