Files
sdk/pkg/vm/lib/dominators.dart
T
Ryan Macnak 6cc943957b [vm] Compute a partitioning of the program into loading units.
The partitioning has the property that for every reference from loading unit S to unit T, either
 - the reference is through a deferred prefix, or
 - T is guarenteed to be loaded before S

The partitioning is constructed by cutting the dominator tree of the library import graph at deferred imports. It is suboptimal if there are deferred imports to multiple libraries in a connected component, but the expected use case involves loading units with a single deferred entry.

Bug: https://github.com/dart-lang/sdk/issues/41974
Change-Id: I3c49044ae19112525f197b077b36e4ce874b81ac
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151470
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2020-06-19 21:35:47 +00:00

127 lines
2.7 KiB
Dart

// Copyright (c) 2020, 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.
library vm.dominators;
class Vertex<T extends Vertex<T>> {
// Input: vertices directly reachable from this vertex.
final List<T> successors = <T>[];
// Output: the nearest vertex that all paths from the root must go through to
// reach this vertex.
T dominator;
bool isDominatedBy(T other) {
var d = this;
while (d != null) {
if (d == other) {
return true;
}
d = d.dominator;
}
return false;
}
// Temporaries. See Lengauer and Tarjan.
final List<T> _predecessors = <T>[];
int _semi = 0;
T _label;
T _ancestor;
T _parent;
List<T> _bucket;
}
// T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators
// in a Flowgraph."
computeDominators<T extends Vertex<T>>(T root) {
// Lengauer and Tarjan Step 1.
final vertex = <T>[];
vertex.add(null);
var n = 0;
dfs(T v) {
n++;
vertex.add(v);
v._semi = n;
v._label = v;
v._ancestor = null;
for (final w in v.successors) {
if (w._semi == 0) {
w._parent = v;
dfs(w);
}
w._predecessors.add(v);
}
}
dfs(root);
forestCompress(T v) {
if (v._ancestor._ancestor != null) {
forestCompress(v._ancestor);
if (v._ancestor._label._semi < v._label._semi) {
v._label = v._ancestor._label;
}
v._ancestor = v._ancestor._ancestor;
}
}
forestEval(T v) {
if (v._ancestor == null) {
return v;
} else {
forestCompress(v);
return v._label;
}
}
forestLink(T v, T w) {
w._ancestor = v;
}
for (var i = vertex.length - 1; i > 1; i--) {
Vertex<T> w = vertex[i];
// Lengauer and Tarjan Step 2.
for (Vertex<T> v in w._predecessors) {
if (v._semi == 0) continue; // Unreachable
final u = forestEval(v);
if (u._semi < w._semi) {
w._semi = u._semi;
}
}
Vertex<T> z = vertex[w._semi];
var b = z._bucket;
if (b == null) {
z._bucket = b = <T>[];
}
b.add(w);
forestLink(w._parent, w);
// Lengauer and Tarjan Step 3.
z = w._parent;
assert(z != null);
b = z._bucket;
z._bucket = null;
if (b != null) {
for (final v in b) {
final u = forestEval(v);
v.dominator = u._semi < v._semi ? u : w._parent;
}
}
}
// Lengauer and Tarjan Step 4.
for (var i = 2; i < vertex.length; i++) {
final w = vertex[i];
if (w.dominator != vertex[w._semi]) {
w.dominator = w.dominator.dominator;
}
}
}