use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class InliningUtil method handleMissingAfterExceptionFrameState.
@SuppressWarnings("try")
public static FrameState handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState, Invoke invoke, EconomicMap<Node, Node> replacements, boolean alwaysDuplicateStateAfter) {
StructuredGraph graph = nonReplaceableFrameState.graph();
NodeWorkList workList = graph.createNodeWorkList();
workList.add(nonReplaceableFrameState);
for (Node node : workList) {
FrameState fs = (FrameState) node;
for (Node usage : fs.usages().snapshot()) {
if (!usage.isAlive()) {
continue;
}
if (usage instanceof FrameState) {
workList.add(usage);
} else {
StateSplit stateSplit = (StateSplit) usage;
FixedNode fixedStateSplit = stateSplit.asFixedNode();
if (fixedStateSplit instanceof AbstractMergeNode) {
AbstractMergeNode merge = (AbstractMergeNode) fixedStateSplit;
while (merge.isAlive()) {
AbstractEndNode end = merge.forwardEnds().first();
try (DebugCloseable position = end.withNodeSourcePosition()) {
DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
end.replaceAtPredecessor(deoptimizeNode);
GraphUtil.killCFG(end);
}
}
} else if (fixedStateSplit instanceof ExceptionObjectNode) {
/**
* The target invoke does not have an exception edge. This means that the
* bytecode parser made the wrong assumption of making an exception for the
* partial intrinsic exit. We therefore replace the WithExceptionNode with a
* non throwing version -- the deoptimization occurs when the invoke throws.
*/
WithExceptionNode oldException = (WithExceptionNode) fixedStateSplit.predecessor();
FixedNode newNode = oldException.replaceWithNonThrowing();
if (replacements != null && oldException != newNode) {
replacements.put(oldException, newNode);
}
if (newNode instanceof StateSplit) {
handleAfterBciFrameState(((StateSplit) newNode).stateAfter(), invoke, alwaysDuplicateStateAfter);
}
} else {
try (DebugCloseable position = fixedStateSplit.withNodeSourcePosition()) {
FixedNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
if (fixedStateSplit instanceof AbstractBeginNode) {
deoptimizeNode = BeginNode.begin(deoptimizeNode);
}
fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
GraphUtil.killCFG(fixedStateSplit);
}
}
}
}
}
return nonReplaceableFrameState;
}
use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class PlaceholderLogicNode method rewireFrameStatesAfterFSA.
private void rewireFrameStatesAfterFSA(ValueNode replacee, UnmodifiableEconomicMap<Node, Node> duplicates) {
DeoptimizingNode replaceeDeopt = (DeoptimizingNode) replacee;
GraalError.guarantee(replaceeDeopt.canDeoptimize(), "Method expects the replacee to have deopt state");
FrameState stateBefore = null;
FrameState stateDuring = null;
FrameState stateAfter = null;
if (replaceeDeopt instanceof DeoptimizingNode.DeoptBefore) {
stateBefore = ((DeoptimizingNode.DeoptBefore) replaceeDeopt).stateBefore();
}
if (replaceeDeopt instanceof DeoptimizingNode.DeoptDuring) {
stateDuring = ((DeoptimizingNode.DeoptDuring) replaceeDeopt).stateDuring();
}
if (replaceeDeopt instanceof DeoptimizingNode.DeoptAfter) {
stateAfter = ((DeoptimizingNode.DeoptAfter) replaceeDeopt).stateAfter();
}
if (stateAfter == null && stateDuring == null && stateBefore == null) {
/*
* There should only be no state available to transfer during testing or if the
* replacee's graph itself is a substitution.
*/
StructuredGraph graph = replacee.graph();
boolean condition = graph.isStateAfterClearedForTesting() || graph.isSubstitution();
GraalError.guarantee(condition, "No state available to transfer");
return;
}
final ExceptionObjectNode exceptionObject;
if (replacee instanceof WithExceptionNode) {
WithExceptionNode withExceptionNode = (WithExceptionNode) replacee;
if (withExceptionNode.exceptionEdge() instanceof ExceptionObjectNode) {
exceptionObject = (ExceptionObjectNode) withExceptionNode.exceptionEdge();
} else {
GraalError.guarantee(withExceptionNode.exceptionEdge() instanceof UnreachableBeginNode, "Unexpected exception edge %s", withExceptionNode.exceptionEdge());
exceptionObject = null;
}
} else {
exceptionObject = null;
}
for (DeoptimizingNode deoptNode : deoptNodes) {
DeoptimizingNode deoptDup = (DeoptimizingNode) duplicates.get(deoptNode.asNode());
if (deoptDup.canDeoptimize()) {
if (deoptDup instanceof ExceptionObjectNode) {
ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) deoptDup;
rewireExceptionFrameState(exceptionObject, newExceptionObject, newExceptionObject);
continue;
}
if (deoptDup instanceof DeoptimizingNode.DeoptBefore) {
GraalError.guarantee(stateBefore != null, "Invalid stateBefore being transferred.");
((DeoptimizingNode.DeoptBefore) deoptDup).setStateBefore(stateBefore);
}
if (deoptDup instanceof DeoptimizingNode.DeoptDuring) {
// compute a state "during" for a DeoptDuring inside the snippet depending
// on what kind of states we had on the node we are replacing.
// If the original node had a state "during" already, we just use that,
// otherwise we need to find a strategy to compute a state during based on
// some other state (before or after).
DeoptimizingNode.DeoptDuring deoptDupDuring = (DeoptimizingNode.DeoptDuring) deoptDup;
if (stateDuring != null) {
deoptDupDuring.setStateDuring(stateDuring);
} else if (stateAfter != null) {
deoptDupDuring.computeStateDuring(stateAfter);
} else if (stateBefore != null) {
boolean guarantee = ((DeoptBefore) replaceeDeopt).canUseAsStateDuring() || !deoptDupDuring.hasSideEffect();
GraalError.guarantee(guarantee, "Can't use stateBefore as stateDuring for state split %s", deoptDupDuring);
deoptDupDuring.setStateDuring(stateBefore);
} else {
throw GraalError.shouldNotReachHere("No stateDuring assigned.");
}
}
if (deoptDup instanceof DeoptimizingNode.DeoptAfter) {
DeoptimizingNode.DeoptAfter deoptDupAfter = (DeoptimizingNode.DeoptAfter) deoptDup;
if (stateAfter != null) {
deoptDupAfter.setStateAfter(stateAfter);
} else {
boolean guarantee = stateBefore != null && !deoptDupAfter.hasSideEffect();
GraalError.guarantee(guarantee, "Can't use stateBefore as stateAfter for state split %s", deoptDupAfter);
deoptDupAfter.setStateAfter(stateBefore);
}
}
}
}
}
use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class PlaceholderLogicNode method assignNecessaryFrameStates.
private void assignNecessaryFrameStates(ValueNode replacee, UnmodifiableEconomicMap<Node, Node> duplicates, FixedNode replaceeGraphCFGPredecessor) {
FrameState stateAfter = null;
if (replacee instanceof StateSplit && ((StateSplit) replacee).hasSideEffect()) {
stateAfter = ((StateSplit) replacee).stateAfter();
GraalError.guarantee(stateAfter != null, "Statesplit with side-effect %s needs a framestate", replacee);
} else {
/*
* We dont have a state split as a replacee, thus we take the prev state as the state
* after for the node in the snippet.
*/
stateAfter = GraphUtil.findLastFrameState(replaceeGraphCFGPredecessor);
}
final ExceptionObjectNode exceptionObject;
if (replacee instanceof WithExceptionNode) {
WithExceptionNode withExceptionNode = (WithExceptionNode) replacee;
if (withExceptionNode.exceptionEdge() instanceof ExceptionObjectNode) {
exceptionObject = (ExceptionObjectNode) withExceptionNode.exceptionEdge();
} else {
GraalError.guarantee(withExceptionNode.exceptionEdge() instanceof UnreachableBeginNode, "Unexpected exception edge %s", withExceptionNode.exceptionEdge());
exceptionObject = null;
}
} else {
exceptionObject = null;
}
NodeMap<NodeStateAssignment> assignedStateMappings = frameStateAssignment.getStateMapping();
MapCursor<Node, NodeStateAssignment> stateAssignments = assignedStateMappings.getEntries();
while (stateAssignments.advance()) {
Node nodeRequiringState = stateAssignments.getKey();
if (nodeRequiringState instanceof DeoptBciSupplier) {
if (replacee instanceof DeoptBciSupplier) {
((DeoptBciSupplier) duplicates.get(nodeRequiringState)).setBci(((DeoptBciSupplier) replacee).bci());
}
}
NodeStateAssignment assignment = stateAssignments.getValue();
switch(assignment) {
case AFTER_BCI:
setReplaceeGraphStateAfter(nodeRequiringState, replacee, duplicates, stateAfter);
break;
case AFTER_EXCEPTION_BCI:
if (nodeRequiringState instanceof ExceptionObjectNode) {
ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) duplicates.get(nodeRequiringState);
rewireExceptionFrameState(exceptionObject, newExceptionObject, newExceptionObject);
} else if (nodeRequiringState instanceof MergeNode) {
MergeNode mergeNode = (MergeNode) duplicates.get(nodeRequiringState);
rewireExceptionFrameState(exceptionObject, getExceptionValueFromMerge(mergeNode), mergeNode);
} else {
GraalError.shouldNotReachHere("Unexpected exception state node: " + nodeRequiringState);
}
break;
case BEFORE_BCI:
FrameState stateBeforeSnippet = GraphUtil.findLastFrameState(replaceeGraphCFGPredecessor);
((StateSplit) duplicates.get(nodeRequiringState)).setStateAfter(stateBeforeSnippet.duplicate());
break;
case INVALID:
/*
* We cannot assign a proper frame state for this snippet's node since there are
* effects which cannot be represented by a single state at the node
*/
throw GraalError.shouldNotReachHere("Invalid snippet replacing a node before frame state assignment with node " + nodeRequiringState + " for replacee " + replacee);
default:
throw GraalError.shouldNotReachHere("Unknown StateAssigment:" + assignment);
}
replacee.graph().getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, replacee.graph(), "After duplicating after state for node %s in snippet", duplicates.get(nodeRequiringState));
}
}
use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class PlaceholderLogicNode method instantiate.
/**
* Replaces a given fixed node with this specialized snippet.
*
* @param metaAccess
* @param replacee the node that will be replaced
* @param replacer object that replaces the usages of {@code replacee}
* @param args the arguments to be bound to the flattened positional parameters of the snippet
* @param killReplacee is true, the replacee node is deleted
* @return the map of duplicated nodes (original -> duplicate)
*/
@SuppressWarnings("try")
public UnmodifiableEconomicMap<Node, Node> instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args, boolean killReplacee) {
if (!(replacee instanceof ControlSinkNode)) {
/*
* For all use cases of this, the replacee is killed sooner ({@code killReplacee ==
* true}) or later (by the caller of this method). However, we cannot do that if the
* snippet does not have a return node we because that means we kill the {@code
* replacee.next()} which might be connected to a merge whose next node has not yet been
* lowered [GR-33909].
*/
GraalError.guarantee(this.returnNode != null, "Cannot kill %s because snippet %s does not have a return node", replacee, this);
}
DebugContext debug = replacee.getDebug();
assert assertSnippetKills(replacee);
try (DebugCloseable a = args.info.instantiationTimer.start(debug)) {
args.info.instantiationCounter.increment(debug);
// Inline the snippet nodes, replacing parameters with the given args in the process
final FixedNode replaceeGraphPredecessor = (FixedNode) replacee.predecessor();
StartNode entryPointNode = snippet.start();
FixedNode firstCFGNode = entryPointNode.next();
StructuredGraph replaceeGraph = replacee.graph();
EconomicMap<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
replacements.put(entryPointNode, AbstractBeginNode.prevBegin(replacee));
EconomicMap<Node, Node> duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements);
// Re-wire the control flow graph around the replacee
FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
replacee.replaceAtPredecessor(firstCFGNodeDuplicate);
if (replacee.graph().getGuardsStage().areFrameStatesAtSideEffects()) {
boolean replaceeHasSideEffect = replacee instanceof StateSplit && ((StateSplit) replacee).hasSideEffect();
boolean replacementHasSideEffect = !sideEffectNodes.isEmpty();
if (replacementHasSideEffect) {
GraalError.guarantee(replaceeHasSideEffect, "Lowering node %s without side-effect to snippet %s with sideeffects=%s", replacee, info, this.sideEffectNodes);
}
}
updateStamps(replacee, duplicates);
rewireMemoryGraph(replacee, duplicates);
rewireFrameStates(replacee, duplicates, replaceeGraphPredecessor);
// Replace all usages of the replacee with the value returned by the snippet
ValueNode returnValue = null;
AbstractBeginNode originalWithExceptionNextNode = null;
if (returnNode != null && !(replacee instanceof ControlSinkNode)) {
ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode);
returnValue = returnDuplicate.result();
if (returnValue == null && replacee.usages().isNotEmpty() && replacee instanceof MemoryKill) {
replacer.replace(replacee, null);
} else {
assert returnValue != null || replacee.hasNoUsages();
replacer.replace(replacee, returnValue);
}
if (returnDuplicate.isAlive()) {
FixedNode next = null;
if (replacee instanceof FixedWithNextNode) {
FixedWithNextNode fwn = (FixedWithNextNode) replacee;
next = fwn.next();
fwn.setNext(null);
} else if (replacee instanceof WithExceptionNode) {
WithExceptionNode withExceptionNode = (WithExceptionNode) replacee;
next = originalWithExceptionNextNode = withExceptionNode.next();
withExceptionNode.setNext(null);
}
returnDuplicate.replaceAndDelete(next);
}
}
if (unwindPath != null && unwindPath.isAlive()) {
GraalError.guarantee(replacee.graph().isBeforeStage(StageFlag.FLOATING_READS) || replacee instanceof WithExceptionNode, "Using a snippet with an UnwindNode after floating reads would require support for the memory graph (unless the replacee has an exception edge)");
GraalError.guarantee(replacee instanceof WithExceptionNode, "Snippet has an UnwindNode, but replacee is not a node with an exception handler");
// snippet exception handler
UnwindNode snippetUnwindDuplicate = (UnwindNode) duplicates.get(unwindPath);
ValueNode snippetExceptionValue = snippetUnwindDuplicate.exception();
FixedWithNextNode snippetUnwindPath = (FixedWithNextNode) snippetUnwindDuplicate.predecessor();
GraalError.guarantee(!(snippetExceptionValue instanceof ExceptionObjectNode) || snippetUnwindPath == snippetExceptionValue, "Snippet unwind predecessor must be the exception object %s: %s", snippetUnwindPath, snippetExceptionValue);
GraalError.guarantee(!(snippetUnwindPath instanceof MergeNode) || snippetExceptionValue instanceof PhiNode, "If the snippet unwind predecessor is a merge node, the exception object must be a phi %s: %s", snippetUnwindPath, snippetExceptionValue);
// replacee exception handler
WithExceptionNode replaceeWithExceptionNode = (WithExceptionNode) replacee;
AbstractBeginNode exceptionEdge = replaceeWithExceptionNode.exceptionEdge();
if (exceptionEdge instanceof ExceptionObjectNode) {
/*
* The exception object node is a begin node, i.e., it can be used as an anchor
* for other nodes, thus we need to re-route them to a valid anchor, i.e. the
* begin node of the unwind block.
*/
GraalError.guarantee(exceptionEdge.usages().filter(x -> x instanceof GuardedNode && ((GuardedNode) x).getGuard() == exceptionEdge).count() == 0, "Must not have guards attached to exception object node %s", exceptionEdge);
replaceeWithExceptionNode.setExceptionEdge(null);
// replace the old exception object with the one
exceptionEdge.replaceAtUsages(snippetExceptionValue);
GraalError.guarantee(originalWithExceptionNextNode != null, "Need to have next node to link placeholder to: %s", replacee);
// replace exceptionEdge with snippetUnwindPath
replaceExceptionObjectNode(exceptionEdge, snippetUnwindPath);
GraphUtil.killCFG(snippetUnwindDuplicate);
} else {
GraalError.guarantee(exceptionEdge instanceof UnreachableBeginNode, "Unexpected exception edge: %s", exceptionEdge);
markExceptionsUnreachable(unwindPath.exception(), duplicates);
}
} else {
/*
* Since the snippet unwindPath is null or has been deleted, a placeholder
* WithExceptionNode needs to be added for any WithExceptionNode replacee. This
* placeholder WithExceptionNode temporarily preserves the replacee's original
* exception edge and is needed because lowering should not remove edges from the
* original CFG.
*/
if (replacee instanceof WithExceptionNode) {
GraalError.guarantee(originalWithExceptionNextNode != null, "Need to have next node to link placeholder to: %s", replacee);
WithExceptionNode newExceptionNode = replacee.graph().add(new PlaceholderWithExceptionNode());
/*
* First attaching placeholder as predecessor of original WithExceptionNode next
* edge.
*/
((FixedWithNextNode) originalWithExceptionNextNode.predecessor()).setNext(newExceptionNode);
newExceptionNode.setNext(originalWithExceptionNextNode);
/* Now connecting exception edge. */
WithExceptionNode oldExceptionNode = (WithExceptionNode) replacee;
AbstractBeginNode exceptionEdge = oldExceptionNode.exceptionEdge();
oldExceptionNode.setExceptionEdge(null);
newExceptionNode.setExceptionEdge(exceptionEdge);
}
}
if (artificialReturnCondition != null) {
((PlaceholderLogicNode) duplicates.get(artificialReturnCondition)).markForDeletion();
}
if (fallbackInvoke != null) {
GraalError.guarantee(replacee instanceof MacroWithExceptionNode, "%s can only be used in snippets replacing %s", FallbackInvokeWithExceptionNode.class.getSimpleName(), MacroWithExceptionNode.class.getSimpleName());
WithExceptionNode fallbackInvokeNode = (WithExceptionNode) duplicates.get(fallbackInvoke);
MacroWithExceptionNode macroNode = (MacroWithExceptionNode) replacee;
// create fallback invoke
InvokeWithExceptionNode invoke = macroNode.createInvoke(returnValue);
// replace placeholder
replaceeGraph.replaceWithExceptionSplit(fallbackInvokeNode, invoke);
// register the invoke as the replacement for the fallback invoke
duplicates.put(fallbackInvoke, invoke);
}
if (killReplacee) {
// Remove the replacee from its graph
GraphUtil.killCFG(replacee);
}
debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this);
return duplicates;
}
}
use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class IntrinsicGraphBuilder method updateLastInstruction.
private <T extends ValueNode> void updateLastInstruction(T v) {
if (v instanceof FixedNode) {
FixedNode fixedNode = (FixedNode) v;
if (lastInstr != null) {
lastInstr.setNext(fixedNode);
}
if (fixedNode instanceof FixedWithNextNode) {
FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
lastInstr = fixedWithNextNode;
} else if (fixedNode instanceof WithExceptionNode) {
WithExceptionNode withExceptionNode = (WithExceptionNode) fixedNode;
AbstractBeginNode normalSuccessor = graph.add(new BeginNode());
ExceptionObjectNode exceptionSuccessor = graph.add(new ExceptionObjectNode(getMetaAccess()));
setExceptionState(exceptionSuccessor);
exceptionSuccessor.setNext(graph.add(new UnwindNode(exceptionSuccessor)));
withExceptionNode.setNext(normalSuccessor);
withExceptionNode.setExceptionEdge(exceptionSuccessor);
lastInstr = normalSuccessor;
} else {
lastInstr = null;
}
}
}
Aggregations