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