Java Code Examples for com.google.javascript.jscomp.graph.DiGraph.DiGraphNode#getOutEdges()

The following examples show how to use com.google.javascript.jscomp.graph.DiGraph.DiGraphNode#getOutEdges() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: CheckPathsBetweenNodes.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
private void discoverBackEdges(DiGraphNode<N, E> u) {
  u.setAnnotation(GRAY);
  for (DiGraphEdge<N, E> e : u.getOutEdges()) {
    if (ignoreEdge(e)) {
      continue;
    }
    DiGraphNode<N, E> v = e.getDestination();
    if (v.getAnnotation() == WHITE) {
      discoverBackEdges(v);
    } else if (v.getAnnotation() == GRAY) {
      e.setAnnotation(BACK_EDGE);
    }
  }
  u.setAnnotation(BLACK);
}
 
Example 2
Source File: CheckPathsBetweenNodes.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Verify that all non-looping paths from {@code a} to {@code b} pass
 * through at least one node where {@code nodePredicate} is true.
 */
private boolean checkAllPathsWithoutBackEdges(DiGraphNode<N, E> a,
    DiGraphNode<N, E> b) {
  if (nodePredicate.apply(a.getValue()) &&
      (inclusive || (a != start && a != end))) {
    return true;
  }
  if (a == b) {
    return false;
  }
  for (DiGraphEdge<N, E> e : a.getOutEdges()) {
    // Once we visited that edge once, we no longer need to
    // re-visit it again.
    if (e.getAnnotation() == VISITED_EDGE) {
      continue;
    }
    e.setAnnotation(VISITED_EDGE);

    if (ignoreEdge(e)) {
      continue;
    }
    if (e.getAnnotation() == BACK_EDGE) {
      continue;
    }

    DiGraphNode<N, E> next = e.getDestination();
    if (!checkAllPathsWithoutBackEdges(next, b)) {
      return false;
    }
  }
  return true;
}
 
Example 3
Source File: CheckPathsBetweenNodes.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Verify that some non-looping paths from {@code a} to {@code b} pass
 * through at least one node where {@code nodePredicate} is true.
 */
private boolean checkSomePathsWithoutBackEdges(DiGraphNode<N, E> a,
    DiGraphNode<N, E> b) {
  if (nodePredicate.apply(a.getValue()) &&
      (inclusive || (a != start && a != end))) {
    return true;
  }
  if (a == b) {
    return false;
  }
  for (DiGraphEdge<N, E> e : a.getOutEdges()) {
    // Once we visited that edge once, we no longer need to
    // re-visit it again.
    if (e.getAnnotation() == VISITED_EDGE) {
      continue;
    }
    e.setAnnotation(VISITED_EDGE);

    if (ignoreEdge(e)) {
      continue;
    }
    if (e.getAnnotation() == BACK_EDGE) {
      continue;
    }

    DiGraphNode<N, E> next = e.getDestination();
    if (checkSomePathsWithoutBackEdges(next, b)) {
      return true;
    }
  }
  return false;
}
 
Example 4
Source File: GraphPruner.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
private static <N, E> LinkedDirectedGraph<N, E> cloneGraph(
    DiGraph<N, E> graph) {
  LinkedDirectedGraph<N, E> newGraph = LinkedDirectedGraph.create();
  for (DiGraphNode<N, E> node : graph.getDirectedGraphNodes()) {
    newGraph.createNode(node.getValue());

    for (DiGraphEdge<N, E> outEdge : node.getOutEdges()) {
      N dest = outEdge.getDestination().getValue();
      newGraph.createNode(dest);
      newGraph.connect(node.getValue(), outEdge.getValue(), dest);
    }
  }

  return newGraph;
}
 
Example 5
Source File: FixedPointGraphTraversal.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Compute a fixed point for the given graph, entering from the given nodes.
 * @param graph The graph to traverse.
 * @param entrySet The nodes to begin traversing from.
 */
public void computeFixedPoint(DiGraph<N, E> graph, Set<N> entrySet) {
  int cycleCount = 0;
  long nodeCount = graph.getNodes().size();

  // Choose a bail-out heuristically in case the computation
  // doesn't converge.
  long maxIterations = Math.max(nodeCount * nodeCount * nodeCount, 100);

  // Use a LinkedHashSet, so that the traversal is deterministic.
  LinkedHashSet<DiGraphNode<N, E>> workSet =
      Sets.newLinkedHashSet();
  for (N n : entrySet) {
    workSet.add(graph.getDirectedGraphNode(n));
  }
  for (; !workSet.isEmpty() && cycleCount < maxIterations; cycleCount++) {
    // For every out edge in the workSet, traverse that edge. If that
    // edge updates the state of the graph, then add the destination
    // node to the resultSet, so that we can update all of its out edges
    // on the next iteration.
    DiGraphNode<N, E> source = workSet.iterator().next();
    N sourceValue = source.getValue();

    workSet.remove(source);

    List<DiGraphEdge<N, E>> outEdges = source.getOutEdges();
    for (DiGraphEdge<N, E> edge : outEdges) {
      N destNode = edge.getDestination().getValue();
      if (callback.traverseEdge(sourceValue, edge.getValue(), destNode)) {
        workSet.add(edge.getDestination());
      }
    }
  }

  Preconditions.checkState(cycleCount != maxIterations,
      NON_HALTING_ERROR_MSG);
}
 
Example 6
Source File: Closure_127_UnreachableCodeElimination_t.java    From coming with MIT License 4 votes vote down vote up
/**
 * Tries to remove n if it is an unconditional branch node (break, continue,
 * or return) and the target of n is the same as the the follow of n.
 * That is, if removing n preserves the control flow. Also if n targets
 * another unconditional branch, this function will recursively try to
 * remove the target branch as well. The reason why we want to cascade this
 * removal is because we only run this pass once. If we have code such as
 *
 * break -> break -> break
 *
 * where all 3 breaks are useless, then the order of removal matters. When
 * we first look at the first break, we see that it branches to the 2nd
 * break. However, if we remove the last break, the 2nd break becomes
 * useless and finally the first break becomes useless as well.
 *
 * @returns The target of this jump. If the target is also useless jump,
 *     the target of that useless jump recursively.
 */
@SuppressWarnings("fallthrough")
private void tryRemoveUnconditionalBranching(Node n) {
  /*
   * For each unconditional branching control flow node, check to see
   * if the ControlFlowAnalysis.computeFollowNode of that node is same as
   * the branching target. If it is, the branch node is safe to be removed.
   *
   * This is not as clever as MinimizeExitPoints because it doesn't do any
   * if-else conversion but it handles more complicated switch statements
   * much more nicely.
   */

  // If n is null the target is the end of the function, nothing to do.
  if (n == null) {
     return;
  }

  DiGraphNode<Node, Branch> gNode = cfg.getDirectedGraphNode(n);

  if (gNode == null) {
    return;
  }

  switch (n.getType()) {
    case Token.RETURN:
      if (n.hasChildren()) {
        break;
      }
    case Token.BREAK:
    case Token.CONTINUE:
      // We are looking for a control flow changing statement that always
      // branches to the same node. If after removing it control still
      // branches to the same node, it is safe to remove.
      List<DiGraphEdge<Node, Branch>> outEdges = gNode.getOutEdges();
      if (outEdges.size() == 1 &&
          // If there is a next node, this jump is not useless.
          (n.getNext() == null || n.getNext().isFunction())) {

        Preconditions.checkState(
            outEdges.get(0).getValue() == Branch.UNCOND);
        Node fallThrough = computeFollowing(n);
        Node nextCfgNode = outEdges.get(0).getDestination().getValue();
        if (nextCfgNode == fallThrough && !inFinally(n.getParent(), n)) {
          removeNode(n);
        }
      }
  }
}
 
Example 7
Source File: Closure_127_UnreachableCodeElimination_s.java    From coming with MIT License 4 votes vote down vote up
/**
 * Tries to remove n if it is an unconditional branch node (break, continue,
 * or return) and the target of n is the same as the the follow of n.
 * That is, if removing n preserves the control flow. Also if n targets
 * another unconditional branch, this function will recursively try to
 * remove the target branch as well. The reason why we want to cascade this
 * removal is because we only run this pass once. If we have code such as
 *
 * break -> break -> break
 *
 * where all 3 breaks are useless, then the order of removal matters. When
 * we first look at the first break, we see that it branches to the 2nd
 * break. However, if we remove the last break, the 2nd break becomes
 * useless and finally the first break becomes useless as well.
 *
 * @returns The target of this jump. If the target is also useless jump,
 *     the target of that useless jump recursively.
 */
@SuppressWarnings("fallthrough")
private void tryRemoveUnconditionalBranching(Node n) {
  /*
   * For each unconditional branching control flow node, check to see
   * if the ControlFlowAnalysis.computeFollowNode of that node is same as
   * the branching target. If it is, the branch node is safe to be removed.
   *
   * This is not as clever as MinimizeExitPoints because it doesn't do any
   * if-else conversion but it handles more complicated switch statements
   * much more nicely.
   */

  // If n is null the target is the end of the function, nothing to do.
  if (n == null) {
     return;
  }

  DiGraphNode<Node, Branch> gNode = cfg.getDirectedGraphNode(n);

  if (gNode == null) {
    return;
  }

  switch (n.getType()) {
    case Token.RETURN:
      if (n.hasChildren()) {
        break;
      }
    case Token.BREAK:
    case Token.CONTINUE:
      // We are looking for a control flow changing statement that always
      // branches to the same node. If after removing it control still
      // branches to the same node, it is safe to remove.
      List<DiGraphEdge<Node, Branch>> outEdges = gNode.getOutEdges();
      if (outEdges.size() == 1 &&
          // If there is a next node, this jump is not useless.
          (n.getNext() == null || n.getNext().isFunction())) {

        Preconditions.checkState(
            outEdges.get(0).getValue() == Branch.UNCOND);
        Node fallThrough = computeFollowing(n);
        Node nextCfgNode = outEdges.get(0).getDestination().getValue();
        if (nextCfgNode == fallThrough) {
          removeNode(n);
        }
      }
  }
}
 
Example 8
Source File: Closure_85_UnreachableCodeElimination_t.java    From coming with MIT License 4 votes vote down vote up
/**
 * Tries to remove n if an unconditional branch node (break, continue or
 * return) if the target of n is the same as the the follow of n. That is, if
 * we remove n, the control flow remains the same. Also if n targets to
 * another unconditional branch, this function will recursively try to remove
 * the target branch as well. The reason why we want to cascade this removal
 * is because we only run this pass once. If we have code such as
 *
 * break -> break -> break
 *
 * where all 3 break's are useless. The order of removal matters. When we
 * first look at the first break, we see that it branches to the 2nd break.
 * However, if we remove the last break, the 2nd break becomes useless and
 * finally the first break becomes useless as well.
 *
 * @return The target of this jump. If the target is also useless jump,
 *     the target of that useless jump recursively.
 */
@SuppressWarnings("fallthrough")
private Node tryRemoveUnconditionalBranching(Node n) {
  /*
   * For each of the unconditional branching control flow node, check to see
   * if the ControlFlowAnalysis.computeFollowNode of that node is same as
   * the branching target. If it is, the branch node is safe to be removed.
   *
   * This is not as clever as MinimizeExitPoints because it doesn't do any
   * if-else conversion but it handles more complicated switch statements
   * much nicer.
   */

  // If n is null the target is the end of the function, nothing to do.
  if (n == null) {
     return n;
  }

  DiGraphNode<Node, Branch> gNode = curCfg.getDirectedGraphNode(n);

  if (gNode == null) {
    return n;
  }

  switch (n.getType()) {
    case Token.RETURN:
      if (n.hasChildren()) {
        break;
      }
    case Token.BREAK:
    case Token.CONTINUE:

      // We are looking for a control flow changing statement that always
      // branches to the same node. If removing it the control flow still
      // branches to that same node. It is safe to remove it.
      List<DiGraphEdge<Node,Branch>> outEdges = gNode.getOutEdges();
      if (outEdges.size() == 1 &&
          // If there is a next node, there is no chance this jump is useless.
          (n.getNext() == null || n.getNext().getType() == Token.FUNCTION)) {

        Preconditions.checkState(outEdges.get(0).getValue() == Branch.UNCOND);
        Node fallThrough = computeFollowing(n);
        Node nextCfgNode = outEdges.get(0).getDestination().getValue();
        if (nextCfgNode == fallThrough) {
          removeDeadExprStatementSafely(n);
          return fallThrough;
        }
      }
  }
  return n;
}
 
Example 9
Source File: UnreachableCodeElimination.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Tries to remove n if it is an unconditional branch node (break, continue,
 * or return) and the target of n is the same as the the follow of n.
 * That is, if removing n preserves the control flow. Also if n targets
 * another unconditional branch, this function will recursively try to remove
 * the target branch as well. The reason why we want to cascade this removal
 * is because we only run this pass once. If we have code such as
 *
 * break -> break -> break
 *
 * where all 3 breaks are useless, then the order of removal matters. When we
 * first look at the first break, we see that it branches to the 2nd break.
 * However, if we remove the last break, the 2nd break becomes useless and
 * finally the first break becomes useless as well.
 *
 * @return The target of this jump. If the target is also useless jump,
 *     the target of that useless jump recursively.
 */
@SuppressWarnings("fallthrough")
private Node tryRemoveUnconditionalBranching(Node n) {
  /*
   * For each unconditional branching control flow node, check to see
   * if the ControlFlowAnalysis.computeFollowNode of that node is same as
   * the branching target. If it is, the branch node is safe to be removed.
   *
   * This is not as clever as MinimizeExitPoints because it doesn't do any
   * if-else conversion but it handles more complicated switch statements
   * much more nicely.
   */

  // If n is null the target is the end of the function, nothing to do.
  if (n == null) {
     return n;
  }

  DiGraphNode<Node, Branch> gNode = cfg.getDirectedGraphNode(n);

  if (gNode == null) {
    return n;
  }

  switch (n.getType()) {
    case Token.RETURN:
      if (n.hasChildren()) {
        break;
      }
    case Token.BREAK:
    case Token.CONTINUE:

      // We are looking for a control flow changing statement that always
      // branches to the same node. If after removing it control still
      // branches to the same node, it is safe to remove.
      List<DiGraphEdge<Node,Branch>> outEdges = gNode.getOutEdges();
      if (outEdges.size() == 1 &&
          // If there is a next node, there is no chance this jump is useless.
          (n.getNext() == null || n.getNext().isFunction())) {

        Preconditions.checkState(outEdges.get(0).getValue() == Branch.UNCOND);
        Node fallThrough = computeFollowing(n);
        Node nextCfgNode = outEdges.get(0).getDestination().getValue();
        if (nextCfgNode == fallThrough) {
          removeDeadExprStatementSafely(n);
          return fallThrough;
        }
      }
  }
  return n;
}