diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotDeoptBoundJavaMethodCallerTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotDeoptBoundJavaMethodCallerTest.java
new file mode 100644
index 000000000000..8a3305dcfc42
--- /dev/null
+++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotDeoptBoundJavaMethodCallerTest.java
@@ -0,0 +1,72 @@
+package jdk.graal.compiler.hotspot.test;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import jdk.graal.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl;
+import jdk.graal.compiler.hotspot.nodes.InvokeStaticJavaMethodNode;
+import jdk.graal.compiler.nodes.ValueNode;
+import jdk.graal.compiler.nodes.extended.ForeignCallNode;
+import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Verifies that deoptimization functions correctly when triggered during a method call invoked by
+ * an {@link InvokeStaticJavaMethodNode}.
+ */
+public class HotSpotDeoptBoundJavaMethodCallerTest extends HotSpotInvokeBoundJavaMethodBaseTest {
+
+ /**
+ * Calling {@link #getForeignCallInvokerMethod()} will deoptimize the calling frame. We will
+ * deoptimize to {@link InvokeStaticJavaMethodNode#stateBefore()}.
+ */
+ @Override
+ protected boolean invocationPluginApply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg, JavaKind kind) {
+ InvokeStaticJavaMethodNode node = InvokeStaticJavaMethodNode.create(b, getForeignCallInvokerMethod(), b.bci());
+ b.add(node);
+ // add the arg to the stack as the method has a return value
+ b.addPush(kind, arg);
+ return false;
+ }
+
+ @Override
+ protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+ invocationPlugins.register(HotSpotDeoptBoundJavaMethodCallerTest.class, new InvocationPlugin("testCallInt", int.class) {
+
+ @Override
+ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+ ForeignCallNode node = new ForeignCallNode(HotSpotForeignCallsProviderImpl.TEST_DEOPTIMIZE_CALLER_OF_CALLER, arg);
+ b.addPush(JavaKind.Int, node);
+ return true;
+ }
+ });
+ super.registerInvocationPlugins(invocationPlugins);
+ }
+
+ public static int testCallInt(int value) {
+ return value;
+ }
+
+ public static void invokeForeignCall() {
+ testCallInt(3);
+ }
+
+ public ResolvedJavaMethod getForeignCallInvokerMethod() {
+ return getResolvedJavaMethod(HotSpotDeoptBoundJavaMethodCallerTest.class, "invokeForeignCall");
+ }
+
+ @Before
+ public void before() {
+ getCode(getForeignCallInvokerMethod(), null, true, true, getInitialOptions());
+ }
+
+ @Test
+ @Override
+ public void testMany() {
+ super.testMany();
+ }
+
+}
diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotInvokeBoundJavaMethodBaseTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotInvokeBoundJavaMethodBaseTest.java
new file mode 100644
index 000000000000..add04dc86ad1
--- /dev/null
+++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotInvokeBoundJavaMethodBaseTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.graal.compiler.hotspot.test;
+
+import jdk.graal.compiler.nodes.ValueNode;
+import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Base class for tests involving calls to bound methods.
+ */
+public abstract class HotSpotInvokeBoundJavaMethodBaseTest extends HotSpotGraalCompilerTest {
+
+ public static final JavaKind[] KINDS = {JavaKind.Boolean, JavaKind.Byte, JavaKind.Short, JavaKind.Char, JavaKind.Int, JavaKind.Long, JavaKind.Object};
+
+ @Override
+ protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+ for (JavaKind kind : KINDS) {
+ String name = kind.isObject() ? "passingObject" : "passing" + capitalize(kind.getJavaName());
+ Class> argType = kind.isObject() ? Object.class : kind.toJavaClass();
+ invocationPlugins.register(HotSpotInvokeBoundJavaMethodBaseTest.class, new InvocationPlugin(name, argType) {
+ @Override
+ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg) {
+ invocationPluginApply(b, targetMethod, receiver, arg, kind);
+ return true;
+ }
+ });
+ }
+ super.registerInvocationPlugins(invocationPlugins);
+ }
+
+ private static String capitalize(String s) {
+ return Character.toUpperCase(s.charAt(0)) + s.substring(1);
+ }
+
+ protected abstract boolean invocationPluginApply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg, JavaKind kind);
+
+ static boolean[] booleanValues = new boolean[]{Boolean.TRUE, Boolean.FALSE};
+
+ static boolean passingBoolean(boolean arg) {
+ return arg;
+ }
+
+ public static boolean passingBooleanSnippet(boolean arg) {
+ return passingBoolean(arg);
+ }
+
+ public void testPassingBoolean() {
+ for (boolean value : booleanValues) {
+ test("passingBooleanSnippet", value);
+ }
+ }
+
+ static byte[] byteValues = new byte[]{Byte.MAX_VALUE, -1, 0, 1, Byte.MIN_VALUE};
+
+ static byte passingByte(byte arg) {
+ return arg;
+ }
+
+ public static byte passingByteSnippet(byte arg) {
+ return passingByte(arg);
+ }
+
+ public void testPassingByte() {
+ for (byte value : byteValues) {
+ test("passingByteSnippet", value);
+ }
+ }
+
+ static short[] shortValues = new short[]{Short.MAX_VALUE, -1, 0, 1, Short.MIN_VALUE};
+
+ static short passingShort(short arg) {
+ return arg;
+ }
+
+ public static short passingShortSnippet(short arg) {
+ return passingShort(arg);
+ }
+
+ public void testPassingShort() {
+ for (short value : shortValues) {
+ test("passingShortSnippet", value);
+ }
+ }
+
+ static char[] charValues = new char[]{Character.MAX_VALUE, 1, Character.MIN_VALUE};
+
+ static char passingChar(char arg) {
+ return arg;
+ }
+
+ public static char passingCharSnippet(char arg) {
+ return passingChar(arg);
+ }
+
+ public void testPassingChar() {
+ for (char value : charValues) {
+ test("passingCharSnippet", value);
+ }
+ }
+
+ static int[] intValues = new int[]{Integer.MAX_VALUE, -1, 0, 1, Integer.MIN_VALUE};
+
+ static int passingInt(int arg) {
+ return arg;
+ }
+
+ public static int passingIntSnippet(int arg) {
+ return passingInt(arg);
+ }
+
+ public void testPassingInt() {
+ for (int value : intValues) {
+ test("passingIntSnippet", value);
+ }
+ }
+
+ static long[] longValues = new long[]{Long.MAX_VALUE, -1, 0, 1, Long.MIN_VALUE};
+
+ static long passingLong(long arg) {
+ return arg;
+ }
+
+ public static long passingLongSnippet(long arg) {
+ return passingLong(arg);
+ }
+
+ public void testPassingLong() {
+ for (long value : longValues) {
+ test("passingLongSnippet", value);
+ }
+ }
+
+ static Object[] objectValues = new Object[]{null, "String", Integer.valueOf(-1)};
+
+ static Object passingObject(Object arg) {
+ return arg;
+ }
+
+ public static Object passingObjectSnippet(Object arg) {
+ return passingObject(arg);
+ }
+
+ public void testPassingObject() {
+ for (Object value : objectValues) {
+ test("passingObjectSnippet", value);
+ }
+ }
+
+ public void testMany() {
+ testPassingObject();
+ testPassingInt();
+ testPassingByte();
+ testPassingChar();
+ testPassingLong();
+ testPassingBoolean();
+ testPassingShort();
+ }
+}
diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotInvokeBoundJavaMethodTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotInvokeBoundJavaMethodTest.java
new file mode 100644
index 000000000000..0657964b8e53
--- /dev/null
+++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotInvokeBoundJavaMethodTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.graal.compiler.hotspot.test;
+
+import org.junit.Test;
+
+import jdk.graal.compiler.hotspot.nodes.InvokeStaticJavaMethodNode;
+import jdk.graal.compiler.nodes.Invoke;
+import jdk.graal.compiler.nodes.ValueNode;
+import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests that using an {@link InvokeStaticJavaMethodNode} instead of an {@link Invoke} to call a
+ * side-effect-free static method produces identical behavior.
+ */
+public class HotSpotInvokeBoundJavaMethodTest extends HotSpotInvokeBoundJavaMethodBaseTest {
+
+ @Override
+ protected boolean invocationPluginApply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg, JavaKind kind) {
+ InvokeStaticJavaMethodNode node = InvokeStaticJavaMethodNode.create(b, targetMethod, b.bci(), arg);
+ b.addPush(kind, node);
+ return false;
+ }
+
+ @Test
+ @Override
+ public void testMany() {
+ super.testMany();
+ }
+}
diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java
index 9be0df530ead..d6cca531125f 100644
--- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java
+++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java
@@ -701,6 +701,7 @@ private long getZGCAddressField(String name) {
public final long validateObject = getAddress("JVMCIRuntime::validate_object");
public final long testDeoptimizeCallInt = getAddress("JVMCIRuntime::test_deoptimize_call_int");
+ public final long testDeoptimizeCallerOfCaller = getAddress("JVMCIRuntime::test_deoptimize_caller_of_caller");
public final long registerFinalizerAddress = getAddress("SharedRuntime::register_finalizer");
public final long exceptionHandlerForReturnAddressAddress = getAddress("SharedRuntime::exception_handler_for_return_address");
diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java
index 64479a1f99b0..b5f063ea2a4f 100644
--- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java
+++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java
@@ -82,6 +82,8 @@ public abstract class HotSpotForeignCallsProviderImpl implements HotSpotForeignC
Word.class);
public static final HotSpotForeignCallDescriptor TEST_DEOPTIMIZE_CALL_INT = new HotSpotForeignCallDescriptor(SAFEPOINT, NO_SIDE_EFFECT, any(), "test_deoptimize_call_int", int.class, int.class);
+ public static final HotSpotForeignCallDescriptor TEST_DEOPTIMIZE_CALLER_OF_CALLER = new HotSpotForeignCallDescriptor(SAFEPOINT, NO_SIDE_EFFECT, any(), "test_deoptimize_caller_of_caller",
+ int.class, int.class);
protected final HotSpotJVMCIRuntime jvmciRuntime;
protected final HotSpotGraalRuntimeProvider runtime;
diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java
index 483a94a160ad..a6a95d6fbd4c 100644
--- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java
+++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java
@@ -596,6 +596,7 @@ public void initialize(HotSpotProviders providers, OptionValues options) {
linkForeignCall(options, providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD);
linkForeignCall(options, providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD);
+ linkForeignCall(options, providers, TEST_DEOPTIMIZE_CALLER_OF_CALLER, c.testDeoptimizeCallerOfCaller, PREPEND_THREAD);
registerArrayCopy(JavaKind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
registerArrayCopy(JavaKind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/InvokeStaticJavaMethodNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/InvokeStaticJavaMethodNode.java
new file mode 100644
index 000000000000..6796c847437b
--- /dev/null
+++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/InvokeStaticJavaMethodNode.java
@@ -0,0 +1,264 @@
+package jdk.graal.compiler.hotspot.nodes;
+
+import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+import static jdk.graal.compiler.nodes.Invoke.CYCLES_UNKNOWN_RATIONALE;
+import static jdk.graal.compiler.nodes.Invoke.SIZE_UNKNOWN_RATIONALE;
+
+import java.util.Map;
+
+import jdk.graal.compiler.core.common.type.Stamp;
+import jdk.graal.compiler.core.common.type.StampFactory;
+import jdk.graal.compiler.core.common.type.StampPair;
+import jdk.graal.compiler.debug.DebugCloseable;
+import jdk.graal.compiler.debug.GraalError;
+import jdk.graal.compiler.graph.Node.NodeIntrinsicFactory;
+import jdk.graal.compiler.graph.NodeClass;
+import jdk.graal.compiler.graph.NodeInputList;
+import jdk.graal.compiler.nodeinfo.NodeInfo;
+import jdk.graal.compiler.nodeinfo.Verbosity;
+import jdk.graal.compiler.nodes.CallTargetNode;
+import jdk.graal.compiler.nodes.DeoptimizingFixedWithNextNode;
+import jdk.graal.compiler.nodes.InliningLog;
+import jdk.graal.compiler.nodes.Invokable;
+import jdk.graal.compiler.nodes.Invoke;
+import jdk.graal.compiler.nodes.InvokeNode;
+import jdk.graal.compiler.nodes.StructuredGraph;
+import jdk.graal.compiler.nodes.ValueNode;
+import jdk.graal.compiler.nodes.extended.StateSplitProxyNode;
+import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import jdk.graal.compiler.nodes.java.MethodCallTargetNode;
+import jdk.graal.compiler.nodes.memory.MemoryKill;
+import jdk.graal.compiler.nodes.spi.Lowerable;
+import jdk.graal.compiler.nodes.spi.LoweringTool;
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Signature;
+
+/**
+ * A node for invoking a Java method out of line from the surrounding Java bytecode. The current use
+ * cases are:
+ *
+ *
Invoking a Java method from a Truffle safepoint ({@code TruffleSafePointNode})
+ *
Performing an {@code acmp} (equality) comparison for value objects in Valhalla by calling a
+ * Java method. For future use in HotSpot, a {@link StateSplitProxyNode} must be inserted with the
+ * state before the {@code acmp}'s pop operation. The call site resolution requires the BCI of the
+ * {@code acmp} bytecode.
+ *
+ * Compared to an {@link Invoke} node, the node is side effect free and the call does not originate
+ * from the associated bci. The target method must be static and is bound to the call site to
+ * override the bytecode based call site resolution.
+ */
+// @formatter:off
+@NodeInfo(nameTemplate = "InvokeJavaMethod#{p#targetMethod/s}",
+ cycles = CYCLES_UNKNOWN, cyclesRationale = CYCLES_UNKNOWN_RATIONALE,
+ size = SIZE_UNKNOWN, sizeRationale = SIZE_UNKNOWN_RATIONALE)
+// @formatter:on
+@NodeIntrinsicFactory
+public class InvokeStaticJavaMethodNode extends DeoptimizingFixedWithNextNode implements Invokable, Lowerable {
+ public static final NodeClass TYPE = NodeClass.create(InvokeStaticJavaMethodNode.class);
+
+ /**
+ * Enables passing a method (to be invoked by this node) as a constant within an intrinsic
+ * context. This is required when the specific method to invoke is known, but the corresponding
+ * {@link ResolvedJavaMethod} instance is not available at the time of
+ * {@link InvokeStaticJavaMethodNode} creation. See
+ * {@code HotSpotTruffleSafepointLoweringSnippet#pollSnippet} for usage details.
+ */
+ public static final class MethodReference {
+ private final String name;
+ private ResolvedJavaMethod targetMethod;
+
+ public MethodReference(String name) {
+ this.name = name;
+ }
+
+ public void setTargetMethod(ResolvedJavaMethod targetMethod) {
+ this.targetMethod = targetMethod;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public static final MethodReference TRUFFLE_SAFEPOINT = new MethodReference("HotSpotThreadLocalHandshake.doHandshake");
+
+ @Input protected NodeInputList arguments;
+
+ private int bci;
+ private final ResolvedJavaMethod callerMethod;
+ private ResolvedJavaMethod targetMethod;
+ private final CallTargetNode.InvokeKind invokeKind;
+ private final StampPair returnStamp;
+ private MethodReference methodReference;
+
+ @SuppressWarnings("this-escape")
+ protected InvokeStaticJavaMethodNode(NodeClass extends InvokeStaticJavaMethodNode> c, ResolvedJavaMethod targetMethod, ResolvedJavaMethod callerMethod,
+ StampPair returnStamp, int bci, ValueNode... args) {
+ super(c, returnStamp.getTrustedStamp());
+ this.arguments = new NodeInputList<>(this, args);
+ this.bci = bci;
+ this.callerMethod = callerMethod;
+ this.targetMethod = targetMethod;
+ this.returnStamp = returnStamp;
+ this.invokeKind = CallTargetNode.InvokeKind.Static;
+ }
+
+ public static InvokeStaticJavaMethodNode create(MethodReference methodReference, ResolvedJavaMethod callerMethod, int bci, ValueNode... args) {
+ verifyTargetMethod(methodReference.targetMethod);
+ ResolvedJavaMethod targetMethod = methodReference.targetMethod;
+ JavaKind returnKind = targetMethod.getSignature().getReturnKind();
+ return new InvokeStaticJavaMethodNode(TYPE, targetMethod, callerMethod, StampPair.createSingle(StampFactory.forKind(returnKind)), bci, args);
+ }
+
+ public static InvokeStaticJavaMethodNode create(GraphBuilderContext b, ResolvedJavaMethod targetMethod, int bci, ValueNode... args) {
+ Signature signature = targetMethod.getSignature();
+ JavaType returnType = signature.getReturnType(null);
+ StructuredGraph graph = b.getGraph();
+ StampPair returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
+ return create(b, targetMethod, b.getMethod(), returnStamp, bci, args);
+ }
+
+ private static InvokeStaticJavaMethodNode createWithoutTargetMethod(GraphBuilderContext b, MethodReference methodReference, Stamp returnStamp, int bci, ValueNode... args) {
+ InvokeStaticJavaMethodNode invoke = create(b, null, b.getMethod(), StampPair.createSingle(returnStamp), bci, args);
+ invoke.methodReference = methodReference;
+ return invoke;
+ }
+
+ private static InvokeStaticJavaMethodNode create(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ResolvedJavaMethod callerMethod,
+ StampPair returnStamp, int bci, ValueNode... args) {
+ GraalError.guarantee(b.getInvokeKind() == CallTargetNode.InvokeKind.Static, "can only invoke static methods");
+ return new InvokeStaticJavaMethodNode(TYPE, targetMethod, callerMethod, returnStamp, bci, args);
+ }
+
+ @Override
+ public ResolvedJavaMethod getContextMethod() {
+ return callerMethod;
+ }
+
+ public NodeInputList getArguments() {
+ return arguments;
+ }
+
+ public ValueNode[] toArgumentArray() {
+ return arguments.toArray(ValueNode.EMPTY_ARRAY);
+ }
+
+ @Override
+ public int bci() {
+ return bci;
+ }
+
+ @Override
+ public void setBci(int bci) {
+ this.bci = bci;
+ }
+
+ @Override
+ public ResolvedJavaMethod getTargetMethod() {
+ return targetMethod;
+ }
+
+ private static void verifyTargetMethod(ResolvedJavaMethod targetMethod) {
+ GraalError.guarantee(targetMethod != null, "method shouldn't be null");
+ GraalError.guarantee(targetMethod.isStatic(), "can only invoke static methods");
+ }
+
+ public void setTargetMethod(ResolvedJavaMethod targetMethod) {
+ verifyTargetMethod(targetMethod);
+ this.targetMethod = targetMethod;
+ }
+
+ public CallTargetNode.InvokeKind getInvokeKind() {
+ return invokeKind;
+ }
+
+ public StampPair getReturnStamp() {
+ return returnStamp;
+ }
+
+ @Override
+ public String toString(Verbosity verbosity) {
+ if (verbosity == Verbosity.Name) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(super.toString(verbosity));
+ sb.append("#");
+ if (targetMethod == null) {
+ sb.append(methodReference.getName());
+ } else {
+ sb.append(targetMethod.format("%h.%n"));
+ }
+ return sb.toString();
+ }
+ return super.toString(verbosity);
+ }
+
+ @Override
+ public Map