OLD | NEW |
---|---|
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library object_graph; | 5 library object_graph; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 import 'dart:typed_data'; | 9 import 'dart:typed_data'; |
10 | 10 |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 static const int dataBitsPerByte = 7; | 212 static const int dataBitsPerByte = 7; |
213 static const int byteMask = (1 << dataBitsPerByte) - 1; | 213 static const int byteMask = (1 << dataBitsPerByte) - 1; |
214 static const int maxUnsignedDataPerByte = byteMask; | 214 static const int maxUnsignedDataPerByte = byteMask; |
215 } | 215 } |
216 | 216 |
217 // Node indices for the root and sentinel nodes. Note that using 0 as the | 217 // Node indices for the root and sentinel nodes. Note that using 0 as the |
218 // sentinel means a newly allocated typed array comes initialized with all | 218 // sentinel means a newly allocated typed array comes initialized with all |
219 // elements as the sentinel. | 219 // elements as the sentinel. |
220 const ROOT = 1; | 220 const ROOT = 1; |
221 const SENTINEL = 0; | 221 const SENTINEL = 0; |
222 // Keep in sync with runtime/vm/object_graph.cc. | |
223 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
| |
222 | 224 |
223 class ObjectVertex { | 225 class ObjectVertex { |
224 final int _id; | 226 final int _id; |
225 final ObjectGraph _graph; | 227 final ObjectGraph _graph; |
226 | 228 |
227 ObjectVertex._(this._id, this._graph); | 229 ObjectVertex._(this._id, this._graph); |
228 | 230 |
229 bool get isRoot => ROOT == _id; | 231 bool get isRoot => ROOT == _id; |
232 bool get isStack => kStackCid == vmCid; | |
230 | 233 |
231 bool operator ==(other) => _id == other._id && _graph == other._graph; | 234 bool operator ==(other) => _id == other._id && _graph == other._graph; |
232 int get hashCode => _id; | 235 int get hashCode => _id; |
233 | 236 |
234 int get retainedSize => _graph._retainedSizes[_id]; | 237 int get retainedSize => _graph._retainedSizes[_id]; |
235 ObjectVertex get dominator => new ObjectVertex._(_graph._doms[_id], _graph); | 238 ObjectVertex get dominator => new ObjectVertex._(_graph._doms[_id], _graph); |
236 | 239 |
237 int get shallowSize => _graph._shallowSizes[_id]; | 240 int get shallowSize => _graph._shallowSizes[_id]; |
238 int get vmCid => _graph._cids[_id]; | 241 int get vmCid => _graph._cids[_id]; |
239 | 242 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
293 // object of this set. The other members of the set are found by walking the | 296 // object of this set. The other members of the set are found by walking the |
294 // mergedDomNext links until finding the sentinel node or a node with a | 297 // mergedDomNext links until finding the sentinel node or a node with a |
295 // different class. | 298 // different class. |
296 class MergedObjectVertex { | 299 class MergedObjectVertex { |
297 final int _id; | 300 final int _id; |
298 final ObjectGraph _graph; | 301 final ObjectGraph _graph; |
299 | 302 |
300 MergedObjectVertex._(this._id, this._graph); | 303 MergedObjectVertex._(this._id, this._graph); |
301 | 304 |
302 bool get isRoot => ROOT == _id; | 305 bool get isRoot => ROOT == _id; |
306 bool get isStack => kStackCid == vmCid; | |
303 | 307 |
304 bool operator ==(other) => _id == other._id && _graph == other._graph; | 308 bool operator ==(other) => _id == other._id && _graph == other._graph; |
305 int get hashCode => _id; | 309 int get hashCode => _id; |
306 | 310 |
307 int get vmCid => _graph._cids[_id]; | 311 int get vmCid => _graph._cids[_id]; |
308 | 312 |
309 int get shallowSize { | 313 int get shallowSize { |
310 var cids = _graph._cids; | 314 var cids = _graph._cids; |
311 var size = 0; | 315 var size = 0; |
312 var sibling = _id; | 316 var sibling = _id; |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
490 | 494 |
491 controller.add(["Processed", 100.0]); | 495 controller.add(["Processed", 100.0]); |
492 controller.close(); | 496 controller.close(); |
493 }()); | 497 }()); |
494 return controller.stream; | 498 return controller.stream; |
495 } | 499 } |
496 | 500 |
497 List<ByteData> _chunks; | 501 List<ByteData> _chunks; |
498 | 502 |
499 int _kObjectAlignment; | 503 int _kObjectAlignment; |
500 int _N; | 504 int _N; // Objects in the snapshot. |
501 int _E; | 505 int _Nconnected; // Objects reachable from root. |
506 int _E; // References in the snapshot. | |
502 int _size; | 507 int _size; |
503 | 508 |
504 // Indexed by node id, with id 0 representing invalid/uninitialized. | 509 // Indexed by node id, with id 0 representing invalid/uninitialized. |
505 // From snapshot. | 510 // From snapshot. |
506 Uint16List _cids; | 511 Uint16List _cids; |
507 Uint32List _shallowSizes; | 512 Uint32List _shallowSizes; |
508 Uint32List _firstSuccs; | 513 Uint32List _firstSuccs; |
509 Uint32List _succs; | 514 Uint32List _succs; |
510 Uint32List _addressesLow; // No Uint64List in Javascript. | 515 Uint32List _addressesLow; // No Uint64List in Javascript. |
511 Uint32List _addressesHigh; | 516 Uint32List _addressesHigh; |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
653 stackTop++; | 658 stackTop++; |
654 stackNodes[stackTop] = childId; | 659 stackNodes[stackTop] = childId; |
655 stackCurrentEdgePos[stackTop] = firstSuccs[childId]; | 660 stackCurrentEdgePos[stackTop] = firstSuccs[childId]; |
656 } | 661 } |
657 } else { | 662 } else { |
658 // Done with all children. | 663 // Done with all children. |
659 stackTop--; | 664 stackTop--; |
660 } | 665 } |
661 } | 666 } |
662 | 667 |
663 assert(dfsNumber == N); | 668 if (dfsNumber != N) { |
664 for (var i = ROOT; i <= N; i++) { | 669 // This may happen in filtered snapshots. |
665 assert(semi[i] != SENTINEL); | 670 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.
| |
666 } | |
667 assert(parent[ROOT] == SENTINEL); | |
668 for (var i = ROOT + 1; i <= N; i++) { | |
669 assert(parent[i] != SENTINEL); | |
670 } | 671 } |
671 | 672 |
673 for (var i = 1; i <= dfsNumber; i++) { | |
Cutch
2016/11/18 20:40:31
assert(() {
....
});
rmacnak
2016/11/18 22:34:02
Done.
| |
674 var v = vertex[i]; | |
675 assert(semi[v] != SENTINEL); | |
676 } | |
677 assert(parent[1] == SENTINEL); | |
678 for (var i = 2; i <= dfsNumber; i++) { | |
679 var v = vertex[i]; | |
680 assert(parent[v] != SENTINEL); | |
681 } | |
682 | |
683 if (dfsNumber != N) { | |
684 // Remove successors of unconnected nodes | |
685 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.
| |
686 if (parent[i] == SENTINEL) { | |
687 var startSuccIndex = firstSuccs[i]; | |
688 var limitSuccIndex = firstSuccs[i + 1]; | |
689 for (var succIndex = startSuccIndex; | |
690 succIndex < limitSuccIndex; | |
691 succIndex++) { | |
692 succs[succIndex] = SENTINEL; | |
693 } | |
694 } | |
695 } | |
696 } | |
697 | |
698 _Nconnected = dfsNumber; | |
672 _vertex = vertex; | 699 _vertex = vertex; |
673 _semi = semi; | 700 _semi = semi; |
674 _parent = parent; | 701 _parent = parent; |
675 } | 702 } |
676 | 703 |
677 void _buildPredecessors() { | 704 void _buildPredecessors() { |
678 var N = _N; | 705 var N = _N; |
706 var Nconnected = _Nconnected; | |
679 var E = _E; | 707 var E = _E; |
680 var firstSuccs = _firstSuccs; | 708 var firstSuccs = _firstSuccs; |
681 var succs = _succs; | 709 var succs = _succs; |
682 | 710 |
683 // This is first filled with the predecessor counts, then reused to hold the | 711 // This is first filled with the predecessor counts, then reused to hold the |
684 // offset to the first predecessor (see alias below). | 712 // offset to the first predecessor (see alias below). |
685 // + 1 because 0 is a sentinel | 713 // + 1 because 0 is a sentinel |
686 // + 1 so the number of predecessors can be found from the difference with | 714 // + 1 so the number of predecessors can be found from the difference with |
687 // the next node's offset. | 715 // the next node's offset. |
688 var numPreds = new Uint32List(N + 2); | 716 var numPreds = new Uint32List(N + 2); |
689 var preds = new Uint32List(E); | 717 var preds = new Uint32List(E); |
690 | 718 |
691 // Count predecessors of each node. | 719 // Count predecessors of each node. |
692 for (var succIndex = 0; succIndex < E; succIndex++) { | 720 for (var succIndex = 0; succIndex < E; succIndex++) { |
693 var succId = succs[succIndex]; | 721 var succId = succs[succIndex]; |
694 numPreds[succId]++; | 722 if (succId != SENTINEL) { |
723 numPreds[succId]++; | |
724 } | |
695 } | 725 } |
696 | 726 |
697 // Assign indices into predecessors array. | 727 // Assign indices into predecessors array. |
698 var firstPreds = numPreds; // Alias. | 728 var firstPreds = numPreds; // Alias. |
699 var nextPreds = new Uint32List(N + 1); | 729 var nextPreds = new Uint32List(N + 1); |
700 var predIndex = 0; | 730 var predIndex = 0; |
701 for (var i = 1; i <= N; i++) { | 731 for (var i = 1; i <= N; i++) { |
702 var thisPredIndex = predIndex; | 732 var thisPredIndex = predIndex; |
703 predIndex += numPreds[i]; | 733 predIndex += numPreds[i]; |
704 firstPreds[i] = thisPredIndex; | 734 firstPreds[i] = thisPredIndex; |
705 nextPreds[i] = thisPredIndex; | 735 nextPreds[i] = thisPredIndex; |
706 } | 736 } |
707 assert(predIndex == E); | 737 if (N == Nconnected) { |
708 firstPreds[N + 1] = E; // Extra entry for cheap boundary detection. | 738 assert(predIndex == E); |
739 } | |
740 firstPreds[N + 1] = predIndex; // Extra entry for cheap boundary detection. | |
709 | 741 |
710 // Fill predecessors array. | 742 // Fill predecessors array. |
711 for (var i = 1; i <= N; i++) { | 743 for (var i = 1; i <= N; i++) { |
712 var startSuccIndex = firstSuccs[i]; | 744 var startSuccIndex = firstSuccs[i]; |
713 var limitSuccIndex = firstSuccs[i + 1]; | 745 var limitSuccIndex = firstSuccs[i + 1]; |
714 for (var succIndex = startSuccIndex; | 746 for (var succIndex = startSuccIndex; |
715 succIndex < limitSuccIndex; | 747 succIndex < limitSuccIndex; |
716 succIndex++) { | 748 succIndex++) { |
717 var succId = succs[succIndex]; | 749 var succId = succs[succIndex]; |
718 var predIndex = nextPreds[succId]++; | 750 if (succId != SENTINEL) { |
719 preds[predIndex] = i; | 751 var predIndex = nextPreds[succId]++; |
752 preds[predIndex] = i; | |
753 } | |
720 } | 754 } |
721 } | 755 } |
722 | 756 |
723 _firstPreds = firstPreds; | 757 _firstPreds = firstPreds; |
724 _preds = preds; | 758 _preds = preds; |
725 } | 759 } |
726 | 760 |
727 static int _eval(int v, Uint32List ancestor, Uint32List semi, | 761 static int _eval(int v, Uint32List ancestor, Uint32List semi, |
728 Uint32List label, Uint32List stackNode, Uint8List stackState) { | 762 Uint32List label, Uint32List stackNode, Uint8List stackState) { |
729 if (ancestor[v] == SENTINEL) { | 763 if (ancestor[v] == SENTINEL) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
795 while (s != 0) { | 829 while (s != 0) { |
796 ancestor[s] = v; | 830 ancestor[s] = v; |
797 s = child[s]; | 831 s = child[s]; |
798 } | 832 } |
799 } | 833 } |
800 | 834 |
801 // T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators | 835 // T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators |
802 // in a Flowgraph." | 836 // in a Flowgraph." |
803 void _buildDominators() { | 837 void _buildDominators() { |
804 var N = _N; | 838 var N = _N; |
839 var Nconnected = _Nconnected; | |
805 | 840 |
806 var vertex = _vertex; | 841 var vertex = _vertex; |
807 var semi = _semi; | 842 var semi = _semi; |
808 var parent = _parent; | 843 var parent = _parent; |
809 var firstPreds = _firstPreds; | 844 var firstPreds = _firstPreds; |
810 var preds = _preds; | 845 var preds = _preds; |
811 | 846 |
812 var dom = new Uint32List(N + 1); | 847 var dom = new Uint32List(N + 1); |
813 | 848 |
814 var ancestor = new Uint32List(N + 1); | 849 var ancestor = new Uint32List(N + 1); |
815 var label = new Uint32List(N + 1); | 850 var label = new Uint32List(N + 1); |
816 for (var i = 1; i <= N; i++) { | 851 for (var i = 1; i <= N; i++) { |
817 label[i] = i; | 852 label[i] = i; |
818 } | 853 } |
819 var buckets = new List(N + 1); | 854 var buckets = new List(N + 1); |
820 var child = new Uint32List(N + 1); | 855 var child = new Uint32List(N + 1); |
821 var size = new Uint32List(N + 1); | 856 var size = new Uint32List(N + 1); |
822 for (var i = 1; i <= N; i++) { | 857 for (var i = 1; i <= N; i++) { |
823 size[i] = 1; | 858 size[i] = 1; |
824 } | 859 } |
825 var stackNode = new Uint32List(N + 1); | 860 var stackNode = new Uint32List(N + 1); |
826 var stackState = new Uint8List(N + 1); | 861 var stackState = new Uint8List(N + 1); |
827 | 862 |
828 for (var i = N; i > 1; i--) { | 863 for (var i = Nconnected; i > 1; i--) { |
829 var w = vertex[i]; | 864 var w = vertex[i]; |
830 assert(w != ROOT); | 865 assert(w != ROOT); |
831 | 866 |
832 // Lengauer & Tarjan Step 2. | 867 // Lengauer & Tarjan Step 2. |
833 var startPred = firstPreds[w]; | 868 var startPred = firstPreds[w]; |
834 var limitPred = firstPreds[w + 1]; | 869 var limitPred = firstPreds[w + 1]; |
835 for (var predIndex = startPred; predIndex < limitPred; predIndex++) { | 870 for (var predIndex = startPred; predIndex < limitPred; predIndex++) { |
836 var v = preds[predIndex]; | 871 var v = preds[predIndex]; |
837 var u = _eval(v, ancestor, semi, label, stackNode, stackState); | 872 var u = _eval(v, ancestor, semi, label, stackNode, stackState); |
838 if (semi[u] < semi[w]) { | 873 if (semi[u] < semi[w]) { |
(...skipping 18 matching lines...) Expand all Loading... | |
857 for (var v in bucket) { | 892 for (var v in bucket) { |
858 var u = _eval(v, ancestor, semi, label, stackNode, stackState); | 893 var u = _eval(v, ancestor, semi, label, stackNode, stackState); |
859 dom[v] = semi[u] < semi[v] ? u : parent[w]; | 894 dom[v] = semi[u] < semi[v] ? u : parent[w]; |
860 } | 895 } |
861 } | 896 } |
862 } | 897 } |
863 for (var i = ROOT; i <= N; i++) { | 898 for (var i = ROOT; i <= N; i++) { |
864 assert(buckets[i] == null); | 899 assert(buckets[i] == null); |
865 } | 900 } |
866 // Lengauer & Tarjan Step 4. | 901 // Lengauer & Tarjan Step 4. |
867 for (var i = 2; i <= N; i++) { | 902 for (var i = 2; i <= Nconnected; i++) { |
868 var w = vertex[i]; | 903 var w = vertex[i]; |
869 if (dom[w] != vertex[semi[w]]) { | 904 if (dom[w] != vertex[semi[w]]) { |
870 dom[w] = dom[dom[w]]; | 905 dom[w] = dom[dom[w]]; |
871 } | 906 } |
872 } | 907 } |
873 | 908 |
874 _doms = dom; | 909 _doms = dom; |
875 } | 910 } |
876 | 911 |
877 void _calculateRetainedSizes() { | 912 void _calculateRetainedSizes() { |
878 var N = _N; | 913 var N = _N; |
914 var Nconnected = _Nconnected; | |
879 | 915 |
880 var size = 0; | 916 var size = 0; |
881 var shallowSizes = _shallowSizes; | 917 var shallowSizes = _shallowSizes; |
882 var vertex = _vertex; | 918 var vertex = _vertex; |
883 var doms = _doms; | 919 var doms = _doms; |
884 | 920 |
885 // Sum shallow sizes. | 921 // Sum shallow sizes. |
886 for (var i = ROOT; i < N; i++) { | 922 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.
| |
887 size += shallowSizes[i]; | 923 var v = vertex[i]; |
924 size += shallowSizes[v]; | |
888 } | 925 } |
889 | 926 |
890 // Start with retained size as shallow size. | 927 // Start with retained size as shallow size. |
891 var retainedSizes = new Uint32List.fromList(shallowSizes); | 928 var retainedSizes = new Uint32List.fromList(shallowSizes); |
892 | 929 |
893 // In post order (bottom up), add retained size to dominator's retained | 930 // In post order (bottom up), add retained size to dominator's retained |
894 // size, skipping root. | 931 // size, skipping root. |
895 for (var i = N; i > 1; i--) { | 932 for (var i = Nconnected; i > 1; i--) { |
896 var v = vertex[i]; | 933 var v = vertex[i]; |
897 assert(v != ROOT); | 934 assert(v != ROOT); |
898 retainedSizes[doms[i]] += retainedSizes[i]; | 935 retainedSizes[doms[v]] += retainedSizes[v]; |
899 } | 936 } |
900 | 937 |
938 assert(retainedSizes[ROOT] == size); // Root retains everything. | |
939 | |
901 _retainedSizes = retainedSizes; | 940 _retainedSizes = retainedSizes; |
902 _size = size; | 941 _size = size; |
903 } | 942 } |
904 | 943 |
905 // Build linked lists of the children for each node in the dominator tree. | 944 // Build linked lists of the children for each node in the dominator tree. |
906 void _linkDominatorChildren() { | 945 void _linkDominatorChildren() { |
907 var N = _N; | 946 var N = _N; |
908 var doms = _doms; | 947 var doms = _doms; |
909 var head = new Uint32List(N + 1); | 948 var head = new Uint32List(N + 1); |
910 var next = new Uint32List(N + 1); | 949 var next = new Uint32List(N + 1); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1056 | 1095 |
1057 // From all the siblings between child and after, take their children, | 1096 // From all the siblings between child and after, take their children, |
1058 // merge them and given to child. | 1097 // merge them and given to child. |
1059 mergeChildrenAndSort(child, after); | 1098 mergeChildrenAndSort(child, after); |
1060 | 1099 |
1061 child = after; | 1100 child = after; |
1062 } | 1101 } |
1063 } | 1102 } |
1064 } | 1103 } |
1065 } | 1104 } |
OLD | NEW |