use of org.graalvm.compiler.nodes.AbstractBeginNode in project graal by oracle.
the class LoopUnswitchingPhase method logUnswitch.
private static void logUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
StringBuilder sb = new StringBuilder("Unswitching ");
sb.append(loop).append(" at ");
for (ControlSplitNode controlSplit : controlSplits) {
sb.append(controlSplit).append(" [");
Iterator<Node> it = controlSplit.successors().iterator();
while (it.hasNext()) {
sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
if (it.hasNext()) {
sb.append(", ");
}
}
sb.append("]");
}
loop.entryPoint().getDebug().log("%s", sb);
}
use of org.graalvm.compiler.nodes.AbstractBeginNode in project graal by oracle.
the class UseTrappingNullChecksPhase method checkPredecessor.
private static void checkPredecessor(AbstractDeoptimizeNode deopt, Node predecessor, DeoptimizationReason deoptimizationReason, long implicitNullCheckLimit) {
Node current = predecessor;
AbstractBeginNode branch = null;
while (current instanceof AbstractBeginNode) {
branch = (AbstractBeginNode) current;
if (branch.anchored().isNotEmpty()) {
// some input of the deopt framestate is anchored to this branch
return;
}
current = current.predecessor();
}
if (current instanceof IfNode) {
IfNode ifNode = (IfNode) current;
if (branch != ifNode.trueSuccessor()) {
return;
}
LogicNode condition = ifNode.condition();
if (condition instanceof IsNullNode) {
replaceWithTrappingNullCheck(deopt, ifNode, condition, deoptimizationReason, implicitNullCheckLimit);
}
}
}
use of org.graalvm.compiler.nodes.AbstractBeginNode in project graal by oracle.
the class UseTrappingNullChecksPhase method replaceWithTrappingNullCheck.
private static void replaceWithTrappingNullCheck(AbstractDeoptimizeNode deopt, IfNode ifNode, LogicNode condition, DeoptimizationReason deoptimizationReason, long implicitNullCheckLimit) {
DebugContext debug = deopt.getDebug();
counterTrappingNullCheck.increment(debug);
if (deopt instanceof DynamicDeoptimizeNode) {
counterTrappingNullCheckDynamicDeoptimize.increment(debug);
}
if (deoptimizationReason == DeoptimizationReason.UnreachedCode) {
counterTrappingNullCheckUnreached.increment(debug);
}
IsNullNode isNullNode = (IsNullNode) condition;
AbstractBeginNode nonTrappingContinuation = ifNode.falseSuccessor();
AbstractBeginNode trappingContinuation = ifNode.trueSuccessor();
DeoptimizingFixedWithNextNode trappingNullCheck = null;
FixedNode nextNonTrapping = nonTrappingContinuation.next();
ValueNode value = isNullNode.getValue();
if (OptImplicitNullChecks.getValue(ifNode.graph().getOptions()) && implicitNullCheckLimit > 0) {
if (nextNonTrapping instanceof FixedAccessNode) {
FixedAccessNode fixedAccessNode = (FixedAccessNode) nextNonTrapping;
if (fixedAccessNode.canNullCheck()) {
AddressNode address = fixedAccessNode.getAddress();
ValueNode base = address.getBase();
ValueNode index = address.getIndex();
// intervening uncompress out of the address chain
if (base != null && base instanceof CompressionNode) {
base = ((CompressionNode) base).getValue();
}
if (index != null && index instanceof CompressionNode) {
index = ((CompressionNode) index).getValue();
}
if (((base == value && index == null) || (base == null && index == value)) && address.getMaxConstantDisplacement() < implicitNullCheckLimit) {
// Opportunity for implicit null check as part of an existing read found!
fixedAccessNode.setStateBefore(deopt.stateBefore());
fixedAccessNode.setNullCheck(true);
deopt.graph().removeSplit(ifNode, nonTrappingContinuation);
trappingNullCheck = fixedAccessNode;
counterTrappingNullCheckExistingRead.increment(debug);
}
}
}
}
if (trappingNullCheck == null) {
// Need to add a null check node.
trappingNullCheck = deopt.graph().add(new NullCheckNode(value));
deopt.graph().replaceSplit(ifNode, trappingNullCheck, nonTrappingContinuation);
}
trappingNullCheck.setStateBefore(deopt.stateBefore());
/*
* We now have the pattern NullCheck/BeginNode/... It's possible some node is using the
* BeginNode as a guard input, so replace guard users of the Begin with the NullCheck and
* then remove the Begin from the graph.
*/
nonTrappingContinuation.replaceAtUsages(InputType.Guard, trappingNullCheck);
if (nonTrappingContinuation instanceof BeginNode) {
GraphUtil.unlinkFixedNode(nonTrappingContinuation);
nonTrappingContinuation.safeDelete();
}
GraphUtil.killCFG(trappingContinuation);
GraphUtil.tryKillUnused(isNullNode);
}
use of org.graalvm.compiler.nodes.AbstractBeginNode in project graal by oracle.
the class InliningUtil method inline.
/**
* Performs an actual inlining, thereby replacing the given invoke with the given
* {@code inlineGraph}.
*
* @param invoke the invoke that will be replaced
* @param inlineGraph the graph that the invoke will be replaced with
* @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
* false if no such check is required
* @param inlineeMethod the actual method being inlined. Maybe be null for snippets.
* @param reason the reason for inlining, used in tracing
* @param phase the phase that invoked inlining
*/
@SuppressWarnings("try")
public static UnmodifiableEconomicMap<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, String reason, String phase) {
FixedNode invokeNode = invoke.asNode();
StructuredGraph graph = invokeNode.graph();
final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
nonNullReceiver(invoke);
}
ArrayList<Node> nodes = new ArrayList<>(inlineGraph.getNodes().count());
ArrayList<ReturnNode> returnNodes = new ArrayList<>(4);
ArrayList<Invoke> partialIntrinsicExits = new ArrayList<>();
UnwindNode unwindNode = null;
final StartNode entryPointNode = inlineGraph.start();
FixedNode firstCFGNode = entryPointNode.next();
if (firstCFGNode == null) {
throw new IllegalStateException("Inlined graph is in invalid state: " + inlineGraph);
}
for (Node node : inlineGraph.getNodes()) {
if (node == entryPointNode || (node == entryPointNode.stateAfter() && node.usages().count() == 1) || node instanceof ParameterNode) {
// Do nothing.
} else {
nodes.add(node);
if (node instanceof ReturnNode) {
returnNodes.add((ReturnNode) node);
} else if (node instanceof Invoke) {
Invoke invokeInInlineGraph = (Invoke) node;
if (invokeInInlineGraph.bci() == BytecodeFrame.UNKNOWN_BCI) {
ResolvedJavaMethod target1 = inlineeMethod;
ResolvedJavaMethod target2 = invokeInInlineGraph.callTarget().targetMethod();
assert target1.equals(target2) : String.format("invoke in inlined method expected to be partial intrinsic exit (i.e., call to %s), not a call to %s", target1.format("%H.%n(%p)"), target2.format("%H.%n(%p)"));
partialIntrinsicExits.add(invokeInInlineGraph);
}
} else if (node instanceof UnwindNode) {
assert unwindNode == null;
unwindNode = (UnwindNode) node;
}
}
}
final AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(invokeNode);
DuplicationReplacement localReplacement = new DuplicationReplacement() {
@Override
public Node replacement(Node node) {
if (node instanceof ParameterNode) {
return parameters.get(((ParameterNode) node).index());
} else if (node == entryPointNode) {
return prevBegin;
}
return node;
}
};
assert invokeNode.successors().first() != null : invoke;
assert invokeNode.predecessor() != null;
Mark mark = graph.getMark();
// Instead, attach the inlining log of the child graph to the current inlining log.
EconomicMap<Node, Node> duplicates;
try (InliningLog.UpdateScope scope = graph.getInliningLog().openDefaultUpdateScope()) {
duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
if (scope != null) {
graph.getInliningLog().addDecision(invoke, true, reason, phase, duplicates, inlineGraph.getInliningLog());
}
}
FrameState stateAfter = invoke.stateAfter();
assert stateAfter == null || stateAfter.isAlive();
FrameState stateAtExceptionEdge = null;
if (invoke instanceof InvokeWithExceptionNode) {
InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
if (unwindNode != null) {
ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
stateAtExceptionEdge = obj.stateAfter();
}
}
updateSourcePositions(invoke, inlineGraph, duplicates, !Objects.equals(inlineGraph.method(), inlineeMethod), mark);
if (stateAfter != null) {
processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1);
int callerLockDepth = stateAfter.nestedLockDepth();
if (callerLockDepth != 0) {
for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.TYPE)) {
MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
processMonitorId(invoke.stateAfter(), monitor);
}
}
} else {
assert checkContainsOnlyInvalidOrAfterFrameState(duplicates);
}
firstCFGNode = (FixedNode) duplicates.get(firstCFGNode);
for (int i = 0; i < returnNodes.size(); i++) {
returnNodes.set(i, (ReturnNode) duplicates.get(returnNodes.get(i)));
}
for (Invoke exit : partialIntrinsicExits) {
// A partial intrinsic exit must be replaced with a call to
// the intrinsified method.
Invoke dup = (Invoke) duplicates.get(exit.asNode());
if (dup instanceof InvokeNode) {
InvokeNode repl = graph.add(new InvokeNode(invoke.callTarget(), invoke.bci()));
dup.intrinsify(repl.asNode());
} else {
((InvokeWithExceptionNode) dup).replaceWithNewBci(invoke.bci());
}
}
if (unwindNode != null) {
unwindNode = (UnwindNode) duplicates.get(unwindNode);
}
finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph);
GraphUtil.killCFG(invokeNode);
return duplicates;
}
use of org.graalvm.compiler.nodes.AbstractBeginNode in project graal by oracle.
the class InliningUtil method handleMissingAfterExceptionFrameState.
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.asNode();
if (fixedStateSplit instanceof AbstractMergeNode) {
AbstractMergeNode merge = (AbstractMergeNode) fixedStateSplit;
while (merge.isAlive()) {
AbstractEndNode end = merge.forwardEnds().first();
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
// InvokeWithExceptionNode for the partial intrinsic exit. We therefore
// replace the InvokeWithExceptionNode with a normal
// InvokeNode -- the deoptimization occurs when the invoke throws.
InvokeWithExceptionNode oldInvoke = (InvokeWithExceptionNode) fixedStateSplit.predecessor();
FrameState oldFrameState = oldInvoke.stateAfter();
InvokeNode newInvoke = oldInvoke.replaceWithInvoke();
newInvoke.setStateAfter(oldFrameState.duplicate());
if (replacements != null) {
replacements.put(oldInvoke, newInvoke);
}
handleAfterBciFrameState(newInvoke.stateAfter(), invoke, alwaysDuplicateStateAfter);
} else {
FixedNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
if (fixedStateSplit instanceof AbstractBeginNode) {
deoptimizeNode = BeginNode.begin(deoptimizeNode);
}
fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
GraphUtil.killCFG(fixedStateSplit);
}
}
}
}
return nonReplaceableFrameState;
}
Aggregations