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 |
| 11 import 'package:logging/logging.dart'; |
| 12 |
11 class _JenkinsSmiHash { | 13 class _JenkinsSmiHash { |
12 static int combine(int hash, int value) { | 14 static int combine(int hash, int value) { |
13 hash = 0x1fffffff & (hash + value); | 15 hash = 0x1fffffff & (hash + value); |
14 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | 16 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); |
15 return hash ^ (hash >> 6); | 17 return hash ^ (hash >> 6); |
16 } | 18 } |
17 | 19 |
18 static int finish(int hash) { | 20 static int finish(int hash) { |
19 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | 21 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); |
20 hash = hash ^ (hash >> 11); | 22 hash = hash ^ (hash >> 11); |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 const ROOT = 1; | 222 const ROOT = 1; |
221 const SENTINEL = 0; | 223 const SENTINEL = 0; |
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 => vmCid == _graph._kStackCid; |
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 => vmCid == _graph._kStackCid; |
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 _kStackCid; |
501 int _E; | 505 int _N; // Objects in the snapshot. |
| 506 int _Nconnected; // Objects reachable from root. |
| 507 int _E; // References in the snapshot. |
502 int _size; | 508 int _size; |
503 | 509 |
504 // Indexed by node id, with id 0 representing invalid/uninitialized. | 510 // Indexed by node id, with id 0 representing invalid/uninitialized. |
505 // From snapshot. | 511 // From snapshot. |
506 Uint16List _cids; | 512 Uint16List _cids; |
507 Uint32List _shallowSizes; | 513 Uint32List _shallowSizes; |
508 Uint32List _firstSuccs; | 514 Uint32List _firstSuccs; |
509 Uint32List _succs; | 515 Uint32List _succs; |
510 Uint32List _addressesLow; // No Uint64List in Javascript. | 516 Uint32List _addressesLow; // No Uint64List in Javascript. |
511 Uint32List _addressesHigh; | 517 Uint32List _addressesHigh; |
(...skipping 18 matching lines...) Expand all Loading... |
530 var addrToId = new AddressMapper(N); | 536 var addrToId = new AddressMapper(N); |
531 | 537 |
532 var addressesHigh = new Uint32List(N + 1); | 538 var addressesHigh = new Uint32List(N + 1); |
533 var addressesLow = new Uint32List(N + 1); | 539 var addressesLow = new Uint32List(N + 1); |
534 var shallowSizes = new Uint32List(N + 1); | 540 var shallowSizes = new Uint32List(N + 1); |
535 var cids = new Uint16List(N + 1); | 541 var cids = new Uint16List(N + 1); |
536 | 542 |
537 var stream = new ReadStream(_chunks); | 543 var stream = new ReadStream(_chunks); |
538 stream.readUnsigned(); | 544 stream.readUnsigned(); |
539 _kObjectAlignment = stream.clampedUint32; | 545 _kObjectAlignment = stream.clampedUint32; |
| 546 stream.readUnsigned(); |
| 547 _kStackCid = stream.clampedUint32; |
540 | 548 |
541 var id = ROOT; | 549 var id = ROOT; |
542 while (stream.pendingBytes > 0) { | 550 while (stream.pendingBytes > 0) { |
543 stream.readUnsigned(); // addr | 551 stream.readUnsigned(); // addr |
544 addrToId.put(stream.high, stream.mid, stream.low, id); | 552 addrToId.put(stream.high, stream.mid, stream.low, id); |
545 addressesHigh[id] = stream.highUint32; | 553 addressesHigh[id] = stream.highUint32; |
546 addressesLow[id] = stream.lowUint32; | 554 addressesLow[id] = stream.lowUint32; |
547 stream.readUnsigned(); // shallowSize | 555 stream.readUnsigned(); // shallowSize |
548 shallowSizes[id] = stream.clampedUint32; | 556 shallowSizes[id] = stream.clampedUint32; |
549 stream.readUnsigned(); // cid | 557 stream.readUnsigned(); // cid |
(...skipping 20 matching lines...) Expand all Loading... |
570 | 578 |
571 void _remapEdges() { | 579 void _remapEdges() { |
572 var N = _N; | 580 var N = _N; |
573 var E = _E; | 581 var E = _E; |
574 var addrToId = _addrToId; | 582 var addrToId = _addrToId; |
575 | 583 |
576 var firstSuccs = new Uint32List(N + 2); | 584 var firstSuccs = new Uint32List(N + 2); |
577 var succs = new Uint32List(E); | 585 var succs = new Uint32List(E); |
578 | 586 |
579 var stream = new ReadStream(_chunks); | 587 var stream = new ReadStream(_chunks); |
580 stream.skipUnsigned(); // addr alignment | 588 stream.skipUnsigned(); // kObjectAlignment |
| 589 stream.skipUnsigned(); // kStackCid |
581 | 590 |
582 var id = 1, edge = 0; | 591 var id = 1, edge = 0; |
583 while (stream.pendingBytes > 0) { | 592 while (stream.pendingBytes > 0) { |
584 stream.skipUnsigned(); // addr | 593 stream.skipUnsigned(); // addr |
585 stream.skipUnsigned(); // shallowSize | 594 stream.skipUnsigned(); // shallowSize |
586 stream.skipUnsigned(); // cid | 595 stream.skipUnsigned(); // cid |
587 | 596 |
588 firstSuccs[id] = edge; | 597 firstSuccs[id] = edge; |
589 | 598 |
590 stream.readUnsigned(); | 599 stream.readUnsigned(); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 stackTop++; | 662 stackTop++; |
654 stackNodes[stackTop] = childId; | 663 stackNodes[stackTop] = childId; |
655 stackCurrentEdgePos[stackTop] = firstSuccs[childId]; | 664 stackCurrentEdgePos[stackTop] = firstSuccs[childId]; |
656 } | 665 } |
657 } else { | 666 } else { |
658 // Done with all children. | 667 // Done with all children. |
659 stackTop--; | 668 stackTop--; |
660 } | 669 } |
661 } | 670 } |
662 | 671 |
663 assert(dfsNumber == N); | 672 if (dfsNumber != N) { |
664 for (var i = ROOT; i <= N; i++) { | 673 // This may happen in filtered snapshots. |
665 assert(semi[i] != SENTINEL); | 674 Logger.root.warning('Heap snapshot contains unreachable nodes.'); |
666 } | |
667 assert(parent[ROOT] == SENTINEL); | |
668 for (var i = ROOT + 1; i <= N; i++) { | |
669 assert(parent[i] != SENTINEL); | |
670 } | 675 } |
671 | 676 |
| 677 assert(() { |
| 678 for (var i = 1; i <= dfsNumber; i++) { |
| 679 var v = vertex[i]; |
| 680 assert(semi[v] != SENTINEL); |
| 681 } |
| 682 assert(parent[1] == SENTINEL); |
| 683 for (var i = 2; i <= dfsNumber; i++) { |
| 684 var v = vertex[i]; |
| 685 assert(parent[v] != SENTINEL); |
| 686 } |
| 687 return true; |
| 688 }); |
| 689 |
| 690 if (dfsNumber != N) { |
| 691 // Remove successors of unconnected nodes |
| 692 for (var i = ROOT + 1; i <= N; i++) { |
| 693 if (parent[i] == SENTINEL) { |
| 694 var startSuccIndex = firstSuccs[i]; |
| 695 var limitSuccIndex = firstSuccs[i + 1]; |
| 696 for (var succIndex = startSuccIndex; |
| 697 succIndex < limitSuccIndex; |
| 698 succIndex++) { |
| 699 succs[succIndex] = SENTINEL; |
| 700 } |
| 701 } |
| 702 } |
| 703 } |
| 704 |
| 705 _Nconnected = dfsNumber; |
672 _vertex = vertex; | 706 _vertex = vertex; |
673 _semi = semi; | 707 _semi = semi; |
674 _parent = parent; | 708 _parent = parent; |
675 } | 709 } |
676 | 710 |
677 void _buildPredecessors() { | 711 void _buildPredecessors() { |
678 var N = _N; | 712 var N = _N; |
| 713 var Nconnected = _Nconnected; |
679 var E = _E; | 714 var E = _E; |
680 var firstSuccs = _firstSuccs; | 715 var firstSuccs = _firstSuccs; |
681 var succs = _succs; | 716 var succs = _succs; |
682 | 717 |
683 // This is first filled with the predecessor counts, then reused to hold the | 718 // This is first filled with the predecessor counts, then reused to hold the |
684 // offset to the first predecessor (see alias below). | 719 // offset to the first predecessor (see alias below). |
685 // + 1 because 0 is a sentinel | 720 // + 1 because 0 is a sentinel |
686 // + 1 so the number of predecessors can be found from the difference with | 721 // + 1 so the number of predecessors can be found from the difference with |
687 // the next node's offset. | 722 // the next node's offset. |
688 var numPreds = new Uint32List(N + 2); | 723 var numPreds = new Uint32List(N + 2); |
689 var preds = new Uint32List(E); | 724 var preds = new Uint32List(E); |
690 | 725 |
691 // Count predecessors of each node. | 726 // Count predecessors of each node. |
692 for (var succIndex = 0; succIndex < E; succIndex++) { | 727 for (var succIndex = 0; succIndex < E; succIndex++) { |
693 var succId = succs[succIndex]; | 728 var succId = succs[succIndex]; |
694 numPreds[succId]++; | 729 if (succId != SENTINEL) { |
| 730 numPreds[succId]++; |
| 731 } |
695 } | 732 } |
696 | 733 |
697 // Assign indices into predecessors array. | 734 // Assign indices into predecessors array. |
698 var firstPreds = numPreds; // Alias. | 735 var firstPreds = numPreds; // Alias. |
699 var nextPreds = new Uint32List(N + 1); | 736 var nextPreds = new Uint32List(N + 1); |
700 var predIndex = 0; | 737 var predIndex = 0; |
701 for (var i = 1; i <= N; i++) { | 738 for (var i = 1; i <= N; i++) { |
702 var thisPredIndex = predIndex; | 739 var thisPredIndex = predIndex; |
703 predIndex += numPreds[i]; | 740 predIndex += numPreds[i]; |
704 firstPreds[i] = thisPredIndex; | 741 firstPreds[i] = thisPredIndex; |
705 nextPreds[i] = thisPredIndex; | 742 nextPreds[i] = thisPredIndex; |
706 } | 743 } |
707 assert(predIndex == E); | 744 if (N == Nconnected) { |
708 firstPreds[N + 1] = E; // Extra entry for cheap boundary detection. | 745 assert(predIndex == E); |
| 746 } |
| 747 firstPreds[N + 1] = predIndex; // Extra entry for cheap boundary detection. |
709 | 748 |
710 // Fill predecessors array. | 749 // Fill predecessors array. |
711 for (var i = 1; i <= N; i++) { | 750 for (var i = 1; i <= N; i++) { |
712 var startSuccIndex = firstSuccs[i]; | 751 var startSuccIndex = firstSuccs[i]; |
713 var limitSuccIndex = firstSuccs[i + 1]; | 752 var limitSuccIndex = firstSuccs[i + 1]; |
714 for (var succIndex = startSuccIndex; | 753 for (var succIndex = startSuccIndex; |
715 succIndex < limitSuccIndex; | 754 succIndex < limitSuccIndex; |
716 succIndex++) { | 755 succIndex++) { |
717 var succId = succs[succIndex]; | 756 var succId = succs[succIndex]; |
718 var predIndex = nextPreds[succId]++; | 757 if (succId != SENTINEL) { |
719 preds[predIndex] = i; | 758 var predIndex = nextPreds[succId]++; |
| 759 preds[predIndex] = i; |
| 760 } |
720 } | 761 } |
721 } | 762 } |
722 | 763 |
723 _firstPreds = firstPreds; | 764 _firstPreds = firstPreds; |
724 _preds = preds; | 765 _preds = preds; |
725 } | 766 } |
726 | 767 |
727 static int _eval(int v, Uint32List ancestor, Uint32List semi, | 768 static int _eval(int v, Uint32List ancestor, Uint32List semi, |
728 Uint32List label, Uint32List stackNode, Uint8List stackState) { | 769 Uint32List label, Uint32List stackNode, Uint8List stackState) { |
729 if (ancestor[v] == SENTINEL) { | 770 if (ancestor[v] == SENTINEL) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
795 while (s != 0) { | 836 while (s != 0) { |
796 ancestor[s] = v; | 837 ancestor[s] = v; |
797 s = child[s]; | 838 s = child[s]; |
798 } | 839 } |
799 } | 840 } |
800 | 841 |
801 // T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators | 842 // T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators |
802 // in a Flowgraph." | 843 // in a Flowgraph." |
803 void _buildDominators() { | 844 void _buildDominators() { |
804 var N = _N; | 845 var N = _N; |
| 846 var Nconnected = _Nconnected; |
805 | 847 |
806 var vertex = _vertex; | 848 var vertex = _vertex; |
807 var semi = _semi; | 849 var semi = _semi; |
808 var parent = _parent; | 850 var parent = _parent; |
809 var firstPreds = _firstPreds; | 851 var firstPreds = _firstPreds; |
810 var preds = _preds; | 852 var preds = _preds; |
811 | 853 |
812 var dom = new Uint32List(N + 1); | 854 var dom = new Uint32List(N + 1); |
813 | 855 |
814 var ancestor = new Uint32List(N + 1); | 856 var ancestor = new Uint32List(N + 1); |
815 var label = new Uint32List(N + 1); | 857 var label = new Uint32List(N + 1); |
816 for (var i = 1; i <= N; i++) { | 858 for (var i = 1; i <= N; i++) { |
817 label[i] = i; | 859 label[i] = i; |
818 } | 860 } |
819 var buckets = new List(N + 1); | 861 var buckets = new List(N + 1); |
820 var child = new Uint32List(N + 1); | 862 var child = new Uint32List(N + 1); |
821 var size = new Uint32List(N + 1); | 863 var size = new Uint32List(N + 1); |
822 for (var i = 1; i <= N; i++) { | 864 for (var i = 1; i <= N; i++) { |
823 size[i] = 1; | 865 size[i] = 1; |
824 } | 866 } |
825 var stackNode = new Uint32List(N + 1); | 867 var stackNode = new Uint32List(N + 1); |
826 var stackState = new Uint8List(N + 1); | 868 var stackState = new Uint8List(N + 1); |
827 | 869 |
828 for (var i = N; i > 1; i--) { | 870 for (var i = Nconnected; i > 1; i--) { |
829 var w = vertex[i]; | 871 var w = vertex[i]; |
830 assert(w != ROOT); | 872 assert(w != ROOT); |
831 | 873 |
832 // Lengauer & Tarjan Step 2. | 874 // Lengauer & Tarjan Step 2. |
833 var startPred = firstPreds[w]; | 875 var startPred = firstPreds[w]; |
834 var limitPred = firstPreds[w + 1]; | 876 var limitPred = firstPreds[w + 1]; |
835 for (var predIndex = startPred; predIndex < limitPred; predIndex++) { | 877 for (var predIndex = startPred; predIndex < limitPred; predIndex++) { |
836 var v = preds[predIndex]; | 878 var v = preds[predIndex]; |
837 var u = _eval(v, ancestor, semi, label, stackNode, stackState); | 879 var u = _eval(v, ancestor, semi, label, stackNode, stackState); |
838 if (semi[u] < semi[w]) { | 880 if (semi[u] < semi[w]) { |
(...skipping 18 matching lines...) Expand all Loading... |
857 for (var v in bucket) { | 899 for (var v in bucket) { |
858 var u = _eval(v, ancestor, semi, label, stackNode, stackState); | 900 var u = _eval(v, ancestor, semi, label, stackNode, stackState); |
859 dom[v] = semi[u] < semi[v] ? u : parent[w]; | 901 dom[v] = semi[u] < semi[v] ? u : parent[w]; |
860 } | 902 } |
861 } | 903 } |
862 } | 904 } |
863 for (var i = ROOT; i <= N; i++) { | 905 for (var i = ROOT; i <= N; i++) { |
864 assert(buckets[i] == null); | 906 assert(buckets[i] == null); |
865 } | 907 } |
866 // Lengauer & Tarjan Step 4. | 908 // Lengauer & Tarjan Step 4. |
867 for (var i = 2; i <= N; i++) { | 909 for (var i = 2; i <= Nconnected; i++) { |
868 var w = vertex[i]; | 910 var w = vertex[i]; |
869 if (dom[w] != vertex[semi[w]]) { | 911 if (dom[w] != vertex[semi[w]]) { |
870 dom[w] = dom[dom[w]]; | 912 dom[w] = dom[dom[w]]; |
871 } | 913 } |
872 } | 914 } |
873 | 915 |
874 _doms = dom; | 916 _doms = dom; |
875 } | 917 } |
876 | 918 |
877 void _calculateRetainedSizes() { | 919 void _calculateRetainedSizes() { |
878 var N = _N; | 920 var N = _N; |
| 921 var Nconnected = _Nconnected; |
879 | 922 |
880 var size = 0; | 923 var size = 0; |
881 var shallowSizes = _shallowSizes; | 924 var shallowSizes = _shallowSizes; |
882 var vertex = _vertex; | 925 var vertex = _vertex; |
883 var doms = _doms; | 926 var doms = _doms; |
884 | 927 |
885 // Sum shallow sizes. | 928 // Sum shallow sizes. |
886 for (var i = ROOT; i < N; i++) { | 929 for (var i = 1; i <= Nconnected; i++) { |
887 size += shallowSizes[i]; | 930 var v = vertex[i]; |
| 931 size += shallowSizes[v]; |
888 } | 932 } |
889 | 933 |
890 // Start with retained size as shallow size. | 934 // Start with retained size as shallow size. |
891 var retainedSizes = new Uint32List.fromList(shallowSizes); | 935 var retainedSizes = new Uint32List.fromList(shallowSizes); |
892 | 936 |
893 // In post order (bottom up), add retained size to dominator's retained | 937 // In post order (bottom up), add retained size to dominator's retained |
894 // size, skipping root. | 938 // size, skipping root. |
895 for (var i = N; i > 1; i--) { | 939 for (var i = Nconnected; i > 1; i--) { |
896 var v = vertex[i]; | 940 var v = vertex[i]; |
897 assert(v != ROOT); | 941 assert(v != ROOT); |
898 retainedSizes[doms[i]] += retainedSizes[i]; | 942 retainedSizes[doms[v]] += retainedSizes[v]; |
899 } | 943 } |
900 | 944 |
| 945 assert(retainedSizes[ROOT] == size); // Root retains everything. |
| 946 |
901 _retainedSizes = retainedSizes; | 947 _retainedSizes = retainedSizes; |
902 _size = size; | 948 _size = size; |
903 } | 949 } |
904 | 950 |
905 // Build linked lists of the children for each node in the dominator tree. | 951 // Build linked lists of the children for each node in the dominator tree. |
906 void _linkDominatorChildren() { | 952 void _linkDominatorChildren() { |
907 var N = _N; | 953 var N = _N; |
908 var doms = _doms; | 954 var doms = _doms; |
909 var head = new Uint32List(N + 1); | 955 var head = new Uint32List(N + 1); |
910 var next = new Uint32List(N + 1); | 956 var next = new Uint32List(N + 1); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1056 | 1102 |
1057 // From all the siblings between child and after, take their children, | 1103 // From all the siblings between child and after, take their children, |
1058 // merge them and given to child. | 1104 // merge them and given to child. |
1059 mergeChildrenAndSort(child, after); | 1105 mergeChildrenAndSort(child, after); |
1060 | 1106 |
1061 child = after; | 1107 child = after; |
1062 } | 1108 } |
1063 } | 1109 } |
1064 } | 1110 } |
1065 } | 1111 } |
OLD | NEW |