Example #1
0
 public static void killCFG(FixedNode node) {
   assert node.isAlive();
   if (node instanceof AbstractEndNode) {
     // We reached a control flow end.
     AbstractEndNode end = (AbstractEndNode) node;
     killEnd(end);
   } else {
     // Normal control flow node.
     /*
      * We do not take a successor snapshot because this iterator supports concurrent
      * modifications as long as they do not change the size of the successor list. Not
      * taking a snapshot allows us to see modifications to other branches that may happen
      * while processing one branch.
      */
     for (Node successor : node.successors()) {
       killCFG((FixedNode) successor);
     }
   }
   propagateKill(node);
 }
Example #2
0
 @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;
   }
 }
Example #3
0
  /**
   * Precondition: This method assumes that either:
   *
   * <ul>
   *   <li>the state has already stabilized (ie no more pending iterations in the "iterative"
   *       dataflow algorithm); or
   *   <li>any rewritings made based on the state in its current form are conservative enough to be
   *       safe.
   * </ul>
   *
   * <p>The overarching goal is to perform just enough rewriting to trigger other phases ( {@link
   * com.oracle.graal.graph.spi.SimplifierTool SimplifierTool}, {@link
   * com.oracle.graal.phases.common.DeadCodeEliminationPhase DeadCodeEliminationPhase}, etc) to
   * perform the bulk of rewriting, thus lowering the maintenance burden.
   */
  @Override
  protected void node(FixedNode node) {

    assert node.isAlive();

    /*-------------------------------------------------------------------------------------
     * Step 1: Unreachable paths are still visited (PostOrderNodeIterator requires all ends
     * of a merge to have been visited), but time is saved by neither updating the state nor
     * rewriting anything while on an an unreachable path.
     *-------------------------------------------------------------------------------------
     */
    if (state.isUnreachable) {
      return;
    }

    /*-------------------------------------------------------------------------------------
     * Step 2: For an AbstractBeginNode, determine whether this path is reachable, register
     * any associated guards.
     *-------------------------------------------------------------------------------------
     */
    if (node instanceof BeginNode) {
      BeginNode begin = (BeginNode) node;
      Node pred = node.predecessor();

      if (pred != null) {
        registerControlSplit(pred, begin);
      }
      return;
    }

    /*-------------------------------------------------------------------------------------
     * Step 3: Check whether EquationalReasoner caches should be cleared upon state updates.
     *-------------------------------------------------------------------------------------
     */
    reasoner.updateState(state);

    /*-------------------------------------------------------------------------------------
     * Step 4: Whatever special-case handling makes sense for the FixedNode at hand before
     * its inputs are reduced.
     *-------------------------------------------------------------------------------------
     */

    if (node instanceof AbstractEndNode) {
      visitAbstractEndNode((AbstractEndNode) node);
      return;
    } else if (node instanceof Invoke) {
      visitInvoke((Invoke) node);
      return;
    } else if (node instanceof CheckCastNode) {
      // it's important not to call deverbosification for visitCheckCastNode()
      visitCheckCastNode((CheckCastNode) node);
      return;
    } else if (node instanceof GuardingPiNode) {
      visitGuardingPiNode((GuardingPiNode) node);
      return;
    } else if (node instanceof NullCheckNode) {
      visitNullCheckNode((NullCheckNode) node);
      return;
    } else if (node instanceof FixedGuardNode) {
      visitFixedGuardNode((FixedGuardNode) node);
      return;
    } else if (node instanceof ConditionAnchorNode) {
      // ConditionAnchorNode shouldn't occur during HighTier
      return;
    }

    /*-------------------------------------------------------------------------------------
     * Step 5: After special-case handling, we do our best for those FixedNode-s
     * where the effort to reduce their inputs might pay off.
     *
     * Why is this useful? For example, by the time the BeginNode for an If-branch
     * is visited (in general a ControlSplitNode), the If-condition will have gone already
     * through simplification (and thus potentially have been reduced to a
     * LogicConstantNode).
     *-------------------------------------------------------------------------------------
     */
    boolean paysOffToReduce = false;
    if (node instanceof ControlSplitNode) {
      // desire to simplify control flow
      paysOffToReduce = true;
    } else if (node instanceof ReturnNode) {
      paysOffToReduce = true;
    } else if (node instanceof AccessFieldNode || node instanceof AccessArrayNode) {
      // desire to remove null-checks
      paysOffToReduce = true;
    }

    // TODO comb remaining FixedWithNextNode subclasses, pick those with chances of paying-off

    // TODO UnsafeLoadNode takes a condition

    if (paysOffToReduce) {
      deverbosifyInputsInPlace(node);
    }

    /*---------------------------------------------------------------------------------------
     * Step 6: Any additional special-case handling, this time after having inputs reduced.
     * For example, leverage anchors provided by the FixedNode, to add facts to the factbase.
     *---------------------------------------------------------------------------------------
     */

    // TODO some nodes are GuardingNodes (eg, FixedAccessNode) we could use them to track state
    // TODO other nodes are guarded (eg JavaReadNode), thus *their* guards could be replaced.

  }
  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);
    }
  }
Example #5
0
    @SuppressWarnings("try")
    private AnchoringNode process(
        final Block b, final NodeBitMap activeGuards, final AnchoringNode startAnchor) {

      final LoweringToolImpl loweringTool =
          new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode());

      // Lower the instructions of this block.
      List<Node> nodes = schedule.nodesFor(b);
      for (Node node : nodes) {

        if (node.isDeleted()) {
          // This case can happen when previous lowerings deleted nodes.
          continue;
        }

        // Cache the next node to be able to reconstruct the previous of the next node
        // after lowering.
        FixedNode nextNode = null;
        if (node instanceof FixedWithNextNode) {
          nextNode = ((FixedWithNextNode) node).next();
        } else {
          nextNode = loweringTool.lastFixedNode().next();
        }

        if (node instanceof Lowerable) {
          Collection<Node> unscheduledUsages = null;
          assert (unscheduledUsages = getUnscheduledUsages(node)) != null;
          Mark preLoweringMark = node.graph().getMark();
          try (DebugCloseable s = node.graph().withNodeContext(node)) {
            ((Lowerable) node).lower(loweringTool);
          }
          if (loweringTool.guardAnchor.asNode().isDeleted()) {
            // TODO nextNode could be deleted but this is not currently supported
            assert nextNode.isAlive();
            loweringTool.guardAnchor = AbstractBeginNode.prevBegin(nextNode);
          }
          assert checkPostNodeLowering(node, loweringTool, preLoweringMark, unscheduledUsages);
        }

        if (!nextNode.isAlive()) {
          // can happen when the rest of the block is killed by lowering
          // (e.g. by an unconditional deopt)
          break;
        } else {
          Node nextLastFixed = nextNode.predecessor();
          if (!(nextLastFixed instanceof FixedWithNextNode)) {
            // insert begin node, to have a valid last fixed for next lowerable node.
            // This is about lowering a FixedWithNextNode to a control split while this
            // FixedWithNextNode is followed by some kind of BeginNode.
            // For example the when a FixedGuard followed by a loop exit is lowered to a
            // control-split + deopt.
            AbstractBeginNode begin = node.graph().add(new BeginNode());
            nextLastFixed.replaceFirstSuccessor(nextNode, begin);
            begin.setNext(nextNode);
            nextLastFixed = begin;
          }
          loweringTool.setLastFixedNode((FixedWithNextNode) nextLastFixed);
        }
      }
      return loweringTool.getCurrentGuardAnchor();
    }