Skip to content

Commit

Permalink
[GR-29688] New method handle intrinsification.
Browse files Browse the repository at this point in the history
PullRequest: graal/14869
  • Loading branch information
peter-hofer committed Aug 13, 2023
2 parents a216052 + b497acf commit 74ad47b
Show file tree
Hide file tree
Showing 60 changed files with 1,960 additions and 912 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode;
import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
import org.graalvm.compiler.nodes.java.InstanceOfNode;
Expand Down Expand Up @@ -333,6 +334,8 @@ protected void dispatch(Node node) {
lower((IdentityHashCodeNode) node);
} else if (node instanceof ClassIsAssignableFromNode) {
lower((ClassIsAssignableFromNode) node);
} else if (node instanceof DynamicNewInstanceNode n) {
lower(n);
} else {
if (!isIgnored(node)) {
handleUnknownNodeType(node);
Expand Down Expand Up @@ -439,6 +442,8 @@ protected void handleUnknownNodeType(Node node) {

protected abstract void lower(NewInstanceNode node);

protected abstract void lower(DynamicNewInstanceNode node);

protected abstract void lower(NotNode node);

protected abstract void lower(NarrowNode node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1338,6 +1338,16 @@ protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKi
deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}

protected FrameStateBuilder createFrameStateForExceptionHandling(@SuppressWarnings("unused") int bci) {
FrameStateBuilder dispatchState = frameState.copy();
dispatchState.clearStack();
return dispatchState;
}

protected void clearNonLiveLocals(FrameStateBuilder state, BciBlock block, boolean liveIn) {
state.clearNonLiveLocals(block, liveness, liveIn);
}

/**
* @return the entry point to exception dispatch
*/
Expand All @@ -1346,8 +1356,7 @@ protected AbstractBeginNode handleException(ValueNode exceptionObject, int bci,
assert bci == BytecodeFrame.BEFORE_BCI || bci == bci() : "invalid bci";
debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, (profilingInfo == null ? "" : profilingInfo.getExceptionSeen(bci)));

FrameStateBuilder dispatchState = frameState.copy();
dispatchState.clearStack();
FrameStateBuilder dispatchState = createFrameStateForExceptionHandling(bci);

AbstractBeginNode dispatchBegin;
if (exceptionObject == null) {
Expand All @@ -1374,13 +1383,20 @@ protected AbstractBeginNode handleException(ValueNode exceptionObject, int bci,
return dispatchBegin;
}

protected void createHandleExceptionTarget(FixedWithNextNode afterExceptionLoaded, int bci, FrameStateBuilder dispatchState) {
private void createHandleExceptionTarget(FixedWithNextNode afterExceptionLoaded, int bci, FrameStateBuilder dispatchState) {
FixedWithNextNode afterInstrumentation = afterExceptionLoaded;
for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
afterInstrumentation = plugin.instrumentExceptionDispatch(graph, afterInstrumentation, () -> dispatchState.create(bci, getNonIntrinsicAncestor(), false, null, null));
assert afterInstrumentation.next() == null : "exception dispatch instrumentation will be linked to dispatch block";
}

BciBlock dispatchBlock = getDispatchBlock(bci);

FixedNode target = createTarget(dispatchBlock, dispatchState);
afterInstrumentation.setNext(target);
}

protected BciBlock getDispatchBlock(int bci) {
BciBlock dispatchBlock = currentBlock.exceptionDispatchBlock();
/*
* The exception dispatch block is always for the last bytecode of a block, so if we are not
Expand All @@ -1391,8 +1407,7 @@ protected void createHandleExceptionTarget(FixedWithNextNode afterExceptionLoade
dispatchBlock = blockMap.getUnwindBlock();
}

FixedNode target = createTarget(dispatchBlock, dispatchState);
afterInstrumentation.setNext(target);
return dispatchBlock;
}

protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind kind) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,9 @@ public boolean contains(ValueNode value) {
return false;
}

/**
* @param liveIn true if live in, false if live out
*/
public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
/*
* Non-live local clearing is mandatory for the entry block of an OSR compilation so that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import org.graalvm.compiler.nodes.spi.Canonicalizable;
import org.graalvm.compiler.nodes.spi.CanonicalizerTool;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.replacements.nodes.MethodHandleWithExceptionNode;

import jdk.vm.ci.code.Architecture;
import jdk.vm.ci.meta.Assumptions;
Expand Down Expand Up @@ -446,31 +447,21 @@ public int hashCode() {
}
}

/**
* Additional information encoded for {@link Invoke} nodes to allow method inlining without
* decoding the frame state and successors beforehand.
*/
protected static class InvokeData {
public final Invoke invoke;
protected static class InvokableData<T extends Invokable> {
public final T invoke;
public final ResolvedJavaType contextType;
public final int invokeOrderId;
public final int callTargetOrderId;
public final int orderId;
public final int stateAfterOrderId;
public final int nextOrderId;

public final int exceptionOrderId;
public final int exceptionStateOrderId;
public final int exceptionNextOrderId;
public JavaConstant constantReceiver;
public CallTargetNode callTarget;
public FixedWithNextNode invokePredecessor;

protected InvokeData(Invoke invoke, ResolvedJavaType contextType, int invokeOrderId, int callTargetOrderId, int stateAfterOrderId, int nextOrderId,
protected InvokableData(T invoke, ResolvedJavaType contextType, int orderId, int stateAfterOrderId, int nextOrderId,
int exceptionOrderId, int exceptionStateOrderId, int exceptionNextOrderId) {
this.invoke = invoke;
this.contextType = contextType;
this.invokeOrderId = invokeOrderId;
this.callTargetOrderId = callTargetOrderId;
this.orderId = orderId;
this.stateAfterOrderId = stateAfterOrderId;
this.nextOrderId = nextOrderId;
this.exceptionOrderId = exceptionOrderId;
Expand All @@ -479,6 +470,31 @@ protected InvokeData(Invoke invoke, ResolvedJavaType contextType, int invokeOrde
}
}

/**
* Additional information encoded for {@link Invoke} nodes to allow method inlining without
* decoding the frame state and successors beforehand.
*/
protected static class InvokeData extends InvokableData<Invoke> {
static InvokeData createFrom(InvokableData<? extends Invoke> from, int callTargetOrderId, boolean intrinsifiedMethodHandle) {
return new InvokeData(from.invoke, from.contextType, from.orderId, callTargetOrderId, intrinsifiedMethodHandle,
from.stateAfterOrderId, from.nextOrderId, from.exceptionOrderId, from.exceptionStateOrderId, from.exceptionNextOrderId);
}

public final int callTargetOrderId;
public final boolean intrinsifiedMethodHandle;

public JavaConstant constantReceiver;
public CallTargetNode callTarget;
public FixedWithNextNode invokePredecessor;

public InvokeData(Invoke invoke, ResolvedJavaType contextType, int invokeOrderId, int callTargetOrderId, boolean intrinsifiedMethodHandle,
int stateAfterOrderId, int nextOrderId, int exceptionOrderId, int exceptionStateOrderId, int exceptionNextOrderId) {
super(invoke, contextType, invokeOrderId, stateAfterOrderId, nextOrderId, exceptionOrderId, exceptionStateOrderId, exceptionNextOrderId);
this.callTargetOrderId = callTargetOrderId;
this.intrinsifiedMethodHandle = intrinsifiedMethodHandle;
}
}

/**
* A node that is created during {@link LoopExplosionKind#MERGE_EXPLODE loop explosion} that can
* later be replaced by a ProxyNode if {@link LoopDetector loop detection} finds out that the
Expand Down Expand Up @@ -903,6 +919,9 @@ protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope
} else if (node instanceof Invoke) {
InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node);
resultScope = handleInvoke(methodScope, loopScope, invokeData);
} else if (node instanceof MethodHandleWithExceptionNode methodHandle) {
InvokableData<MethodHandleWithExceptionNode> invokableData = readInvokableData(methodScope, nodeOrderId, methodHandle);
resultScope = handleMethodHandle(methodScope, loopScope, invokableData);
} else if (node instanceof ReturnNode || node instanceof UnwindNode) {
methodScope.returnAndUnwindNodes.add((ControlSinkNode) node);
} else {
Expand All @@ -923,23 +942,32 @@ protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope
}
}

protected InvokeData readInvokeData(MethodScope methodScope, int invokeOrderId, Invoke invoke) {
protected LoopScope handleMethodHandle(MethodScope methodScope, LoopScope loopScope, InvokableData<MethodHandleWithExceptionNode> invokableData) {
appendInvokable(methodScope, loopScope, invokableData);
return loopScope;
}

protected <T extends Invokable> InvokableData<T> readInvokableData(MethodScope methodScope, int orderId, T node) {
ResolvedJavaType contextType = (ResolvedJavaType) readObject(methodScope);
int callTargetOrderId = readOrderId(methodScope);
int stateAfterOrderId = readOrderId(methodScope);
int nextOrderId = readOrderId(methodScope);

if (invoke instanceof InvokeWithExceptionNode) {
if (node instanceof WithExceptionNode) {
int exceptionOrderId = readOrderId(methodScope);
int exceptionStateOrderId = readOrderId(methodScope);
int exceptionNextOrderId = readOrderId(methodScope);
return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, exceptionOrderId, exceptionStateOrderId,
exceptionNextOrderId);
return new InvokableData<>(node, contextType, orderId, stateAfterOrderId, nextOrderId, exceptionOrderId, exceptionStateOrderId, exceptionNextOrderId);
} else {
return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, -1, -1, -1);
return new InvokableData<>(node, contextType, orderId, stateAfterOrderId, nextOrderId, -1, -1, -1);
}
}

protected InvokeData readInvokeData(MethodScope methodScope, int invokeOrderId, Invoke invoke) {
int callTargetOrderId = readOrderId(methodScope);
InvokableData<Invoke> invokableData = readInvokableData(methodScope, invokeOrderId, invoke);
return InvokeData.createFrom(invokableData, callTargetOrderId, false);
}

/**
* {@link Invoke} nodes do not have the {@link CallTargetNode}, {@link FrameState}, and
* successors encoded. Instead, this information is provided separately to allow method inlining
Expand All @@ -963,15 +991,21 @@ protected void appendInvoke(MethodScope methodScope, LoopScope loopScope, Invoke
} else {
((InvokeNode) invokeData.invoke).setCallTarget(callTarget);
}
appendInvokable(methodScope, loopScope, invokeData);
}

private <T extends Invokable & StateSplit> void appendInvokable(MethodScope methodScope, LoopScope loopScope, InvokableData<T> invokeData) {
if (invokeData.invoke.stateAfter() == null) {
invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
}
assert invokeData.invoke.stateDuring() == null : "stateDuring is not used in high tier graphs";
assert !(invokeData.invoke instanceof Invoke inv && inv.stateDuring() != null) : "stateDuring is not used in high tier graphs";

invokeData.invoke.setNext(makeStubNode(methodScope, loopScope, invokeData.nextOrderId));
if (invokeData.invoke instanceof InvokeWithExceptionNode) {
((InvokeWithExceptionNode) invokeData.invoke).setExceptionEdge((AbstractBeginNode) makeStubNode(methodScope, loopScope, invokeData.exceptionOrderId));
FixedNode next = makeStubNode(methodScope, loopScope, invokeData.nextOrderId);
if (invokeData.invoke instanceof WithExceptionNode withException) {
withException.setNext((AbstractBeginNode) next);
withException.setExceptionEdge((AbstractBeginNode) makeStubNode(methodScope, loopScope, invokeData.exceptionOrderId));
} else {
((FixedWithNextNode) invokeData.invoke).setNext(next);
}
}

Expand Down Expand Up @@ -1705,18 +1739,17 @@ protected FixedNode makeStubNode(MethodScope methodScope, LoopScope loopScope, i
}

protected static boolean skipDirectEdge(Node node, Edges edges, int index) {
if (node instanceof Invoke) {
assert node instanceof InvokeNode || node instanceof InvokeWithExceptionNode : "The only two Invoke node classes. Got " + node.getClass();
if (node instanceof Invoke || node instanceof MethodHandleWithExceptionNode) {
assert node instanceof InvokeNode || node instanceof InvokeWithExceptionNode || node instanceof MethodHandleWithExceptionNode : "The only supported node classes. Got " + node.getClass();
if (edges.type() == Edges.Type.Successors) {
assert edges.getCount() == (node instanceof InvokeWithExceptionNode ? 2
: 1) : "InvokeNode has one successor (next); InvokeWithExceptionNode has two successors (next, exceptionEdge)";
assert edges.getCount() == (node instanceof WithExceptionNode ? 2 : 1) : "Base Invokable has one successor (next); WithExceptionNode has two successors (next, exceptionEdge)";
return true;
} else {
assert edges.type() == Edges.Type.Inputs;
if (edges.getType(index) == CallTargetNode.class) {
return true;
} else if (edges.getType(index) == FrameState.class) {
assert edges.get(node, index) == null || edges.get(node, index) == ((Invoke) node).stateAfter() : "Only stateAfter can be a FrameState during encoding";
assert edges.get(node, index) == null || edges.get(node, index) == ((StateSplit) node).stateAfter() : "Only stateAfter can be a FrameState during encoding";
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.nodes.EncodedGraph.EncodedNodeReference;
import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
import org.graalvm.compiler.replacements.nodes.MethodHandleWithExceptionNode;

import jdk.vm.ci.code.Architecture;

Expand Down Expand Up @@ -216,8 +217,8 @@ public void prepare(StructuredGraph graph) {
addObject(nodeClass.getData().get(node, i));
}
}
if (node instanceof Invoke) {
addObject(((Invoke) node).getContextType());
if (node instanceof Invoke || node instanceof MethodHandleWithExceptionNode) {
addObject(((Invokable) node).getContextType());
}
}
}
Expand Down Expand Up @@ -313,19 +314,24 @@ protected int encode(StructuredGraph graph, Iterable<EncodedNodeReference> nodeR
writeOrderId(proxy, nodeOrder);
}

} else if (node instanceof Invoke) {
Invoke invoke = (Invoke) node;
assert invoke.stateDuring() == null : "stateDuring is not used in high-level graphs";
} else if (node instanceof Invoke || node instanceof MethodHandleWithExceptionNode) {
Node next;
if (node instanceof Invoke invoke) {
assert invoke.stateDuring() == null : "stateDuring is not used in high-level graphs";
writeOrderId(invoke.callTarget(), nodeOrder);
next = invoke.next();
} else {
next = ((MethodHandleWithExceptionNode) node).next();
}

writeObjectId(invoke.getContextType());
writeOrderId(invoke.callTarget(), nodeOrder);
writeOrderId(invoke.stateAfter(), nodeOrder);
writeOrderId(invoke.next(), nodeOrder);
if (invoke instanceof InvokeWithExceptionNode) {
InvokeWithExceptionNode invokeWithExcpetion = (InvokeWithExceptionNode) invoke;
ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExcpetion.exceptionEdge();
Invokable inv = (Invokable) node;
writeObjectId(inv.getContextType());
writeOrderId(((StateSplit) inv).stateAfter(), nodeOrder);
writeOrderId(next, nodeOrder);
if (inv instanceof WithExceptionNode withException) {
ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) withException.exceptionEdge();

writeOrderId(invokeWithExcpetion.exceptionEdge(), nodeOrder);
writeOrderId(withException.exceptionEdge(), nodeOrder);
writeOrderId(exceptionEdge.stateAfter(), nodeOrder);
writeOrderId(exceptionEdge.next(), nodeOrder);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.graalvm.compiler.graph.Node;

import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;

/**
* A marker interface for nodes that represent calls to other methods.
Expand All @@ -42,6 +43,20 @@ public interface Invokable extends DeoptBciSupplier {
*/
ResolvedJavaMethod getContextMethod();

/**
* Returns the {@linkplain ResolvedJavaType type} from which this invoke is executed. This is
* the declaring type of the caller method.
*
* @return the type from which this invoke is executed.
*/
default ResolvedJavaType getContextType() {
ResolvedJavaMethod contextMethod = getContextMethod();
if (contextMethod == null) {
return null;
}
return contextMethod.getDeclaringClass();
}

/**
* Returns the receiver cast to {@link FixedNode}, or null if this invokable is a placeholder.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,6 @@ default ResolvedJavaMethod getContextMethod() {
return state.getMethod();
}

/**
* Returns the {@linkplain ResolvedJavaType type} from which this invoke is executed. This is
* the declaring type of the caller method.
*
* @return the type from which this invoke is executed.
*/
default ResolvedJavaType getContextType() {
ResolvedJavaMethod contextMethod = getContextMethod();
if (contextMethod == null) {
return null;
}
return contextMethod.getDeclaringClass();
}

@Override
default void computeStateDuring(FrameState stateAfter) {
FrameState newStateDuring = stateAfter.duplicateModifiedDuringCall(bci(), asNode().getStackKind());
Expand Down
Loading

0 comments on commit 74ad47b

Please sign in to comment.