Index: pkg/compiler/tool/graph.dart |
diff --git a/pkg/compiler/tool/graph.dart b/pkg/compiler/tool/graph.dart |
deleted file mode 100644 |
index 1ef8d9e12d4a50b015bbd3a42071e5f544c88e4c..0000000000000000000000000000000000000000 |
--- a/pkg/compiler/tool/graph.dart |
+++ /dev/null |
@@ -1,292 +0,0 @@ |
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-/// A library to work with graphs. It contains a couple algorithms, including |
-/// Tarjan's algorithm to compute strongest connected components in a graph and |
-/// Cooper et al's dominator algorithm. |
-/// |
-/// Portions of the code in this library was adapted from |
-/// `package:analyzer/src/generated/collection_utilities.dart`. |
-// TODO(sigmund): move this into a shared place? |
-library compiler.tool.graph; |
- |
-import 'dart:math' as math; |
- |
-abstract class Graph<N> { |
- Iterable<N> get nodes; |
- bool get isEmpty; |
- int get nodeCount; |
- Iterable<N> targetsOf(N source); |
- Iterable<N> sourcesOf(N source); |
- |
- /// Run a topological sort of the graph. Since the graph may contain cycles, |
- /// this results in a list of strongly connected components rather than a list |
- /// of nodes. The nodes in each strongly connected components only have edges |
- /// that point to nodes in the same component or earlier components. |
- List<List<N>> computeTopologicalSort() { |
- _SccFinder<N> finder = new _SccFinder<N>(this); |
- return finder.computeTopologicalSort(); |
- } |
- |
- /// Whether [source] can transitively reach [target]. |
- bool containsPath(N source, N target) { |
- Set<N> seen = new Set<N>(); |
- bool helper(N node) { |
- if (identical(node, target)) return true; |
- if (!seen.add(node)) return false; |
- return targetsOf(node).any(helper); |
- } |
- return helper(source); |
- } |
- |
- /// Returns all nodes reachable from [root] in post order. |
- List<N> postOrder(N root) { |
- var seen = new Set<N>(); |
- var result = <N>[]; |
- helper(n) { |
- if (!seen.add(n)) return; |
- targetsOf(n).forEach(helper); |
- result.add(n); |
- } |
- helper(root); |
- return result; |
- } |
- |
- /// Return a list of nodes that form a cycle containing the given node. If the |
- /// node is not part of this graph, then a list containing only the node |
- /// itself will be returned. |
- List<N> findCycleContaining(N node) { |
- assert(node != null); |
- _SccFinder<N> finder = new _SccFinder<N>(this); |
- return finder._componentContaining(node); |
- } |
- |
- Graph<N> dominatorTree(N root) { |
- var iDom = (new _DominatorFinder(this)..run(root)).immediateDominators; |
- var graph = new EdgeListGraph<N>(); |
- for (N node in iDom.keys) { |
- if (node != root) graph.addEdge(iDom[node], node); |
- } |
- return graph; |
- } |
-} |
- |
-class EdgeListGraph<N> extends Graph<N> { |
- /// Edges in the graph. |
- Map<N, Set<N>> _edges = new Map<N, Set<N>>(); |
- |
- /// The reverse of _edges. |
- Map<N, Set<N>> _revEdges = new Map<N, Set<N>>(); |
- |
- Iterable<N> get nodes => _edges.keys; |
- bool get isEmpty => _edges.isEmpty; |
- int get nodeCount => _edges.length; |
- |
- final _empty = new Set<N>(); |
- |
- Iterable<N> targetsOf(N source) => _edges[source] ?? _empty; |
- Iterable<N> sourcesOf(N source) => _revEdges[source] ?? _empty; |
- |
- void addEdge(N source, N target) { |
- assert(source != null); |
- assert(target != null); |
- addNode(source); |
- addNode(target); |
- _edges[source].add(target); |
- _revEdges[target].add(source); |
- } |
- |
- void addNode(N node) { |
- assert(node != null); |
- _edges.putIfAbsent(node, () => new Set<N>()); |
- _revEdges.putIfAbsent(node, () => new Set<N>()); |
- } |
- |
- /// Remove the edge from the given [source] node to the given [target] node. |
- /// If there was no such edge then the graph will be unmodified: the number of |
- /// edges will be the same and the set of nodes will be the same (neither node |
- /// will either be added or removed). |
- void removeEdge(N source, N target) { |
- _edges[source]?.remove(target); |
- } |
- |
- /// Remove the given node from this graph. As a consequence, any edges for |
- /// which that node was either a head or a tail will also be removed. |
- void removeNode(N node) { |
- _edges.remove(node); |
- var sources = _revEdges[node]; |
- if (sources == null) return; |
- for (var source in sources) { |
- _edges[source].remove(node); |
- } |
- } |
- |
- /// Remove all of the given nodes from this graph. As a consequence, any edges |
- /// for which those nodes were either a head or a tail will also be removed. |
- void removeAllNodes(List<N> nodes) => nodes.forEach(removeNode); |
-} |
- |
-/// Used by the [SccFinder] to maintain information about the nodes that have |
-/// been examined. There is an instance of this class per node in the graph. |
-class _NodeInfo<N> { |
- /// Depth of the node corresponding to this info. |
- int index = 0; |
- |
- /// Depth of the first node in a cycle. |
- int lowlink = 0; |
- |
- /// Whether the corresponding node is on the stack. Used to remove the need |
- /// for searching a collection for the node each time the question needs to be |
- /// asked. |
- bool onStack = false; |
- |
- /// Component that contains the corresponding node. |
- List<N> component; |
- |
- _NodeInfo(int depth) |
- : index = depth, lowlink = depth, onStack = false; |
-} |
- |
-/// Implements Tarjan's Algorithm for finding the strongly connected components |
-/// in a graph. |
-class _SccFinder<N> { |
- /// The graph to process. |
- final Graph<N> _graph; |
- |
- /// The index used to uniquely identify the depth of nodes. |
- int _index = 0; |
- |
- /// Nodes that are being visited in order to identify components. |
- List<N> _stack = new List<N>(); |
- |
- /// Information associated with each node. |
- Map<N, _NodeInfo<N>> _info = <N, _NodeInfo<N>>{}; |
- |
- /// All strongly connected components found, in topological sort order (each |
- /// node in a strongly connected component only has edges that point to nodes |
- /// in the same component or earlier components). |
- List<List<N>> _allComponents = new List<List<N>>(); |
- |
- _SccFinder(this._graph) : super(); |
- |
- /// Return a list containing the nodes that are part of the strongly connected |
- /// component that contains the given node. |
- List<N> _componentContaining(N node) => _strongConnect(node).component; |
- |
- /// Run Tarjan's algorithm and return the resulting list of strongly connected |
- /// components. The list is in topological sort order (each node in a strongly |
- /// connected component only has edges that point to nodes in the same |
- /// component or earlier components). |
- List<List<N>> computeTopologicalSort() { |
- for (N node in _graph.nodes) { |
- var nodeInfo = _info[node]; |
- if (nodeInfo == null) _strongConnect(node); |
- } |
- return _allComponents; |
- } |
- |
- /// Remove and return the top-most element from the stack. |
- N _pop() { |
- N node = _stack.removeAt(_stack.length - 1); |
- _info[node].onStack = false; |
- return node; |
- } |
- |
- /// Add the given node to the stack. |
- void _push(N node) { |
- _info[node].onStack = true; |
- _stack.add(node); |
- } |
- |
- /// Compute the strongly connected component that contains the given node as |
- /// well as any components containing nodes that are reachable from the given |
- /// component. |
- _NodeInfo<N> _strongConnect(N v) { |
- // Set the depth index for v to the smallest unused index |
- var vInfo = new _NodeInfo<N>(_index++); |
- _info[v] = vInfo; |
- _push(v); |
- |
- for (N w in _graph.targetsOf(v)) { |
- var wInfo = _info[w]; |
- if (wInfo == null) { |
- // Successor w has not yet been visited; recurse on it |
- wInfo = _strongConnect(w); |
- vInfo.lowlink = math.min(vInfo.lowlink, wInfo.lowlink); |
- } else if (wInfo.onStack) { |
- // Successor w is in stack S and hence in the current SCC |
- vInfo.lowlink = math.min(vInfo.lowlink, wInfo.index); |
- } |
- } |
- |
- // If v is a root node, pop the stack and generate an SCC |
- if (vInfo.lowlink == vInfo.index) { |
- var component = new List<N>(); |
- N w; |
- do { |
- w = _pop(); |
- component.add(w); |
- _info[w].component = component; |
- } while (!identical(w, v)); |
- _allComponents.add(component); |
- } |
- return vInfo; |
- } |
-} |
- |
-/// Computes dominators using (Cooper, Harvey, and Kennedy's |
-/// algorithm)[http://www.cs.rice.edu/~keith/EMBED/dom.pdf]. |
-class _DominatorFinder<N> { |
- final Graph<N> _graph; |
- Map<N, N> immediateDominators = {}; |
- Map<N, int> postOrderId = {}; |
- _DominatorFinder(this._graph); |
- |
- run(N root) { |
- immediateDominators[root] = root; |
- bool changed = true; |
- int i = 0; |
- var nodesInPostOrder = _graph.postOrder(root); |
- for (var n in nodesInPostOrder) { |
- postOrderId[n] = i++; |
- } |
- var nodesInReversedPostOrder = nodesInPostOrder.reversed; |
- while (changed) { |
- changed = false; |
- for (var n in nodesInReversedPostOrder) { |
- if (n == root) continue; |
- bool first = true; |
- var idom = null; |
- for (var p in _graph.sourcesOf(n)) { |
- if (immediateDominators[p] != null) { |
- if (first) { |
- idom = p; |
- first = false; |
- } else { |
- idom = _intersect(p, idom); |
- } |
- } |
- } |
- if (immediateDominators[n] != idom) { |
- immediateDominators[n] = idom; |
- changed = true; |
- } |
- } |
- } |
- } |
- |
- N _intersect(N b1, N b2) { |
- var finger1 = b1; |
- var finger2 = b2; |
- while (finger1 != finger2) { |
- while (postOrderId[finger1] < postOrderId[finger2]) { |
- finger1 = immediateDominators[finger1]; |
- } |
- while (postOrderId[finger2] < postOrderId[finger1]) { |
- finger2 = immediateDominators[finger2]; |
- } |
- } |
- return finger1; |
- } |
-} |