| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library dominator_tree; |
| 6 |
| 7 // Flowgraph dominators in O(m log n) time. Implements the algorithm from |
| 8 // [Lengauer & Tarjan 1979] |
| 9 // T. Lengauer and R.E. Tarjan, |
| 10 // "A fast algorithm for finding dominators in a flowgraph", |
| 11 // ACM Transactions on Programming Language and Systems, 1(1):121-141, 1979. |
| 12 |
| 13 // Internal vertex information used inside 'Dominator'. |
| 14 // Field names mostly follow naming in [Lengauer & Tarjan 1979]. |
| 15 class _Vertex { |
| 16 final Object id; |
| 17 _Vertex dom; |
| 18 _Vertex parent; |
| 19 _Vertex ancestor; |
| 20 _Vertex label; |
| 21 int semi; |
| 22 final List<_Vertex> pred = new List<_Vertex>(); |
| 23 final List<_Vertex> bucket = new List<_Vertex>(); |
| 24 // TODO(koda): Avoid duplication by having an interface for 'id' with |
| 25 // access to outgoing edges, and/or clearing 'succ' after constructing |
| 26 // inverse graph in 'pred'. |
| 27 final List<_Vertex> succ = new List<_Vertex>(); |
| 28 _Vertex(this.id) { label = this; } |
| 29 } |
| 30 |
| 31 // Utility to compute immediate dominators. Usage: |
| 32 // 1. Build the flowgraph using 'addEdges'. |
| 33 // 2. Call 'computeDominatorTree' once. |
| 34 // 3. Use 'dominator' to access result. |
| 35 // The instance can only be used once. |
| 36 class Dominator { |
| 37 final Map<Object, _Vertex> _idToVertex = new Map<Object, _Vertex>(); |
| 38 final List<_Vertex> _vertex = new List<_Vertex>(); |
| 39 |
| 40 void addEdges(Object u, Iterable<Object> vs) { |
| 41 _asVertex(u).succ.addAll(vs.map(_asVertex)); |
| 42 } |
| 43 |
| 44 // Returns the immediate dominator of 'v', or null if 'v' is the root. |
| 45 Object dominator(Object v) { |
| 46 _Vertex dom = _asVertex(v).dom; |
| 47 return dom == null ? null : dom.id; |
| 48 } |
| 49 |
| 50 _Vertex _asVertex(Object u) { |
| 51 return _idToVertex.putIfAbsent(u, () => new _Vertex(u)); |
| 52 } |
| 53 |
| 54 void _dfs(_Vertex v) { |
| 55 v.semi = _vertex.length; |
| 56 _vertex.add(v); |
| 57 for (_Vertex w in v.succ) { |
| 58 if (w.semi == null) { |
| 59 w.parent = v; |
| 60 _dfs(w); |
| 61 } |
| 62 w.pred.add(v); |
| 63 } |
| 64 } |
| 65 |
| 66 void _compress(_Vertex v) { |
| 67 if (v.ancestor.ancestor != null) { |
| 68 _compress(v.ancestor); |
| 69 if (v.ancestor.label.semi < v.label.semi) { |
| 70 v.label = v.ancestor.label; |
| 71 } |
| 72 v.ancestor = v.ancestor.ancestor; |
| 73 } |
| 74 } |
| 75 |
| 76 _Vertex _eval(_Vertex v) { |
| 77 if (v.ancestor == null) { |
| 78 return v; |
| 79 } else { |
| 80 _compress(v); |
| 81 return v.label; |
| 82 } |
| 83 } |
| 84 |
| 85 void _link(_Vertex v, _Vertex w) { |
| 86 w.ancestor = v; |
| 87 } |
| 88 |
| 89 void computeDominatorTree(Object root) { |
| 90 _Vertex r = _asVertex(root); |
| 91 int n = _idToVertex.length; |
| 92 _dfs(r); |
| 93 if (_vertex.length != n) { |
| 94 throw new StateError("Not a flowgraph: " |
| 95 "only ${_vertex.length} of $n vertices reachable"); |
| 96 } |
| 97 for (int i = n - 1; i >= 1; --i) { |
| 98 _Vertex w = _vertex[i]; |
| 99 for (_Vertex v in w.pred) { |
| 100 _Vertex u = _eval(v); |
| 101 if (u.semi < w.semi) { |
| 102 w.semi = u.semi; |
| 103 } |
| 104 } |
| 105 _vertex[w.semi].bucket.add(w); |
| 106 _link(w.parent, w); |
| 107 for (_Vertex v in w.parent.bucket) { |
| 108 _Vertex u = _eval(v); |
| 109 v.dom = u.semi < v.semi ? u : w.parent; |
| 110 } |
| 111 w.parent.bucket.clear(); |
| 112 } |
| 113 for (int i = 1; i < n; ++i) { |
| 114 _Vertex w = _vertex[i]; |
| 115 if (w.dom != _vertex[w.semi]) { |
| 116 w.dom = w.dom.dom; |
| 117 } |
| 118 } |
| 119 r.dom = null; |
| 120 } |
| 121 } |
| OLD | NEW |