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 object_graph; | |
6 | |
7 import 'dart:typed_data'; | |
8 | |
9 import 'dominator_tree.dart'; | |
10 | |
11 // Port of dart::ReadStream from vm/datastream.h. | |
12 class ReadStream { | |
13 int _cur = 0; | |
14 final ByteData _data; | |
15 | |
16 ReadStream(this._data); | |
17 | |
18 int get pendingBytes => _data.lengthInBytes - _cur; | |
19 | |
20 int readUnsigned() { | |
21 int result = 0; | |
22 int shift = 0; | |
23 while (_data.getUint8(_cur) <= maxUnsignedDataPerByte) { | |
24 result |= _data.getUint8(_cur) << shift; | |
25 shift += dataBitsPerByte; | |
26 ++_cur; | |
27 } | |
28 result |= (_data.getUint8(_cur) & byteMask) << shift; | |
29 ++_cur; | |
30 return result; | |
31 } | |
32 | |
33 static const int dataBitsPerByte = 7; | |
34 static const int byteMask = (1 << dataBitsPerByte) - 1; | |
35 static const int maxUnsignedDataPerByte = byteMask; | |
36 } | |
37 | |
38 class ObjectVertex { | |
39 // Never null. The isolate root has id 0. | |
40 final int _id; | |
41 // null for VM-heap objects. | |
42 int _shallowSize; | |
43 int get shallowSize => _shallowSize; | |
44 int _retainedSize; | |
45 int get retainedSize => _retainedSize; | |
46 // null for VM-heap objects. | |
47 int _classId; | |
48 int get classId => _classId; | |
49 final List<ObjectVertex> succ = new List<ObjectVertex>(); | |
50 ObjectVertex(this._id) : _retainedSize = 0; | |
51 String toString() => '$_id,$_shallowSize,$succ'; | |
52 } | |
53 | |
54 // See implementation of ObjectGraph::Serialize for format. | |
55 class ObjectGraph { | |
56 final Map<int, ObjectVertex> _idToVertex = new Map<int, ObjectVertex>(); | |
57 | |
58 ObjectVertex _asVertex(int id) { | |
59 return _idToVertex.putIfAbsent(id, () => new ObjectVertex(id)); | |
60 } | |
61 | |
62 void _addFrom(ReadStream stream) { | |
63 ObjectVertex obj = _asVertex(stream.readUnsigned()); | |
64 obj._shallowSize = stream.readUnsigned(); | |
65 obj._classId = stream.readUnsigned(); | |
66 int last = stream.readUnsigned(); | |
67 while (last != 0) { | |
68 obj.succ.add(_asVertex(last)); | |
69 last = stream.readUnsigned(); | |
70 } | |
71 } | |
72 | |
73 ObjectGraph(ReadStream reader) { | |
74 while (reader.pendingBytes > 0) { | |
75 _addFrom(reader); | |
76 } | |
77 _computeRetainedSizes(); | |
78 } | |
79 | |
80 Iterable<ObjectVertex> get vertices => _idToVertex.values; | |
81 | |
82 ObjectVertex get root => _asVertex(0); | |
83 | |
84 void _computeRetainedSizes() { | |
85 // The retained size for an object is the sum of the shallow sizes of | |
86 // all its descendants in the dominator tree (including itself). | |
87 var d = new Dominator(); | |
88 for (ObjectVertex u in vertices) { | |
89 if (u.shallowSize != null) { | |
90 u._retainedSize = u.shallowSize; | |
91 d.addEdges(u, u.succ.where((ObjectVertex v) => v.shallowSize != null)); | |
92 } | |
93 } | |
94 d.computeDominatorTree(root); | |
95 // Compute all retained sizes "bottom up", starting from the leaves. | |
96 // Keep track of number of remaining children of each vertex. | |
97 var degree = new Map<ObjectVertex, int>(); | |
98 for (ObjectVertex u in vertices) { | |
99 var v = d.dominator(u); | |
100 if (v != null) { | |
101 degree[v] = 1 + degree.putIfAbsent(v, () => 0); | |
102 } | |
103 } | |
104 var leaves = new List<ObjectVertex>(); | |
105 for (ObjectVertex u in vertices) { | |
106 if (!degree.containsKey(u)) { | |
107 leaves.add(u); | |
108 } | |
109 } | |
110 while (!leaves.isEmpty) { | |
111 var v = leaves.removeLast(); | |
112 var u = d.dominator(v); | |
113 if (u == null) continue; | |
114 u._retainedSize += v._retainedSize; | |
115 if (--degree[u] == 0) { | |
116 leaves.add(u); | |
117 } | |
118 } | |
119 } | |
120 } | |
OLD | NEW |