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 |