/** * In case the scrutinee: * * <ul> * <li>is known to be null, an unconditional deopt is added. * <li>is known to be non-null, the NullCheckNode is removed. * <li>otherwise, the NullCheckNode is lowered to a FixedGuardNode which then allows using it as * anchor for state-tracking. * </ul> * * <p>Precondition: the input (ie, object) hasn't been deverbosified yet. */ private void visitNullCheckNode(NullCheckNode ncn) { ValueNode object = ncn.getObject(); if (state.isNull(object)) { postponedDeopts.addDeoptBefore(ncn, NullCheckException); state.impossiblePath(); return; } if (state.isNonNull(object)) { /* * Redundant NullCheckNode. Unlike GuardingPiNode or FixedGuardNode, NullCheckNode-s * aren't used as GuardingNode-s, thus in this case can be removed without further ado. */ assert FlowUtil.lacksUsages(ncn); graph.removeFixed(ncn); return; } /* * Lower the NullCheckNode to a FixedGuardNode which then allows using it as anchor for * state-tracking. TODO the assumption here is that the code emitted for the resulting * FixedGuardNode is as efficient as for NullCheckNode. */ IsNullNode isNN = graph.unique(IsNullNode.create(object)); reasoner.added.add(isNN); FixedGuardNode nullCheck = graph.add(FixedGuardNode.create(isNN, UnreachedCode, InvalidateReprofile, true)); graph.replaceFixedWithFixed(ncn, nullCheck); state.trackNN(object, nullCheck); }
private void processFixedGuardAndMerge( FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi, AbstractMergeNode merge) { List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot(); for (int i = 0; i < mergePredecessors.size(); ++i) { AbstractEndNode mergePredecessor = mergePredecessors.get(i); if (!mergePredecessor.isAlive()) { break; } Constant xs; if (xPhi == null) { xs = x.asConstant(); } else { xs = xPhi.valueAt(mergePredecessor).asConstant(); } Constant ys; if (yPhi == null) { ys = y.asConstant(); } else { ys = yPhi.valueAt(mergePredecessor).asConstant(); } if (xs != null && ys != null && compare .condition() .foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) { visitDeoptBegin( AbstractBeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), fixedGuard.getSpeculation(), fixedGuard.graph()); } } }
@Override public GuardingNode createGuard( FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated) { if (OptEliminateGuards.getValue()) { for (Node usage : condition.usages()) { if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage) && ((GuardNode) usage).isNegated() == negated) { return (GuardNode) usage; } } } StructuredGraph graph = before.graph(); if (!condition.graph().getGuardsStage().allowsFloatingGuards()) { FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, deoptReason, action, speculation, negated)); graph.addBeforeFixed(before, fixedGuard); DummyGuardHandle handle = graph.add(new DummyGuardHandle(fixedGuard)); fixedGuard.lower(this); GuardingNode result = handle.getGuard(); handle.safeDelete(); return result; } else { GuardNode newGuard = graph.unique( new GuardNode(condition, guardAnchor, deoptReason, action, negated, speculation)); if (OptEliminateGuards.getValue()) { activeGuards.markAndGrow(newGuard); } return newGuard; } }
private void trySplitFixedGuard(FixedGuardNode fixedGuard, PhaseContext context) { LogicNode condition = fixedGuard.condition(); if (condition instanceof CompareNode) { CompareNode compare = (CompareNode) condition; ValueNode x = compare.getX(); ValuePhiNode xPhi = (x instanceof ValuePhiNode) ? (ValuePhiNode) x : null; if (x instanceof ConstantNode || xPhi != null) { ValueNode y = compare.getY(); ValuePhiNode yPhi = (y instanceof ValuePhiNode) ? (ValuePhiNode) y : null; if (y instanceof ConstantNode || yPhi != null) { processFixedGuardAndPhis(fixedGuard, context, compare, x, xPhi, y, yPhi); } } } }
private void visitDeoptBegin( AbstractBeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, JavaConstant speculation, StructuredGraph graph) { if (deoptBegin.predecessor() instanceof AbstractBeginNode) { /* Walk up chains of LoopExitNodes to the "real" BeginNode that leads to deoptimization. */ visitDeoptBegin( (AbstractBeginNode) deoptBegin.predecessor(), deoptAction, deoptReason, speculation, graph); return; } if (deoptBegin instanceof AbstractMergeNode) { AbstractMergeNode mergeNode = (AbstractMergeNode) deoptBegin; Debug.log("Visiting %s", mergeNode); FixedNode next = mergeNode.next(); while (mergeNode.isAlive()) { AbstractEndNode end = mergeNode.forwardEnds().first(); AbstractBeginNode newBeginNode = findBeginNode(end); visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph); } assert next.isAlive(); AbstractBeginNode newBeginNode = findBeginNode(next); visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph); return; } else if (deoptBegin.predecessor() instanceof IfNode) { IfNode ifNode = (IfNode) deoptBegin.predecessor(); AbstractBeginNode otherBegin = ifNode.trueSuccessor(); LogicNode conditionNode = ifNode.condition(); FixedGuardNode guard = graph.add( new FixedGuardNode( conditionNode, deoptReason, deoptAction, speculation, deoptBegin == ifNode.trueSuccessor())); FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); AbstractBeginNode survivingSuccessor; if (deoptBegin == ifNode.trueSuccessor()) { survivingSuccessor = ifNode.falseSuccessor(); } else { survivingSuccessor = ifNode.trueSuccessor(); } graph.removeSplitPropagate(ifNode, survivingSuccessor); Node newGuard = guard; if (survivingSuccessor instanceof LoopExitNode) { newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph); } survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard); Debug.log( "Converting deopt on %-5s branch of %s to guard for remaining branch %s.", deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin); FixedNode next = pred.next(); pred.setNext(guard); guard.setNext(next); survivingSuccessor.simplify(simplifierTool); return; } // We could not convert the control split - at least cut off control flow after the split. FixedWithNextNode deoptPred = deoptBegin; FixedNode next = deoptPred.next(); if (!(next instanceof DeoptimizeNode)) { DeoptimizeNode newDeoptNode = graph.add(new DeoptimizeNode(deoptAction, deoptReason, speculation)); deoptPred.setNext(newDeoptNode); assert deoptPred == newDeoptNode.predecessor(); GraphUtil.killCFG(next); } }