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
  /**
   * 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.

  }