use of org.graalvm.compiler.nodes.DynamicDeoptimizeNode in project graal by oracle.
the class DeoptimizationGroupingPhase method run.
@Override
protected void run(StructuredGraph graph, MidTierContext context) {
ControlFlowGraph cfg = null;
for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
FixedNode target = null;
PhiNode reasonActionPhi = null;
PhiNode speculationPhi = null;
List<AbstractDeoptimizeNode> obsoletes = null;
for (AbstractDeoptimizeNode deopt : fs.usages().filter(AbstractDeoptimizeNode.class)) {
if (target == null) {
target = deopt;
} else {
if (cfg == null) {
cfg = ControlFlowGraph.compute(graph, true, true, false, false);
}
AbstractMergeNode merge;
if (target instanceof AbstractDeoptimizeNode) {
merge = graph.add(new MergeNode());
EndNode firstEnd = graph.add(new EndNode());
ValueNode actionAndReason = ((AbstractDeoptimizeNode) target).getActionAndReason(context.getMetaAccess());
ValueNode speculation = ((AbstractDeoptimizeNode) target).getSpeculation(context.getMetaAccess());
reasonActionPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(actionAndReason.getStackKind()), merge));
speculationPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(speculation.getStackKind()), merge));
merge.addForwardEnd(firstEnd);
reasonActionPhi.addInput(actionAndReason);
speculationPhi.addInput(speculation);
target.replaceAtPredecessor(firstEnd);
exitLoops((AbstractDeoptimizeNode) target, firstEnd, cfg);
merge.setNext(graph.add(new DynamicDeoptimizeNode(reasonActionPhi, speculationPhi)));
obsoletes = new LinkedList<>();
obsoletes.add((AbstractDeoptimizeNode) target);
target = merge;
} else {
merge = (AbstractMergeNode) target;
}
EndNode newEnd = graph.add(new EndNode());
merge.addForwardEnd(newEnd);
reasonActionPhi.addInput(deopt.getActionAndReason(context.getMetaAccess()));
speculationPhi.addInput(deopt.getSpeculation(context.getMetaAccess()));
deopt.replaceAtPredecessor(newEnd);
exitLoops(deopt, newEnd, cfg);
obsoletes.add(deopt);
}
}
if (obsoletes != null) {
((DynamicDeoptimizeNode) ((AbstractMergeNode) target).next()).setStateBefore(fs);
for (AbstractDeoptimizeNode obsolete : obsoletes) {
obsolete.safeDelete();
}
}
}
}
use of org.graalvm.compiler.nodes.DynamicDeoptimizeNode in project graal by oracle.
the class UseTrappingNullChecksPhase method tryUseTrappingNullCheck.
private static void tryUseTrappingNullCheck(MetaAccessProvider metaAccessProvider, DynamicDeoptimizeNode deopt, long implicitNullCheckLimit) {
Node predecessor = deopt.predecessor();
if (predecessor instanceof AbstractMergeNode) {
AbstractMergeNode merge = (AbstractMergeNode) predecessor;
// Process each predecessor at the merge, unpacking the reasons and speculations as
// needed.
ValueNode reason = deopt.getActionAndReason();
ValuePhiNode reasonPhi = null;
List<ValueNode> reasons = null;
int expectedPhis = 0;
if (reason instanceof ValuePhiNode) {
reasonPhi = (ValuePhiNode) reason;
if (reasonPhi.merge() != merge) {
return;
}
reasons = reasonPhi.values().snapshot();
expectedPhis++;
} else if (!reason.isConstant()) {
return;
}
ValueNode speculation = deopt.getSpeculation();
ValuePhiNode speculationPhi = null;
List<ValueNode> speculations = null;
if (speculation instanceof ValuePhiNode) {
speculationPhi = (ValuePhiNode) speculation;
if (speculationPhi.merge() != merge) {
return;
}
speculations = speculationPhi.values().snapshot();
expectedPhis++;
}
if (merge.phis().count() != expectedPhis) {
return;
}
int index = 0;
for (AbstractEndNode end : merge.cfgPredecessors().snapshot()) {
ValueNode thisReason = reasons != null ? reasons.get(index) : reason;
ValueNode thisSpeculation = speculations != null ? speculations.get(index++) : speculation;
if (!thisReason.isConstant() || !thisSpeculation.isConstant() || !thisSpeculation.asConstant().equals(JavaConstant.NULL_POINTER)) {
continue;
}
DeoptimizationReason deoptimizationReason = metaAccessProvider.decodeDeoptReason(thisReason.asJavaConstant());
tryUseTrappingNullCheck(deopt, end.predecessor(), deoptimizationReason, null, implicitNullCheckLimit);
}
}
}
use of org.graalvm.compiler.nodes.DynamicDeoptimizeNode 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);
}
Aggregations