Chromium Code Reviews| 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 |