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: + * + * 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 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 getDebugProperties(Map map) { + Map debugProperties = super.getDebugProperties(map); + debugProperties.put("targetMethod", targetMethod == null ? methodReference.getName() : targetMethod.format("%h.%n")); + return debugProperties; + } + + public static boolean intrinsify(GraphBuilderContext b, @InjectedNodeParameter Stamp returnStamp, MethodReference methodReference, ValueNode... args) { + GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor(); + int bci = nonIntrinsicAncestor == null ? BytecodeFrame.UNKNOWN_BCI : b.bci(); + InvokeStaticJavaMethodNode invoke = InvokeStaticJavaMethodNode.createWithoutTargetMethod(b, methodReference, returnStamp, bci, args); + JavaKind returnKind = returnStamp.getStackKind(); + if (returnKind == JavaKind.Void) { + b.add(invoke); + } else { + b.addPush(returnKind, invoke); + } + return true; + } + + /** + * Calls a static Java method with one argument and no return value. The target method has to be + * set in the {@link MethodReference}, otherwise the node cannot be lowered. + */ + @NodeIntrinsic + public static native void invoke(@ConstantNodeParameter MethodReference methodReference, Object arg1); + + @SuppressWarnings("try") + public Invoke replaceWithInvoke() { + try (DebugCloseable context = withNodeSourcePosition(); InliningLog.UpdateScope updateScope = InliningLog.openUpdateScopeTrackingReplacement(graph().getInliningLog(), this)) { + InvokeNode invoke = createInvoke(graph()); + graph().replaceFixedWithFixed(this, invoke); + assert invoke.verify(); + return invoke; + } + } + + public InvokeNode createInvoke(StructuredGraph graph) { + MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(getInvokeKind(), getTargetMethod(), toArgumentArray(), getReturnStamp(), null)); + InvokeNode in = new InvokeNode(callTarget, bci(), MemoryKill.NO_LOCATION); + // this node has no side effect, propagate it to the invoke node + in.setSideEffect(false); + InvokeNode invoke = graph.add(in); + invoke.setStateDuring(stateBefore()); + return invoke; + } + + @Override + public void lower(LoweringTool tool) { + if (graph().getGuardsStage().areFrameStatesAtDeopts()) { + if (targetMethod == null) { + GraalError.guarantee(methodReference != null, "method reference shouldn't be null"); + setTargetMethod(methodReference.targetMethod); + } + Invoke invoke = replaceWithInvoke(); + assert invoke.asNode().verify(); + invoke.lower(tool); + } + } + + @Override + public boolean canDeoptimize() { + return true; + } + +} \ No newline at end of file diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/InvokeNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/InvokeNode.java index fc8af8eb4d06..2e740ea1d01e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/InvokeNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/InvokeNode.java @@ -40,6 +40,8 @@ import java.util.Map; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; @@ -52,8 +54,6 @@ import jdk.graal.compiler.nodes.spi.LIRLowerable; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.graal.compiler.nodes.spi.UncheckedInterfaceProvider; -import org.graalvm.word.LocationIdentity; - import jdk.vm.ci.code.BytecodeFrame; /** @@ -76,6 +76,7 @@ public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke protected InlineControl inlineControl; protected final LocationIdentity identity; private boolean isInOOMETry; + private boolean sideEffect; public InvokeNode(CallTargetNode callTarget, int bci) { this(callTarget, bci, callTarget.returnStamp().getTrustedStamp()); @@ -96,6 +97,7 @@ public InvokeNode(CallTargetNode callTarget, int bci, Stamp stamp, LocationIdent this.polymorphic = false; this.inlineControl = InlineControl.Normal; this.identity = identity; + this.sideEffect = super.hasSideEffect(); } @Override @@ -262,4 +264,13 @@ public void setInOOMETry(boolean isInOOMETry) { this.isInOOMETry = isInOOMETry; } + public void setSideEffect(boolean sideEffect) { + this.sideEffect = sideEffect; + } + + @Override + public boolean hasSideEffect() { + return sideEffect; + } + } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java index 52dd9207aabd..2d6b104c8950 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java @@ -109,8 +109,6 @@ import jdk.graal.compiler.phases.common.inlining.info.InlineInfo; import jdk.graal.compiler.phases.common.util.EconomicSetNodeEventListener; import jdk.graal.compiler.phases.util.ValueMergeUtil; -import jdk.graal.compiler.replacements.nodes.MacroInvokable; -import jdk.graal.compiler.replacements.nodes.ResolvedMethodHandleCallTargetNode; import jdk.graal.compiler.serviceprovider.SpeculationReasonGroup; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.DeoptimizationAction; @@ -499,15 +497,6 @@ public Node replacement(Node node) { unwindNode = (UnwindNode) duplicates.get(unwindNode); } - if (firstCFGNode instanceof MacroInvokable && invoke.callTarget() instanceof ResolvedMethodHandleCallTargetNode) { - // Replacing a method handle invoke with a MacroNode - MacroInvokable macroInvokable = (MacroInvokable) firstCFGNode; - ResolvedMethodHandleCallTargetNode methodHandle = (ResolvedMethodHandleCallTargetNode) invoke.callTarget(); - if (methodHandle.targetMethod().equals(macroInvokable.getTargetMethod()) && getDepth(invoke.stateAfter()) == getDepth(macroInvokable.stateAfter())) { - macroInvokable.addMethodHandleInfo(methodHandle); - } - } - finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph, returnAction, mark); GraphUtil.killCFG(invokeNode); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/MethodHandlePlugin.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/MethodHandlePlugin.java index 9bd8b1e0453e..85405036d3a7 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/MethodHandlePlugin.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/MethodHandlePlugin.java @@ -41,7 +41,6 @@ import jdk.graal.compiler.replacements.nodes.MacroInvokable; import jdk.graal.compiler.replacements.nodes.MacroNode; import jdk.graal.compiler.replacements.nodes.MethodHandleNode; -import jdk.graal.compiler.replacements.nodes.ResolvedMethodHandleCallTargetNode; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MethodHandleAccessProvider; import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod; @@ -102,7 +101,7 @@ public T add(T node) { b.addPush(invokeReturnStamp.getTrustedStamp().getStackKind(), methodHandleNode.asNode()); } } else { - ResolvedMethodHandleCallTargetNode callTarget = (ResolvedMethodHandleCallTargetNode) invoke.callTarget(); + CallTargetNode callTarget = invoke.callTarget(); NodeInputList argumentsList = callTarget.arguments(); for (int i = 0; i < argumentsList.size(); ++i) { argumentsList.initialize(i, b.append(argumentsList.get(i))); @@ -130,13 +129,8 @@ public T add(T node) { Invokable newInvokable = b.handleReplacedInvoke(invoke.getInvokeKind(), targetMethod, argumentsList.toArray(new ValueNode[argumentsList.size()]), inlineEverything); if (newInvokable != null) { if (newInvokable instanceof Invoke newInvoke && !newInvoke.callTarget().equals(callTarget) && newInvoke.asFixedNode().isAlive()) { - // In the case where the invoke is not inlined, replace its call target with - // the special ResolvedMethodHandleCallTargetNode. - newInvoke.callTarget().replaceAndDelete(b.append(callTarget)); return true; - } else if (newInvokable instanceof MacroInvokable macroInvokable) { - macroInvokable.addMethodHandleInfo(callTarget); - } else { + } else if (!(newInvokable instanceof MacroInvokable)) { throw GraalError.shouldNotReachHere("unexpected Invokable: " + newInvokable); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroInvokable.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroInvokable.java index f2fd76aa1d3f..d96c90ff8fdc 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroInvokable.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroInvokable.java @@ -67,24 +67,6 @@ public interface MacroInvokable extends Invokable, Lowerable, StateSplit, Single StampPair getReturnStamp(); - /** - * Access to the original arguments for a MethodHandle invoke call site. See - * {@link ResolvedMethodHandleCallTargetNode}. - */ - NodeInputList getOriginalArguments(); - - /** - * Access to the original target methods for a MethodHandle invoke call site. See - * {@link ResolvedMethodHandleCallTargetNode}. - */ - ResolvedJavaMethod getOriginalTargetMethod(); - - /** - * Access to the original return stamp for a MethodHandle invoke call site. See - * {@link ResolvedMethodHandleCallTargetNode}. - */ - StampPair getOriginalReturnStamp(); - /** * Gets the arguments for this macro node. */ @@ -185,27 +167,13 @@ default void lower(LoweringTool tool) { } /** - * Create the call target when converting this node back into a normal {@link Invoke}. For a - * method handle invoke site this will be a {@link ResolvedMethodHandleCallTargetNode}. + * Create the call target when converting this node back into a normal {@link Invoke}. */ default MethodCallTargetNode createCallTarget() { ValueNode[] arguments = getArguments().toArray(new ValueNode[getArguments().size()]); - if (getOriginalTargetMethod() != null) { - ValueNode[] originalArguments = getOriginalArguments().toArray(new ValueNode[getOriginalArguments().size()]); - return asNode().graph().add(ResolvedMethodHandleCallTargetNode.create(getInvokeKind(), getTargetMethod(), arguments, getReturnStamp(), getOriginalTargetMethod(), originalArguments, - getOriginalReturnStamp())); - - } else { - return asNode().graph().add(new MethodCallTargetNode(getInvokeKind(), getTargetMethod(), arguments, getReturnStamp(), null)); - } + return asNode().graph().add(new MethodCallTargetNode(getInvokeKind(), getTargetMethod(), arguments, getReturnStamp(), null)); } - /** - * Captures the method handle information so that it can be properly lowered back to an - * {@link Invoke} later. - */ - void addMethodHandleInfo(ResolvedMethodHandleCallTargetNode methodHandle); - /** * Build a new copy of the {@link MacroNode.MacroParams} stored in this node. */ diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroNode.java index de64c0300cf0..7bf5eba4c5cd 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroNode.java @@ -72,24 +72,6 @@ public abstract class MacroNode extends FixedWithNextNode implements MacroInvoka protected final InvokeKind invokeKind; protected final StampPair returnStamp; - /** - * The original target method for a MethodHandle invoke call site. See - * {@link ResolvedMethodHandleCallTargetNode}. - */ - protected ResolvedJavaMethod originalTargetMethod; - - /** - * The original return stamp for a MethodHandle invoke call site. See - * {@link ResolvedMethodHandleCallTargetNode}. - */ - protected StampPair originalReturnStamp; - - /** - * The original arguments for a MethodHandle invoke call site. See - * {@link ResolvedMethodHandleCallTargetNode}. - */ - @Input NodeInputList originalArguments; - /** * Encapsulates the parameters for constructing a {@link MacroNode} that are the same for all * leaf constructor call sites. Collecting the parameters in an object simplifies passing the @@ -154,7 +136,6 @@ protected MacroNode(NodeClass c, MacroParams p, FrameState this.invokeKind = p.invokeKind; assert !isPlaceholderBci(p.bci); assert MacroInvokable.assertArgumentCount(this); - this.originalArguments = new NodeInputList<>(this); this.stateAfter = stateAfter; } @@ -206,21 +187,6 @@ public StampPair getReturnStamp() { return returnStamp; } - @Override - public NodeInputList getOriginalArguments() { - return originalArguments; - } - - @Override - public ResolvedJavaMethod getOriginalTargetMethod() { - return originalTargetMethod; - } - - @Override - public StampPair getOriginalReturnStamp() { - return originalReturnStamp; - } - @Override public FrameState stateAfter() { return stateAfter; @@ -289,11 +255,4 @@ protected InvokeNode createInvoke(boolean verifyStamp) { return invoke; } - @Override - public void addMethodHandleInfo(ResolvedMethodHandleCallTargetNode methodHandle) { - assert originalArguments.size() == 0 && originalReturnStamp == null & originalTargetMethod == null : this; - originalReturnStamp = methodHandle.originalReturnStamp; - originalTargetMethod = methodHandle.originalTargetMethod; - originalArguments.addAll(methodHandle.originalArguments); - } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroWithExceptionNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroWithExceptionNode.java index 563a6cbe4a9c..ddbe17fe0638 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroWithExceptionNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MacroWithExceptionNode.java @@ -24,9 +24,11 @@ */ package jdk.graal.compiler.replacements.nodes; -import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci; import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; +import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci; + +import org.graalvm.word.LocationIdentity; import jdk.graal.compiler.core.common.type.StampPair; import jdk.graal.compiler.debug.DebugCloseable; @@ -45,8 +47,6 @@ import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.WithExceptionNode; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; -import org.graalvm.word.LocationIdentity; - import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -76,10 +76,6 @@ public abstract class MacroWithExceptionNode extends WithExceptionNode implement protected final InvokeKind invokeKind; protected final StampPair returnStamp; - protected ResolvedJavaMethod originalTargetMethod; - protected StampPair originalReturnStamp; - @Input NodeInputList originalArguments; - @SuppressWarnings("this-escape") protected MacroWithExceptionNode(NodeClass c, MacroNode.MacroParams p) { super(c, p.returnStamp != null ? p.returnStamp.getTrustedStamp() : null); @@ -91,7 +87,6 @@ protected MacroWithExceptionNode(NodeClass c, this.invokeKind = p.invokeKind; assert !isPlaceholderBci(p.bci); assert MacroInvokable.assertArgumentCount(this); - this.originalArguments = new NodeInputList<>(this); } @Override @@ -135,21 +130,6 @@ public StampPair getReturnStamp() { return returnStamp; } - @Override - public NodeInputList getOriginalArguments() { - return originalArguments; - } - - @Override - public ResolvedJavaMethod getOriginalTargetMethod() { - return originalTargetMethod; - } - - @Override - public StampPair getOriginalReturnStamp() { - return originalReturnStamp; - } - @Override protected void afterClone(Node other) { updateInliningLogAfterClone(other); @@ -214,11 +194,4 @@ public LocationIdentity getKilledLocationIdentity() { return LocationIdentity.any(); } - @Override - public void addMethodHandleInfo(ResolvedMethodHandleCallTargetNode methodHandle) { - assert originalArguments.size() == 0 && originalReturnStamp == null & originalTargetMethod == null : this; - originalReturnStamp = methodHandle.originalReturnStamp; - originalTargetMethod = methodHandle.originalTargetMethod; - originalArguments.addAll(methodHandle.originalArguments); - } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MethodHandleNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MethodHandleNode.java index 86779280730a..9788c23612ce 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MethodHandleNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/MethodHandleNode.java @@ -288,7 +288,7 @@ private static T getTargetInvokeNode(GraphAdder adder, Invoke JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass()); maybeCastArgument(adder, arguments, receiverSkip + index, parameterType); } - T invoke = createTargetInvokeNode(factory, assumptions, intrinsicMethod, realTarget, original, bci, returnStamp, arguments); + T invoke = createTargetInvokeNode(factory, assumptions, intrinsicMethod, realTarget, bci, returnStamp, arguments); assert invoke != null : "graph has been modified so this must result an invoke"; return invoke; } @@ -332,13 +332,12 @@ private static void maybeCastArgument(GraphAdder adder, ValueNode[] arguments, i } /** - * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed - * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}. + * Creates an {@link InvokeNode} for the given target method. * * @return invoke node for the member name target */ private static T createTargetInvokeNode(InvokeFactory factory, Assumptions assumptions, IntrinsicMethod intrinsicMethod, - ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, StampPair returnStamp, ValueNode[] arguments) { + ResolvedJavaMethod target, int bci, StampPair returnStamp, ValueNode[] arguments) { InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special; JavaType targetReturnType = target.getSignature().getReturnType(null); @@ -360,7 +359,7 @@ private static T createTargetInvokeNode(InvokeFactory fact } StampPair targetReturnStamp = StampFactory.forDeclaredType(assumptions, targetReturnType, false); - MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnStamp, original, arguments, returnStamp); + MethodCallTargetNode callTarget = new MethodCallTargetNode(targetInvokeKind, target, targetArguments, targetReturnStamp, null); // The call target can have a different return type than the invoker, // e.g. the target returns an Object but the invoker void. In this case diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/ResolvedMethodHandleCallTargetNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/ResolvedMethodHandleCallTargetNode.java deleted file mode 100644 index 8e1bd23b25be..000000000000 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/ResolvedMethodHandleCallTargetNode.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2013, 2023, 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.replacements.nodes; - -import java.lang.invoke.MethodHandle; - -import jdk.graal.compiler.core.common.type.StampPair; -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.graph.NodeInputList; -import jdk.graal.compiler.nodeinfo.NodeInfo; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.java.MethodCallTargetNode; -import jdk.graal.compiler.nodes.spi.Lowerable; -import jdk.graal.compiler.nodes.spi.LoweringTool; -import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -/** - * A call target that replaces itself in the graph when being lowered by restoring the original - * {@link MethodHandle} invocation target. This is required for when a {@link MethodHandle} call is - * resolved to a constant target but the target was not inlined. In that case, the original - * invocation must be restored with all of its original arguments. Why? HotSpot linkage for - * {@link MethodHandle} intrinsics (see {@code MethodHandles::generate_method_handle_dispatch}) - * expects certain implicit arguments to be on the stack such as the MemberName suffix argument for - * a call to one of the MethodHandle.linkTo* methods. An - * {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle} invocation - * drops these arguments which means the interpreter won't find them. - */ -@NodeInfo -public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable { - - public static final NodeClass TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class); - - /** - * Creates a call target for an invocation on a direct target derived by resolving a constant - * {@link MethodHandle}. - */ - public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, StampPair returnStamp, - ResolvedJavaMethod originalTargetMethod, - ValueNode[] originalArguments, StampPair originalReturnStamp) { - return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnStamp, originalTargetMethod, originalArguments, originalReturnStamp); - } - - protected final ResolvedJavaMethod originalTargetMethod; - protected final StampPair originalReturnStamp; - @Input NodeInputList originalArguments; - - protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, StampPair returnStamp, - ResolvedJavaMethod originalTargetMethod, - ValueNode[] originalArguments, StampPair originalReturnStamp) { - super(TYPE, invokeKind, targetMethod, arguments, returnStamp, null); - this.originalTargetMethod = originalTargetMethod; - this.originalReturnStamp = originalReturnStamp; - this.originalArguments = new NodeInputList<>(this, originalArguments); - } - - @Override - public void lower(LoweringTool tool) { - InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special; - MethodCallTargetNode replacement = graph().add( - new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnStamp, null)); - - // Replace myself... - this.replaceAndDelete(replacement); - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - throw GraalError.shouldNotReachHere("should have replaced itself"); // ExcludeFromJacocoGeneratedReport - } -} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleSafepointLoweringSnippet.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleSafepointLoweringSnippet.java index 71dd7a33fcf7..4d145f68d43b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleSafepointLoweringSnippet.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleSafepointLoweringSnippet.java @@ -24,33 +24,24 @@ */ package jdk.graal.compiler.truffle.hotspot; -import static jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect.NO_SIDE_EFFECT; -import static jdk.graal.compiler.hotspot.meta.HotSpotForeignCallDescriptor.Transition.SAFEPOINT; -import static jdk.graal.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.NO_LOCATIONS; import static jdk.graal.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; import org.graalvm.word.LocationIdentity; import jdk.graal.compiler.api.replacements.Snippet; import jdk.graal.compiler.api.replacements.Snippet.ConstantParameter; -import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.debug.DebugDumpHandlersFactory; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.graph.Node.ConstantNodeParameter; -import jdk.graal.compiler.graph.Node.NodeIntrinsic; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; import jdk.graal.compiler.hotspot.meta.DefaultHotSpotLoweringProvider; -import jdk.graal.compiler.hotspot.meta.HotSpotForeignCallDescriptor; import jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; import jdk.graal.compiler.hotspot.meta.HotSpotProviders; import jdk.graal.compiler.hotspot.nodes.CurrentJavaThreadNode; -import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.hotspot.nodes.InvokeStaticJavaMethodNode; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.extended.BranchProbabilityNode; -import jdk.graal.compiler.nodes.extended.ForeignCallNode; import jdk.graal.compiler.nodes.spi.LoweringTool; import jdk.graal.compiler.nodes.util.GraphUtil; import jdk.graal.compiler.options.OptionValues; @@ -62,25 +53,12 @@ import jdk.graal.compiler.truffle.nodes.TruffleSafepointNode; import jdk.graal.compiler.truffle.phases.TruffleSafepointInsertionPhase; import jdk.graal.compiler.word.Word; -import jdk.vm.ci.meta.ResolvedJavaMethod; /** * Snippet that lowers {@link TruffleSafepointNode}. */ public final class HotSpotTruffleSafepointLoweringSnippet implements Snippets { - /** - * Description for a call to - * {@code com.oracle.truffle.runtime.hotspot.HotSpotThreadLocalHandshake.doHandshake()} via a - * stub. - */ - static final HotSpotForeignCallDescriptor THREAD_LOCAL_HANDSHAKE = new HotSpotForeignCallDescriptor( - SAFEPOINT, - NO_SIDE_EFFECT, - NO_LOCATIONS, - "HotSpotThreadLocalHandshake.doHandshake", - void.class, Word.class, Object.class); - static final LocationIdentity PENDING_HANDSHAKE_LOCATION = NamedLocationIdentity.mutable("JavaThread::_jvmci_reserved0"); /** @@ -91,17 +69,14 @@ public final class HotSpotTruffleSafepointLoweringSnippet implements Snippets { * {@link TruffleSafepointInsertionPhase}. */ @Snippet - private static void pollSnippet(Word method, Object node, @ConstantParameter int pendingHandshakeOffset) { + private static void pollSnippet(Object node, @ConstantParameter int pendingHandshakeOffset) { Word thread = CurrentJavaThreadNode.get(); if (BranchProbabilityNode.probability(BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY, thread.readInt(pendingHandshakeOffset, PENDING_HANDSHAKE_LOCATION) != 0)) { - foreignPoll(THREAD_LOCAL_HANDSHAKE, method, node); + InvokeStaticJavaMethodNode.invoke(InvokeStaticJavaMethodNode.TRUFFLE_SAFEPOINT, node); } } - @NodeIntrinsic(value = ForeignCallNode.class) - private static native void foreignPoll(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word method, Object node); - static class Templates extends AbstractTemplates { private final SnippetInfo pollSnippet; @@ -113,11 +88,9 @@ static class Templates extends AbstractTemplates { this.pollSnippet = snippet(providers, HotSpotTruffleSafepointLoweringSnippet.class, "pollSnippet", PENDING_HANDSHAKE_LOCATION); } - public void lower(TruffleSafepointNode node, LoweringTool tool, ResolvedJavaMethod javaMethod) { + public void lower(TruffleSafepointNode node, LoweringTool tool) { StructuredGraph graph = node.graph(); Arguments args = new Arguments(pollSnippet, graph, tool.getLoweringStage()); - ValueNode method = ConstantNode.forConstant(tool.getStampProvider().createMethodStamp(), javaMethod.getEncoding(), tool.getMetaAccess(), graph); - args.add("method", method); args.add("node", node.location()); args.add("pendingHandshakeOffset", pendingHandshakeOffset); SnippetTemplate template = template(tool, node, args); @@ -150,7 +123,7 @@ public void lower(Node n, LoweringTool tool) { if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.LOW_TIER) { doDeferredInit(); if (templates != null) { - templates.lower((TruffleSafepointNode) n, tool, types.HotSpotThreadLocalHandshake_doHandshake); + templates.lower((TruffleSafepointNode) n, tool); } else { GraphUtil.unlinkFixedNode((TruffleSafepointNode) n); n.safeDelete(); @@ -176,12 +149,10 @@ public void initialize(HotSpotProviders providers, HotSpotHostForeignCallsProvider foreignCalls, Iterable factories) { GraalError.guarantee(templates == null, "cannot re-initialize %s", this); - if (config.invokeJavaMethodAddress != 0 && config.jvmciReserved0Offset != -1) { + if (config.jvmciReserved0Offset != -1) { this.templates = new Templates(options, providers, config.jvmciReserved0Offset); - foreignCalls.register(THREAD_LOCAL_HANDSHAKE.getSignature()); this.deferredInit = () -> { - long address = config.invokeJavaMethodAddress; - foreignCalls.invokeJavaMethodStub(options, providers, THREAD_LOCAL_HANDSHAKE, address); + InvokeStaticJavaMethodNode.TRUFFLE_SAFEPOINT.setTargetMethod(types.HotSpotThreadLocalHandshake_doHandshake); }; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java index 83445ca6346b..beb2718761a8 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java @@ -57,11 +57,9 @@ import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.LoopExplosionPlugin; -import jdk.graal.compiler.nodes.java.MethodCallTargetNode; import jdk.graal.compiler.nodes.util.GraphUtil; import jdk.graal.compiler.replacements.PEGraphDecoder; import jdk.graal.compiler.replacements.nodes.MethodHandleWithExceptionNode; -import jdk.graal.compiler.replacements.nodes.ResolvedMethodHandleCallTargetNode; import jdk.vm.ci.meta.ResolvedJavaMethod; public class InlineBeforeAnalysisGraphDecoder extends PEGraphDecoder { @@ -269,10 +267,6 @@ protected LoopScope processNextNode(MethodScope ms, LoopScope loopScope) { return super.processNextNode(methodScope, loopScope); } - protected MethodCallTargetNode createCallTargetNode(ResolvedMethodHandleCallTargetNode t) { - return new MethodCallTargetNode(t.invokeKind(), t.targetMethod(), t.arguments().toArray(ValueNode.EMPTY_ARRAY), t.returnStamp(), t.getTypeProfile()); - } - @Override protected LoopScope handleMethodHandle(MethodScope s, LoopScope loopScope, InvokableData invokableData) { MethodHandleWithExceptionNode node = invokableData.invoke; @@ -288,13 +282,7 @@ protected LoopScope handleMethodHandle(MethodScope s, LoopScope loopScope, Invok invokableData.nextOrderId, invokableData.exceptionOrderId, invokableData.exceptionStateOrderId, invokableData.exceptionNextOrderId); CallTargetNode callTarget; - if (invoke.callTarget() instanceof ResolvedMethodHandleCallTargetNode t) { - // This special CallTargetNode lowers itself back to the original target (e.g. linkTo*) - // if the invocation hasn't been inlined, which we don't want for Native Image. - callTarget = createCallTargetNode(t); - } else { - callTarget = (CallTargetNode) invoke.callTarget().copyWithInputs(false); - } + callTarget = (CallTargetNode) invoke.callTarget().copyWithInputs(false); // handleInvoke() expects that CallTargetNode is not eagerly added to the graph invoke.callTarget().replaceAtUsagesAndDelete(null); invokeData.callTarget = callTarget; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisGraphDecoderImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisGraphDecoderImpl.java index 4c3356a6330f..c9e14364eb7a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisGraphDecoderImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisGraphDecoderImpl.java @@ -31,7 +31,6 @@ import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; -import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; @@ -40,10 +39,7 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.java.LoadFieldNode; -import jdk.graal.compiler.nodes.java.MethodCallTargetNode; -import jdk.graal.compiler.replacements.nodes.ResolvedMethodHandleCallTargetNode; public class InlineBeforeAnalysisGraphDecoderImpl extends InlineBeforeAnalysisGraphDecoder { @@ -126,9 +122,4 @@ private Node handleIsStaticFinalFieldInitializedNode(IsStaticFinalFieldInitializ } return node; } - - @Override - protected MethodCallTargetNode createCallTargetNode(ResolvedMethodHandleCallTargetNode t) { - return new SubstrateMethodCallTargetNode(t.invokeKind(), t.targetMethod(), t.arguments().toArray(ValueNode.EMPTY_ARRAY), t.returnStamp(), t.getTypeProfile()); - } }