/**
   * 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);
    }
  }