use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class OptimizeExceptionPathsPhase method walkBack.
private static void walkBack(ControlSinkNode sink, NodeBitMap exceptionPaths) {
Deque<Node> worklist = new ArrayDeque<>();
worklist.push(sink);
while (!worklist.isEmpty()) {
Node node = worklist.pop();
Node predecessor = node.predecessor();
/* Second loop to avoid the worklist while walking back within a block. */
while (predecessor != null) {
if ((predecessor instanceof IfNode || predecessor instanceof SwitchNode) && node instanceof AbstractBeginNode) {
boolean allSuccessorsInExceptionPaths = true;
for (Node sux : predecessor.successors()) {
if (sux != node && !exceptionPaths.contains(sux)) {
allSuccessorsInExceptionPaths = false;
break;
}
}
if (allSuccessorsInExceptionPaths) {
/*
* All successors of the control split go to an exception path, so keep
* walking backward.
*/
for (Node sux : predecessor.successors()) {
exceptionPaths.clear(sux);
}
} else {
exceptionPaths.mark(node);
break;
}
} else if (predecessor instanceof MergeNode) {
for (ValueNode endNode : ((MergeNode) predecessor).cfgPredecessors()) {
worklist.push(endNode);
}
break;
} else if (predecessor instanceof WithExceptionNode && node instanceof AbstractBeginNode) {
if (node == ((WithExceptionNode) predecessor).exceptionEdge()) {
/*
* We are at the exception edge of the WithExceptionNode. It has the correct
* probability, so nothing to do.
*/
break;
} else {
/*
* We are at the regular successor edge of the WithExceptionNode, keep
* walking back.
*/
}
} else if (predecessor instanceof AbstractMergeNode || predecessor instanceof ControlSplitNode) {
/* Any other split or merge is suspicious: we abort. */
break;
}
node = predecessor;
predecessor = node.predecessor();
}
}
}
use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class RemoveUnwindPhase method run.
@Override
protected void run(StructuredGraph graph) {
SharedMethod method = (SharedMethod) graph.method();
if (method.isDeoptTarget()) {
/*
* Deoptimization targets need need to have an exception entry point for every invoke.
* This decouples deoptimization from exception handling: the exception handling
* mechanism can just deliver an exception to a deoptimized method without any checks.
*/
return;
}
List<WithExceptionNode> withExceptionNodes = new ArrayList<>();
List<BytecodeExceptionNode> bytecodeExceptionNodes = new ArrayList<>();
for (UnwindNode node : graph.getNodes(UnwindNode.TYPE)) {
walkBack(node.predecessor(), node, withExceptionNodes, bytecodeExceptionNodes, GraphUtil.unproxify(node.exception()), graph);
}
/*
* Modify graph only after all suitable nodes with exceptions are found, to avoid problems
* with deleted nodes during graph traversal.
*/
for (WithExceptionNode node : withExceptionNodes) {
if (node.isAlive()) {
graph.getDebug().log(DebugContext.DETAILED_LEVEL, "Removing exception edge for: %s", node);
node.replaceWithNonThrowing();
}
}
for (BytecodeExceptionNode bytecodeExceptionNode : bytecodeExceptionNodes) {
if (bytecodeExceptionNode.isAlive()) {
graph.getDebug().log(DebugContext.DETAILED_LEVEL, "Converting a BytecodeException node to a ThrowBytecodeException node for: %s", bytecodeExceptionNode);
convertToThrow(bytecodeExceptionNode);
}
}
}
use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class RemoveUnwindPhase method walkBack.
/**
* We walk back from the {@link UnwindNode} to a {@link WithExceptionNode}. If the control flow
* path only contains nodes white-listed in this method, then we know that we have a node that
* just forwards the exception to the {@link UnwindNode}. Such nodes are rewritten to a variant
* without an exception edge, i.e., no exception handler entry is created for such invokes.
*/
protected static void walkBack(Node n, Node successor, List<WithExceptionNode> withExceptionNodes, List<BytecodeExceptionNode> bytecodeExceptionNodes, ValueNode expectedExceptionNode, StructuredGraph graph) {
if (n instanceof WithExceptionNode) {
WithExceptionNode node = (WithExceptionNode) n;
if (node.exceptionEdge() == successor) {
withExceptionNodes.add(node);
}
} else if (n instanceof BytecodeExceptionNode || n instanceof ExceptionObjectNode) {
if (n == expectedExceptionNode) {
if (n instanceof BytecodeExceptionNode) {
BytecodeExceptionNode node = (BytecodeExceptionNode) n;
bytecodeExceptionNodes.add(node);
} else {
walkBack(n.predecessor(), n, withExceptionNodes, bytecodeExceptionNodes, expectedExceptionNode, graph);
}
} else {
graph.getDebug().log(DebugContext.VERY_DETAILED_LEVEL, "Node %s does not flow to the corresponding Unwind. Bailing out.", n);
}
} else if (n instanceof MergeNode) {
MergeNode merge = (MergeNode) n;
if (merge.isPhiAtMerge(expectedExceptionNode)) {
/* Propagate expected exception on each control path leading to the merge */
PhiNode expectedExceptionForInput = (PhiNode) expectedExceptionNode;
for (int input = 0; input < merge.forwardEndCount(); input++) {
Node predecessor = merge.forwardEndAt(input);
walkBack(predecessor, merge, withExceptionNodes, bytecodeExceptionNodes, GraphUtil.unproxify(expectedExceptionForInput.valueAt(input)), graph);
}
} else {
for (ValueNode predecessor : merge.cfgPredecessors()) {
walkBack(predecessor, merge, withExceptionNodes, bytecodeExceptionNodes, expectedExceptionNode, graph);
}
}
} else if (n instanceof AbstractBeginNode || n instanceof AbstractEndNode) {
walkBack(n.predecessor(), n, withExceptionNodes, bytecodeExceptionNodes, expectedExceptionNode, graph);
}
}
use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class SubstrateGraphKit method appendWithUnwind.
/**
* Appends the provided node to the control flow graph. The exception edge is connected to an
* {@link UnwindNode}, i.e., the exception is not handled in this method.
*/
protected <T extends WithExceptionNode> T appendWithUnwind(T withExceptionNode, int bci) {
WithExceptionNode appended = append(withExceptionNode);
assert appended == withExceptionNode;
if (withExceptionNode instanceof StateSplit) {
StateSplit stateSplit = (StateSplit) withExceptionNode;
stateSplit.setStateAfter(frameState.create(bci, stateSplit));
}
AbstractBeginNode noExceptionEdge = add(new BeginNode());
withExceptionNode.setNext(noExceptionEdge);
ExceptionObjectNode exceptionEdge = createExceptionObjectNode(frameState, bci);
withExceptionNode.setExceptionEdge(exceptionEdge);
assert lastFixedNode == null;
lastFixedNode = exceptionEdge;
append(new UnwindNode(exceptionEdge));
assert lastFixedNode == null;
lastFixedNode = noExceptionEdge;
return withExceptionNode;
}
use of org.graalvm.compiler.nodes.WithExceptionNode in project graal by oracle.
the class EffectsClosure method processBlock.
@Override
protected BlockT processBlock(Block block, BlockT state) {
if (!state.isDead()) {
GraphEffectList effects = blockEffects.get(block);
/*
* If we enter an if branch that is known to be unreachable, we mark it as dead and
* cease to do any more analysis on it. At merges, these dead branches will be ignored.
*/
if (block.getBeginNode().predecessor() instanceof IfNode) {
IfNode ifNode = (IfNode) block.getBeginNode().predecessor();
LogicNode condition = ifNode.condition();
Node alias = getScalarAlias(condition);
if (alias instanceof LogicConstantNode) {
LogicConstantNode constant = (LogicConstantNode) alias;
boolean isTrueSuccessor = block.getBeginNode() == ifNode.trueSuccessor();
if (constant.getValue() != isTrueSuccessor) {
state.markAsDead();
effects.killIfBranch(ifNode, constant.getValue());
return state;
}
}
}
OptionValues options = block.getBeginNode().getOptions();
VirtualUtil.trace(options, debug, "\nBlock: %s, preds: %s, succ: %s (", block, block.getPredecessors(), block.getSuccessors());
// a lastFixedNode is needed in case we want to insert fixed nodes
FixedWithNextNode lastFixedNode = null;
Iterable<? extends Node> nodes = schedule != null ? schedule.getBlockToNodesMap().get(block) : block.getNodes();
for (Node node : nodes) {
// reset the aliases (may be non-null due to iterative loop processing)
aliases.set(node, null);
if (node instanceof LoopExitNode) {
LoopExitNode loopExit = (LoopExitNode) node;
for (ProxyNode proxy : loopExit.proxies()) {
aliases.set(proxy, null);
changed |= processNode(proxy, state, effects, lastFixedNode) && isSignificantNode(node);
}
processLoopExit(loopExit, loopEntryStates.get(loopExit.loopBegin()), state, blockEffects.get(block));
}
Block exceptionEdgeToKill = node instanceof WithExceptionNode ? cfg.blockFor(((WithExceptionNode) node).exceptionEdge()) : null;
boolean lastNodeChanged = processNode(node, state, effects, lastFixedNode) && isSignificantNode(node);
changed |= lastNodeChanged;
if (lastNodeChanged && exceptionEdgeToKill != null) {
/*
* We deleted a exception node, per definition the exception edge died in that
* process, no need to process the exception edge
*/
if (state.exceptionEdgesToKill == null) {
state.exceptionEdgesToKill = EconomicSet.create();
}
state.exceptionEdgesToKill.add(exceptionEdgeToKill);
}
if (node instanceof FixedWithNextNode) {
lastFixedNode = (FixedWithNextNode) node;
}
if (state.isDead()) {
break;
}
}
VirtualUtil.trace(options, debug, ")\n end state: %s\n", state);
}
return state;
}
Aggregations