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 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |