Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(624)

Side by Side Diff: runtime/observatory/lib/object_graph.dart

Issue 1449243002: Switch dominator algorithm from [1] to [2]. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 359 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 370
371 statusReporter.add("Remapping $_N objects..."); 371 statusReporter.add("Remapping $_N objects...");
372 await new Future(() => _remapNodes()); 372 await new Future(() => _remapNodes());
373 373
374 statusReporter.add("Remapping $_E references..."); 374 statusReporter.add("Remapping $_E references...");
375 await new Future(() => _remapEdges()); 375 await new Future(() => _remapEdges());
376 376
377 _addrToId = null; 377 _addrToId = null;
378 _chunks = null; 378 _chunks = null;
379 379
380 statusReporter.add("Finding post order..."); 380 statusReporter.add("Finding depth-first order...");
381 await new Future(() => _buildPostOrder()); 381 await new Future(() => _dfs());
382 382
383 statusReporter.add("Finding predecessors..."); 383 statusReporter.add("Finding predecessors...");
384 await new Future(() => _buildPredecessors()); 384 await new Future(() => _buildPredecessors());
385 385
386 statusReporter.add("Finding dominators..."); 386 statusReporter.add("Finding dominators...");
387 await new Future(() => _buildDominators()); 387 await new Future(() => _buildDominators());
388 388
389 _firstPreds = null; 389 _firstPreds = null;
390 _preds = null; 390 _preds = null;
391 _postOrderIndices = null; 391
392 _semi = null;
393 _parent = null;
392 394
393 statusReporter.add("Finding retained sizes..."); 395 statusReporter.add("Finding retained sizes...");
394 await new Future(() => _calculateRetainedSizes()); 396 await new Future(() => _calculateRetainedSizes());
395 397
396 _postOrderOrdinals = null; 398 _vertex = null;
397 399
398 statusReporter.add("Loaded"); 400 statusReporter.add("Loaded");
399 return this; 401 return this;
400 } 402 }
401 403
402 List<ByteData> _chunks; 404 List<ByteData> _chunks;
403 405
404 int _kObjectAlignment; 406 int _kObjectAlignment;
405 int _N; 407 int _N;
406 int _E; 408 int _E;
407 int _size; 409 int _size;
408 410
409 // Indexed by node id, with id 0 representing invalid/uninitialized. 411 // Indexed by node id, with id 0 representing invalid/uninitialized.
410 // From snapshot. 412 // From snapshot.
411 Uint16List _cids; 413 Uint16List _cids;
412 Uint32List _shallowSizes; 414 Uint32List _shallowSizes;
413 Uint32List _firstSuccs; 415 Uint32List _firstSuccs;
414 Uint32List _succs; 416 Uint32List _succs;
415 Uint32List _addressesLow; // No Uint64List in Javascript. 417 Uint32List _addressesLow; // No Uint64List in Javascript.
416 Uint32List _addressesHigh; 418 Uint32List _addressesHigh;
417 419
418 // Intermediates. 420 // Intermediates.
419 AddressMapper _addrToId; 421 AddressMapper _addrToId;
420 Uint32List _postOrderOrdinals; // post-order index -> id 422 Uint32List _vertex;
421 Uint32List _postOrderIndices; // id -> post-order index 423 Uint32List _parent;
424 Uint32List _semi;
422 Uint32List _firstPreds; // Offset into preds. 425 Uint32List _firstPreds; // Offset into preds.
423 Uint32List _preds; 426 Uint32List _preds;
424 427
425 // Outputs. 428 // Outputs.
426 Uint32List _doms; 429 Uint32List _doms;
427 Uint32List _retainedSizes; 430 Uint32List _retainedSizes;
428 431
429 void _remapNodes() { 432 void _remapNodes() {
430 var N = _N; 433 var N = _N;
431 var E = 0; 434 var E = 0;
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
507 510
508 assert(id == N + 1); 511 assert(id == N + 1);
509 assert(edge <= E); // edge is smaller because E was computed before we knew 512 assert(edge <= E); // edge is smaller because E was computed before we knew
510 // if references pointed into the VM isolate 513 // if references pointed into the VM isolate
511 514
512 _E = edge; 515 _E = edge;
513 _firstSuccs = firstSuccs; 516 _firstSuccs = firstSuccs;
514 _succs = succs; 517 _succs = succs;
515 } 518 }
516 519
517 void _buildPostOrder() { 520 void _dfs() {
518 var N = _N; 521 var N = _N;
519 var E = _E; 522 var E = _E;
520 var firstSuccs = _firstSuccs; 523 var firstSuccs = _firstSuccs;
521 var succs = _succs; 524 var succs = _succs;
522 525
523 var postOrderOrdinals = new Uint32List(N);
524 var postOrderIndices = new Uint32List(N + 1);
525 var stackNodes = new Uint32List(N); 526 var stackNodes = new Uint32List(N);
526 var stackCurrentEdgePos = new Uint32List(N); 527 var stackCurrentEdgePos = new Uint32List(N);
527 528
528 var visited = new Uint8List(N + 1); 529 var vertex = new Uint32List(N + 1);
529 var postOrderIndex = 0; 530 var semi = new Uint32List(N + 1);
531 var parent = new Uint32List(N + 1);
532 var dfsNumber = 0;
533
534 var dfsCount = 0;
530 var stackTop = 0; 535 var stackTop = 0;
531 var root = 1; 536 var root = 1;
532 537
538 // Push root.
533 stackNodes[0] = root; 539 stackNodes[0] = root;
534 stackCurrentEdgePos[0] = firstSuccs[root]; 540 stackCurrentEdgePos[0] = firstSuccs[root];
535 visited[root] = 1;
536 541
537 while (stackTop >= 0) { 542 while (stackTop >= 0) {
538 var n = stackNodes[stackTop]; 543 var v = stackNodes[stackTop];
539 var edgePos = stackCurrentEdgePos[stackTop]; 544 var edgePos = stackCurrentEdgePos[stackTop];
540 545
541 if (edgePos < firstSuccs[n + 1]) { 546 if (semi[v] == 0) {
547 // First visit.
548 dfsNumber++;
549 semi[v] = dfsNumber;
550 vertex[dfsNumber] = v;
551 }
552
553 if (edgePos < firstSuccs[v + 1]) {
542 var childId = succs[edgePos]; 554 var childId = succs[edgePos];
543 edgePos++; 555 edgePos++;
544 stackCurrentEdgePos[stackTop] = edgePos; 556 stackCurrentEdgePos[stackTop] = edgePos;
545 if (visited[childId] == 1) continue;
546 557
547 // Push child. 558 if (semi[childId] == 0) {
548 stackTop++; 559 parent[childId] = v;
549 stackNodes[stackTop] = childId; 560
550 edgePos = firstSuccs[childId]; 561 // Push child.
551 stackCurrentEdgePos[stackTop] = edgePos; 562 stackTop++;
552 visited[childId] = 1; 563 stackNodes[stackTop] = childId;
564 stackCurrentEdgePos[stackTop] = firstSuccs[childId];
565 }
553 } else { 566 } else {
554 // Done with all children. 567 // Done with all children.
555 postOrderIndices[n] = postOrderIndex;
556 postOrderOrdinals[postOrderIndex++] = n;
557 stackTop--; 568 stackTop--;
558 } 569 }
559 } 570 }
560 571
561 assert(postOrderIndex == N); 572 assert(dfsNumber == N);
562 assert(postOrderOrdinals[N - 1] == root); 573 for (var i = 1; i <= N; i++) {
574 assert(semi[i] != 0);
575 }
576 assert(parent[1] == 0);
577 for (var i = 2; i <= N; i++) {
578 assert(parent[i] != 0);
579 }
563 580
564 _postOrderOrdinals = postOrderOrdinals; 581 _vertex = vertex;
565 _postOrderIndices = postOrderIndices; 582 _semi = semi;
566 _E = E; 583 _parent = parent;
567 } 584 }
568 585
569 void _buildPredecessors() { 586 void _buildPredecessors() {
570 var N = _N; 587 var N = _N;
571 var E = _E; 588 var E = _E;
572 var firstSuccs = _firstSuccs; 589 var firstSuccs = _firstSuccs;
573 var succs = _succs; 590 var succs = _succs;
574 591
575 // This is first filled with the predecessor counts, then reused to hold the 592 // This is first filled with the predecessor counts, then reused to hold the
576 // offset to the first predecessor (see alias below). 593 // offset to the first predecessor (see alias below).
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 var succId = succs[succIndex]; 626 var succId = succs[succIndex];
610 var predIndex = nextPreds[succId]++; 627 var predIndex = nextPreds[succId]++;
611 preds[predIndex] = i; 628 preds[predIndex] = i;
612 } 629 }
613 } 630 }
614 631
615 _firstPreds = firstPreds; 632 _firstPreds = firstPreds;
616 _preds = preds; 633 _preds = preds;
617 } 634 }
618 635
619 // "A Simple, Fast Dominance Algorithm" 636 // static void _compress(int v,
620 // Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy 637 // Uint32List ancestor,
638 // Uint32List semi,
639 // Uint32List label) {
640 // assert(ancestor[v] != 0);
641 // if (ancestor[ancestor[v]] != 0) {
642 // _compress(ancestor[v], ancestor, semi, label);
643 // if (semi[label[ancestor[v]]] < semi[label[v]]) {
644 // label[v] = label[ancestor[v]];
645 // }
646 // ancestor[v] = ancestor[ancestor[v]];
647 // }
648 // }
Cutch 2015/11/17 18:40:09 Remove commented out code.
rmacnak 2015/11/17 19:20:24 Done.
649
650 // static int _eval(int v,
651 // Uint32List ancestor,
652 // Uint32List semi,
653 // Uint32List label) {
654 // if (ancestor[v] == 0) {
655 // return label[v];
656 // } else {
657 // _compress(v, ancestor, semi, label);
658 // if (semi[label[ancestor[v]]] >= semi[label[v]]) {
659 // return label[v];
660 // } else {
661 // return label[ancestor[v]];
662 // }
663 // }
664 // }
665
666 static int _eval(int v,
667 Uint32List ancestor,
668 Uint32List semi,
669 Uint32List label,
670 Uint32List stackNode,
671 Uint8List stackState) {
672 if (ancestor[v] == 0) {
673 return label[v];
674 } else {
675 {
676 // Inlined 'compress' with an explicit stack to prevent JS stack
677 // overflow.
678 var top = 0;
679 stackNode[top] = v;
680 stackState[top] = 0;
681 while (top >= 0) {
682 var v = stackNode[top];
683 var state = stackState[top];
684 if (state == 0) {
685 assert(ancestor[v] != 0);
686 if (ancestor[ancestor[v]] != 0) {
687 stackState[top] = 1;
688 // Recurse with ancestor[v]
689 top++;
690 stackNode[top] = ancestor[v];
691 stackState[top] = 0;
692 } else {
693 top--;
694 }
695 } else {
696 assert(state == 1);
697 if (semi[label[ancestor[v]]] < semi[label[v]]) {
698 label[v] = label[ancestor[v]];
699 }
700 ancestor[v] = ancestor[ancestor[v]];
701 top--;
702 }
703 }
704 }
705
706 if (semi[label[ancestor[v]]] >= semi[label[v]]) {
707 return label[v];
708 } else {
709 return label[ancestor[v]];
710 }
711 }
712 }
713
714 // Note the version in the main text of Lengauer & Tarjan incorrectly
715 // uses parent instead of ancestor. The correct version is in Appendix B.
716 static void _link(int v,
717 int w,
718 Uint32List size,
719 Uint32List label,
720 Uint32List semi,
721 Uint32List child,
722 Uint32List ancestor) {
723 assert(size[0] == 0);
724 assert(label[0] == 0);
725 assert(semi[0] == 0);
726 var s = w;
727 while (semi[label[w]] < semi[label[child[s]]]) {
728 if (size[s] + size[child[child[s]]] >= 2 * size[child[s]]) {
729 ancestor[child[s]] = s;
730 child[s] = child[child[s]];
731 } else {
732 size[child[s]] = size[s];
733 s = ancestor[s] = child[s];
734 }
735 }
736 label[s] = label[w];
737 size[v] = size[v] + size[w];
738 if (size[v] < 2 * size[w]) {
739 var tmp = s;
740 s = child[v];
741 child[v] = tmp;
742 }
743 while (s != 0) {
744 ancestor[s] = v;
745 s = child[s];
746 }
747 }
748
749 // T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators
750 // in a Flowgraph."
621 void _buildDominators() { 751 void _buildDominators() {
622 var N = _N; 752 var N = _N;
623 753
624 var postOrder = _postOrderOrdinals; 754 var vertex = _vertex;
625 var postOrderIndex = _postOrderIndices; 755 var semi = _semi;
756 var parent = _parent;
626 var firstPreds = _firstPreds; 757 var firstPreds = _firstPreds;
627 var preds = _preds; 758 var preds = _preds;
628 759
629 var root = 1; 760 var root = 1;
630 var rootPostOrderIndex = postOrderIndex[root]; 761 var dom = new Uint32List(N + 1);
631 var domByPOI = new Uint32List(N + 1);
632 762
633 domByPOI[rootPostOrderIndex] = rootPostOrderIndex; 763 var ancestor = new Uint32List(N + 1);
764 var label = new Uint32List(N + 1);
765 for (var i = 1; i <= N; i++) {
766 label[i] = i;
767 }
768 var buckets = new List(N + 1);
769 var child = new Uint32List(N + 1);
770 var size = new Uint32List(N + 1);
771 for (var i = 1; i <= N; i++) {
772 size[i] = 1;
773 }
774 var stackNode = new Uint32List(N + 1);
775 var stackState = new Uint8List(N + 1);
634 776
635 var iteration = 0; 777 for (var i = N; i > 1; i--) {
636 var changed = true; 778 var w = vertex[i];
637 while (changed) { 779 assert(w != root);
638 changed = false;
639 Logger.root.info("Find dominators iteration $iteration");
640 iteration++; // dart2js heaps typically converge in 10 iterations.
641 780
642 // Visit the nodes, except the root, in reverse post order (top down). 781 // Lengauer & Tarjan Step 2.
643 for (var curPostOrderIndex = rootPostOrderIndex - 1; 782 var startPred = firstPreds[w];
644 curPostOrderIndex > 1; 783 var limitPred = firstPreds[w + 1];
645 curPostOrderIndex--) { 784 for (var predIndex = startPred;
646 if (domByPOI[curPostOrderIndex] == rootPostOrderIndex) 785 predIndex < limitPred;
647 continue; 786 predIndex++) {
787 var v = preds[predIndex];
788 var u = _eval(v, ancestor, semi, label, stackNode, stackState);
789 if (semi[u] < semi[w]) {
790 semi[w] = semi[u];
791 }
792 }
648 793
649 var nodeOrdinal = postOrder[curPostOrderIndex]; 794 // w.semi.bucket.add(w);
650 var newDomIndex = 0; // 0 = undefined 795 var tmp = vertex[semi[w]];
796 if (buckets[tmp] == null) {
797 buckets[tmp] = new List();
798 }
799 buckets[tmp].add(w);
651 800
652 // Intersect the DOM sets of the node's precedessors. 801 _link(parent[w], w, size, label, semi, child, ancestor);
653 var beginPredIndex = firstPreds[nodeOrdinal]; 802
654 var endPredIndex = firstPreds[nodeOrdinal + 1]; 803 // Lengauer & Tarjan Step 3.
655 for (var predIndex = beginPredIndex; 804 tmp = parent[w];
656 predIndex < endPredIndex; 805 var bucket = buckets[tmp];
657 predIndex++) { 806 buckets[tmp] = null;
658 var predOrdinal = preds[predIndex]; 807 if (bucket != null) {
659 var predPostOrderIndex = postOrderIndex[predOrdinal]; 808 for (var v in bucket) {
660 if (domByPOI[predPostOrderIndex] != 0) { 809 var u = _eval(v, ancestor, semi, label, stackNode, stackState);
661 if (newDomIndex == 0) { 810 dom[v] = semi[u] < semi[v] ? u : parent[w];
662 newDomIndex = predPostOrderIndex;
663 } else {
664 // Note this two finger algorithm to find the DOM intersection
665 // relies on comparing nodes by their post order index.
666 while (predPostOrderIndex != newDomIndex) {
667 while(predPostOrderIndex < newDomIndex)
668 predPostOrderIndex = domByPOI[predPostOrderIndex];
669 while (newDomIndex < predPostOrderIndex)
670 newDomIndex = domByPOI[newDomIndex];
671 }
672 }
673 if (newDomIndex == rootPostOrderIndex) {
674 break;
675 }
676 }
677 }
678 if (newDomIndex != 0 && domByPOI[curPostOrderIndex] != newDomIndex) {
679 domByPOI[curPostOrderIndex] = newDomIndex;
680 changed = true;
681 } 811 }
682 } 812 }
683 } 813 }
684 814 for (var i = 1; i <= N; i++) {
685 Logger.root.info("Start remap dominators"); 815 assert(buckets[i] == null);
686 816 }
687 // Reindex doms by id instead of post order index so we can throw away 817 // Lengauer & Tarjan Step 4.
688 // the post order arrays. 818 for (var i = 2; i <= N; i++) {
689 var domById = new Uint32List(N + 1); 819 var w = vertex[i];
690 for (var id = 1; id <= N; id++) { 820 if (dom[w] != vertex[semi[w]]) {
691 domById[id] = postOrder[domByPOI[postOrderIndex[id]]]; 821 dom[w] = dom[dom[w]];
822 }
692 } 823 }
693 824
694 Logger.root.info("End remap dominators"); 825 _doms = dom;
695
696 domById[root] = 0;
697
698 _doms = domById;
699 } 826 }
700 827
701 void _calculateRetainedSizes() { 828 void _calculateRetainedSizes() {
702 var N = _N; 829 var N = _N;
703 830
704 var size = 0; 831 var size = 0;
705 var shallowSizes = _shallowSizes; 832 var shallowSizes = _shallowSizes;
706 var postOrderOrdinals = _postOrderOrdinals; 833 var vertex = _vertex;
707 var doms = _doms; 834 var doms = _doms;
708 835
709 // Sum shallow sizes. 836 // Sum shallow sizes.
710 for (var i = 1; i < N; i++) { 837 for (var i = 1; i < N; i++) {
711 size += shallowSizes[i]; 838 size += shallowSizes[i];
712 } 839 }
713 840
714 // Start with retained size as shallow size. 841 // Start with retained size as shallow size.
715 var retainedSizes = new Uint32List.fromList(shallowSizes); 842 var retainedSizes = new Uint32List.fromList(shallowSizes);
716 843
717 // In post order (bottom up), add retained size to dominator's retained 844 // In post order (bottom up), add retained size to dominator's retained
718 // size, skipping root. 845 // size, skipping root.
719 for (var o = 0; o < (N - 1); o++) { 846 for (var i = N; i > 1; i--) {
720 var i = postOrderOrdinals[o]; 847 var v = vertex[i];
721 assert(i != 1); 848 assert(v != 1);
722 retainedSizes[doms[i]] += retainedSizes[i]; 849 retainedSizes[doms[i]] += retainedSizes[i];
723 } 850 }
724 851
725 _retainedSizes = retainedSizes; 852 _retainedSizes = retainedSizes;
726 _size = size; 853 _size = size;
727 } 854 }
728 } 855 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698