Index: runtime/observatory/lib/object_graph.dart |
diff --git a/runtime/observatory/lib/object_graph.dart b/runtime/observatory/lib/object_graph.dart |
index d1c171bfe017a6ceb8118ba67054e412d412b80c..a691beba685c7f97b05bb4319a25f984dd1746fc 100644 |
--- a/runtime/observatory/lib/object_graph.dart |
+++ b/runtime/observatory/lib/object_graph.dart |
@@ -219,6 +219,8 @@ class ReadStream { |
// elements as the sentinel. |
const ROOT = 1; |
const SENTINEL = 0; |
+// Keep in sync with runtime/vm/object_graph.cc. |
+const kStackCid = 1; |
Cutch
2016/11/18 20:40:31
can we get this from the VM over the protocol some
rmacnak
2016/11/18 22:34:02
pushing in the header alongside the object alignme
|
class ObjectVertex { |
final int _id; |
@@ -227,6 +229,7 @@ class ObjectVertex { |
ObjectVertex._(this._id, this._graph); |
bool get isRoot => ROOT == _id; |
+ bool get isStack => kStackCid == vmCid; |
bool operator ==(other) => _id == other._id && _graph == other._graph; |
int get hashCode => _id; |
@@ -300,6 +303,7 @@ class MergedObjectVertex { |
MergedObjectVertex._(this._id, this._graph); |
bool get isRoot => ROOT == _id; |
+ bool get isStack => kStackCid == vmCid; |
bool operator ==(other) => _id == other._id && _graph == other._graph; |
int get hashCode => _id; |
@@ -497,8 +501,9 @@ class ObjectGraph { |
List<ByteData> _chunks; |
int _kObjectAlignment; |
- int _N; |
- int _E; |
+ int _N; // Objects in the snapshot. |
+ int _Nconnected; // Objects reachable from root. |
+ int _E; // References in the snapshot. |
int _size; |
// Indexed by node id, with id 0 representing invalid/uninitialized. |
@@ -660,15 +665,37 @@ class ObjectGraph { |
} |
} |
- assert(dfsNumber == N); |
- for (var i = ROOT; i <= N; i++) { |
- assert(semi[i] != SENTINEL); |
+ if (dfsNumber != N) { |
+ // This may happen in filtered snapshots. |
+ print("Warning: graph has unconnected nodes"); |
Cutch
2016/11/18 20:40:31
remove or use the logger?
rmacnak
2016/11/18 22:34:02
Changed to use logger.
|
+ } |
+ |
+ for (var i = 1; i <= dfsNumber; i++) { |
Cutch
2016/11/18 20:40:31
assert(() {
....
});
rmacnak
2016/11/18 22:34:02
Done.
|
+ var v = vertex[i]; |
+ assert(semi[v] != SENTINEL); |
} |
- assert(parent[ROOT] == SENTINEL); |
- for (var i = ROOT + 1; i <= N; i++) { |
- assert(parent[i] != SENTINEL); |
+ assert(parent[1] == SENTINEL); |
+ for (var i = 2; i <= dfsNumber; i++) { |
+ var v = vertex[i]; |
+ assert(parent[v] != SENTINEL); |
} |
+ if (dfsNumber != N) { |
+ // Remove successors of unconnected nodes |
+ for (var i = ROOT + 1; i <= N; i++) { |
Cutch
2016/11/18 20:40:31
how about we add a:
const FIRST_OBJECT = ROOT + 1
rmacnak
2016/11/18 22:34:02
ROOT is the first object.
|
+ if (parent[i] == SENTINEL) { |
+ var startSuccIndex = firstSuccs[i]; |
+ var limitSuccIndex = firstSuccs[i + 1]; |
+ for (var succIndex = startSuccIndex; |
+ succIndex < limitSuccIndex; |
+ succIndex++) { |
+ succs[succIndex] = SENTINEL; |
+ } |
+ } |
+ } |
+ } |
+ |
+ _Nconnected = dfsNumber; |
_vertex = vertex; |
_semi = semi; |
_parent = parent; |
@@ -676,6 +703,7 @@ class ObjectGraph { |
void _buildPredecessors() { |
var N = _N; |
+ var Nconnected = _Nconnected; |
var E = _E; |
var firstSuccs = _firstSuccs; |
var succs = _succs; |
@@ -691,7 +719,9 @@ class ObjectGraph { |
// Count predecessors of each node. |
for (var succIndex = 0; succIndex < E; succIndex++) { |
var succId = succs[succIndex]; |
- numPreds[succId]++; |
+ if (succId != SENTINEL) { |
+ numPreds[succId]++; |
+ } |
} |
// Assign indices into predecessors array. |
@@ -704,8 +734,10 @@ class ObjectGraph { |
firstPreds[i] = thisPredIndex; |
nextPreds[i] = thisPredIndex; |
} |
- assert(predIndex == E); |
- firstPreds[N + 1] = E; // Extra entry for cheap boundary detection. |
+ if (N == Nconnected) { |
+ assert(predIndex == E); |
+ } |
+ firstPreds[N + 1] = predIndex; // Extra entry for cheap boundary detection. |
// Fill predecessors array. |
for (var i = 1; i <= N; i++) { |
@@ -715,8 +747,10 @@ class ObjectGraph { |
succIndex < limitSuccIndex; |
succIndex++) { |
var succId = succs[succIndex]; |
- var predIndex = nextPreds[succId]++; |
- preds[predIndex] = i; |
+ if (succId != SENTINEL) { |
+ var predIndex = nextPreds[succId]++; |
+ preds[predIndex] = i; |
+ } |
} |
} |
@@ -802,6 +836,7 @@ class ObjectGraph { |
// in a Flowgraph." |
void _buildDominators() { |
var N = _N; |
+ var Nconnected = _Nconnected; |
var vertex = _vertex; |
var semi = _semi; |
@@ -825,7 +860,7 @@ class ObjectGraph { |
var stackNode = new Uint32List(N + 1); |
var stackState = new Uint8List(N + 1); |
- for (var i = N; i > 1; i--) { |
+ for (var i = Nconnected; i > 1; i--) { |
var w = vertex[i]; |
assert(w != ROOT); |
@@ -864,7 +899,7 @@ class ObjectGraph { |
assert(buckets[i] == null); |
} |
// Lengauer & Tarjan Step 4. |
- for (var i = 2; i <= N; i++) { |
+ for (var i = 2; i <= Nconnected; i++) { |
var w = vertex[i]; |
if (dom[w] != vertex[semi[w]]) { |
dom[w] = dom[dom[w]]; |
@@ -876,6 +911,7 @@ class ObjectGraph { |
void _calculateRetainedSizes() { |
var N = _N; |
+ var Nconnected = _Nconnected; |
var size = 0; |
var shallowSizes = _shallowSizes; |
@@ -883,8 +919,9 @@ class ObjectGraph { |
var doms = _doms; |
// Sum shallow sizes. |
- for (var i = ROOT; i < N; i++) { |
- size += shallowSizes[i]; |
+ for (var i = 1; i <= Nconnected; i++) { |
Cutch
2016/11/18 20:40:31
FIRST_OBJECT
rmacnak
2016/11/18 22:34:02
1 here is a DFS number, not a node index.
|
+ var v = vertex[i]; |
+ size += shallowSizes[v]; |
} |
// Start with retained size as shallow size. |
@@ -892,12 +929,14 @@ class ObjectGraph { |
// In post order (bottom up), add retained size to dominator's retained |
// size, skipping root. |
- for (var i = N; i > 1; i--) { |
+ for (var i = Nconnected; i > 1; i--) { |
var v = vertex[i]; |
assert(v != ROOT); |
- retainedSizes[doms[i]] += retainedSizes[i]; |
+ retainedSizes[doms[v]] += retainedSizes[v]; |
} |
+ assert(retainedSizes[ROOT] == size); // Root retains everything. |
+ |
_retainedSizes = retainedSizes; |
_size = size; |
} |