| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 #include "vm/gc_marker.h" | 5 #include "vm/gc_marker.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 | 492 |
| 493 void GCMarker::Epilogue(Isolate* isolate, bool invoke_api_callbacks) { | 493 void GCMarker::Epilogue(Isolate* isolate, bool invoke_api_callbacks) { |
| 494 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { | 494 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { |
| 495 (isolate->gc_epilogue_callback())(); | 495 (isolate->gc_epilogue_callback())(); |
| 496 } | 496 } |
| 497 } | 497 } |
| 498 | 498 |
| 499 | 499 |
| 500 void GCMarker::IterateRoots(Isolate* isolate, | 500 void GCMarker::IterateRoots(Isolate* isolate, |
| 501 ObjectPointerVisitor* visitor, | 501 ObjectPointerVisitor* visitor, |
| 502 bool visit_prologue_weak_persistent_handles, | |
| 503 intptr_t slice_index, intptr_t num_slices) { | 502 intptr_t slice_index, intptr_t num_slices) { |
| 504 ASSERT(0 <= slice_index && slice_index < num_slices); | 503 ASSERT(0 <= slice_index && slice_index < num_slices); |
| 505 if ((slice_index == 0) || (num_slices <= 1)) { | 504 if ((slice_index == 0) || (num_slices <= 1)) { |
| 506 isolate->VisitObjectPointers(visitor, | 505 isolate->VisitObjectPointers(visitor, |
| 507 visit_prologue_weak_persistent_handles, | |
| 508 StackFrameIterator::kDontValidateFrames); | 506 StackFrameIterator::kDontValidateFrames); |
| 509 } | 507 } |
| 510 if ((slice_index == 1) || (num_slices <= 1)) { | 508 if ((slice_index == 1) || (num_slices <= 1)) { |
| 511 heap_->new_space()->VisitObjectPointers(visitor); | 509 heap_->new_space()->VisitObjectPointers(visitor); |
| 512 } | 510 } |
| 513 | 511 |
| 514 // For now, we just distinguish two parts of the root set, so any remaining | 512 // For now, we just distinguish two parts of the root set, so any remaining |
| 515 // slices are empty. | 513 // slices are empty. |
| 516 } | 514 } |
| 517 | 515 |
| 518 | 516 |
| 519 void GCMarker::IterateWeakRoots(Isolate* isolate, | 517 void GCMarker::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) { |
| 520 HandleVisitor* visitor, | |
| 521 bool visit_prologue_weak_persistent_handles) { | |
| 522 ApiState* state = isolate->api_state(); | 518 ApiState* state = isolate->api_state(); |
| 523 ASSERT(state != NULL); | 519 ASSERT(state != NULL); |
| 524 isolate->VisitWeakPersistentHandles(visitor, | 520 isolate->VisitWeakPersistentHandles(visitor); |
| 525 visit_prologue_weak_persistent_handles); | |
| 526 } | 521 } |
| 527 | 522 |
| 528 | 523 |
| 529 template<class MarkingVisitorType> | |
| 530 void GCMarker::IterateWeakReferences(Isolate* isolate, | |
| 531 MarkingVisitorType* visitor) { | |
| 532 ApiState* state = isolate->api_state(); | |
| 533 ASSERT(state != NULL); | |
| 534 while (true) { | |
| 535 WeakReferenceSet* queue = state->delayed_weak_reference_sets(); | |
| 536 if (queue == NULL) { | |
| 537 // The delay queue is empty therefore no clean-up is required. | |
| 538 return; | |
| 539 } | |
| 540 state->set_delayed_weak_reference_sets(NULL); | |
| 541 while (queue != NULL) { | |
| 542 WeakReferenceSet* reference_set = WeakReferenceSet::Pop(&queue); | |
| 543 ASSERT(reference_set != NULL); | |
| 544 intptr_t num_keys = reference_set->num_keys(); | |
| 545 intptr_t num_values = reference_set->num_values(); | |
| 546 if ((num_keys == 1) && (num_values == 1) && | |
| 547 reference_set->SingletonKeyEqualsValue()) { | |
| 548 // We do not have to process sets that have just one key/value pair | |
| 549 // and the key and value are identical. | |
| 550 continue; | |
| 551 } | |
| 552 bool is_unreachable = true; | |
| 553 // Test each key object for reachability. If a key object is | |
| 554 // reachable, all value objects should be marked. | |
| 555 for (intptr_t k = 0; k < num_keys; ++k) { | |
| 556 if (!IsUnreachable(*reference_set->get_key(k))) { | |
| 557 for (intptr_t v = 0; v < num_values; ++v) { | |
| 558 visitor->VisitPointer(reference_set->get_value(v)); | |
| 559 } | |
| 560 is_unreachable = false; | |
| 561 // Since we have found a key object that is reachable and all | |
| 562 // value objects have been marked we can break out of iterating | |
| 563 // this set and move on to the next set. | |
| 564 break; | |
| 565 } | |
| 566 } | |
| 567 // If all key objects are unreachable put the reference on a | |
| 568 // delay queue. This reference will be revisited if another | |
| 569 // reference is marked. | |
| 570 if (is_unreachable) { | |
| 571 state->DelayWeakReferenceSet(reference_set); | |
| 572 } | |
| 573 } | |
| 574 if (!visitor->DrainMarkingStack()) { | |
| 575 // Break out of the loop if there has been no forward process. | |
| 576 // All key objects in the weak reference sets are unreachable | |
| 577 // so we reset the weak reference sets queue. | |
| 578 state->set_delayed_weak_reference_sets(NULL); | |
| 579 break; | |
| 580 } | |
| 581 } | |
| 582 ASSERT(state->delayed_weak_reference_sets() == NULL); | |
| 583 // All weak reference sets are zone allocated and unmarked references which | |
| 584 // were on the delay queue will be freed when the zone is released in the | |
| 585 // epilog callback. | |
| 586 } | |
| 587 | |
| 588 | |
| 589 void GCMarker::ProcessWeakTables(PageSpace* page_space) { | 524 void GCMarker::ProcessWeakTables(PageSpace* page_space) { |
| 590 for (int sel = 0; | 525 for (int sel = 0; |
| 591 sel < Heap::kNumWeakSelectors; | 526 sel < Heap::kNumWeakSelectors; |
| 592 sel++) { | 527 sel++) { |
| 593 WeakTable* table = heap_->GetWeakTable( | 528 WeakTable* table = heap_->GetWeakTable( |
| 594 Heap::kOld, static_cast<Heap::WeakSelector>(sel)); | 529 Heap::kOld, static_cast<Heap::WeakSelector>(sel)); |
| 595 intptr_t size = table->size(); | 530 intptr_t size = table->size(); |
| 596 for (intptr_t i = 0; i < size; i++) { | 531 for (intptr_t i = 0; i < size; i++) { |
| 597 if (table->IsValidEntryAt(i)) { | 532 if (table->IsValidEntryAt(i)) { |
| 598 RawObject* raw_obj = table->ObjectAt(i); | 533 RawObject* raw_obj = table->ObjectAt(i); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 636 class MarkTask : public ThreadPool::Task { | 571 class MarkTask : public ThreadPool::Task { |
| 637 public: | 572 public: |
| 638 MarkTask(GCMarker* marker, | 573 MarkTask(GCMarker* marker, |
| 639 Isolate* isolate, | 574 Isolate* isolate, |
| 640 Heap* heap, | 575 Heap* heap, |
| 641 PageSpace* page_space, | 576 PageSpace* page_space, |
| 642 MarkingStack* marking_stack, | 577 MarkingStack* marking_stack, |
| 643 DelaySet* delay_set, | 578 DelaySet* delay_set, |
| 644 ThreadBarrier* barrier, | 579 ThreadBarrier* barrier, |
| 645 bool collect_code, | 580 bool collect_code, |
| 646 bool visit_prologue_weak_persistent_handles, | |
| 647 intptr_t task_index, | 581 intptr_t task_index, |
| 648 intptr_t num_tasks, | 582 intptr_t num_tasks, |
| 649 uintptr_t* num_busy) | 583 uintptr_t* num_busy) |
| 650 : marker_(marker), | 584 : marker_(marker), |
| 651 isolate_(isolate), | 585 isolate_(isolate), |
| 652 heap_(heap), | 586 heap_(heap), |
| 653 page_space_(page_space), | 587 page_space_(page_space), |
| 654 marking_stack_(marking_stack), | 588 marking_stack_(marking_stack), |
| 655 delay_set_(delay_set), | 589 delay_set_(delay_set), |
| 656 barrier_(barrier), | 590 barrier_(barrier), |
| 657 collect_code_(collect_code), | 591 collect_code_(collect_code), |
| 658 visit_prologue_weak_persistent_handles_( | |
| 659 visit_prologue_weak_persistent_handles), | |
| 660 task_index_(task_index), | 592 task_index_(task_index), |
| 661 num_tasks_(num_tasks), | 593 num_tasks_(num_tasks), |
| 662 num_busy_(num_busy) { | 594 num_busy_(num_busy) { |
| 663 } | 595 } |
| 664 | 596 |
| 665 virtual void Run() { | 597 virtual void Run() { |
| 666 Thread::EnterIsolateAsHelper(isolate_, true); | 598 Thread::EnterIsolateAsHelper(isolate_, true); |
| 667 { | 599 { |
| 668 StackZone stack_zone(Thread::Current()); | 600 StackZone stack_zone(Thread::Current()); |
| 669 Zone* zone = stack_zone.GetZone(); | 601 Zone* zone = stack_zone.GetZone(); |
| 670 SkippedCodeFunctions* skipped_code_functions = | 602 SkippedCodeFunctions* skipped_code_functions = |
| 671 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL; | 603 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL; |
| 672 SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_, | 604 SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_, |
| 673 delay_set_, skipped_code_functions); | 605 delay_set_, skipped_code_functions); |
| 674 // Phase 1: Iterate over roots and drain marking stack in tasks. | 606 // Phase 1: Iterate over roots and drain marking stack in tasks. |
| 675 marker_->IterateRoots(isolate_, &visitor, | 607 marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_); |
| 676 visit_prologue_weak_persistent_handles_, | |
| 677 task_index_, num_tasks_); | |
| 678 do { | 608 do { |
| 679 visitor.DrainMarkingStack(); | 609 visitor.DrainMarkingStack(); |
| 680 | 610 |
| 681 // I can't find more work right now. If no other task is busy, | 611 // I can't find more work right now. If no other task is busy, |
| 682 // then there will never be more work (NB: 1 is *before* decrement). | 612 // then there will never be more work (NB: 1 is *before* decrement). |
| 683 if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break; | 613 if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break; |
| 684 | 614 |
| 685 // Wait for some work to appear. | 615 // Wait for some work to appear. |
| 686 // TODO(iposva): Replace busy-waiting with a solution using Monitor, | 616 // TODO(iposva): Replace busy-waiting with a solution using Monitor, |
| 687 // and redraw the boundaries between stack/visitor/task as needed. | 617 // and redraw the boundaries between stack/visitor/task as needed. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 716 | 646 |
| 717 private: | 647 private: |
| 718 GCMarker* marker_; | 648 GCMarker* marker_; |
| 719 Isolate* isolate_; | 649 Isolate* isolate_; |
| 720 Heap* heap_; | 650 Heap* heap_; |
| 721 PageSpace* page_space_; | 651 PageSpace* page_space_; |
| 722 MarkingStack* marking_stack_; | 652 MarkingStack* marking_stack_; |
| 723 DelaySet* delay_set_; | 653 DelaySet* delay_set_; |
| 724 ThreadBarrier* barrier_; | 654 ThreadBarrier* barrier_; |
| 725 bool collect_code_; | 655 bool collect_code_; |
| 726 bool visit_prologue_weak_persistent_handles_; | |
| 727 const intptr_t task_index_; | 656 const intptr_t task_index_; |
| 728 const intptr_t num_tasks_; | 657 const intptr_t num_tasks_; |
| 729 uintptr_t* num_busy_; | 658 uintptr_t* num_busy_; |
| 730 | 659 |
| 731 DISALLOW_COPY_AND_ASSIGN(MarkTask); | 660 DISALLOW_COPY_AND_ASSIGN(MarkTask); |
| 732 }; | 661 }; |
| 733 | 662 |
| 734 | 663 |
| 735 template<class MarkingVisitorType> | 664 template<class MarkingVisitorType> |
| 736 void GCMarker::FinalizeResultsFrom(MarkingVisitorType* visitor) { | 665 void GCMarker::FinalizeResultsFrom(MarkingVisitorType* visitor) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 757 bool invoke_api_callbacks, | 686 bool invoke_api_callbacks, |
| 758 bool collect_code) { | 687 bool collect_code) { |
| 759 Prologue(isolate, invoke_api_callbacks); | 688 Prologue(isolate, invoke_api_callbacks); |
| 760 // The API prologue/epilogue may create/destroy zones, so we must not | 689 // The API prologue/epilogue may create/destroy zones, so we must not |
| 761 // depend on zone allocations surviving beyond the epilogue callback. | 690 // depend on zone allocations surviving beyond the epilogue callback. |
| 762 { | 691 { |
| 763 StackZone stack_zone(Thread::Current()); | 692 StackZone stack_zone(Thread::Current()); |
| 764 Zone* zone = stack_zone.GetZone(); | 693 Zone* zone = stack_zone.GetZone(); |
| 765 MarkingStack marking_stack; | 694 MarkingStack marking_stack; |
| 766 DelaySet delay_set; | 695 DelaySet delay_set; |
| 767 const bool visit_prologue_weak_persistent_handles = !invoke_api_callbacks; | |
| 768 marked_bytes_ = 0; | 696 marked_bytes_ = 0; |
| 769 const int num_tasks = FLAG_marker_tasks; | 697 const int num_tasks = FLAG_marker_tasks; |
| 770 if (num_tasks == 0) { | 698 if (num_tasks == 0) { |
| 771 // Mark everything on main thread. | 699 // Mark everything on main thread. |
| 772 SkippedCodeFunctions* skipped_code_functions = | 700 SkippedCodeFunctions* skipped_code_functions = |
| 773 collect_code ? new(zone) SkippedCodeFunctions() : NULL; | 701 collect_code ? new(zone) SkippedCodeFunctions() : NULL; |
| 774 UnsyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack, | 702 UnsyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack, |
| 775 &delay_set, skipped_code_functions); | 703 &delay_set, skipped_code_functions); |
| 776 IterateRoots(isolate, &mark, visit_prologue_weak_persistent_handles, | 704 IterateRoots(isolate, &mark, 0, 1); |
| 777 0, 1); | |
| 778 mark.DrainMarkingStack(); | 705 mark.DrainMarkingStack(); |
| 779 IterateWeakReferences(isolate, &mark); | |
| 780 MarkingWeakVisitor mark_weak; | 706 MarkingWeakVisitor mark_weak; |
| 781 IterateWeakRoots(isolate, &mark_weak, | 707 IterateWeakRoots(isolate, &mark_weak); |
| 782 !visit_prologue_weak_persistent_handles); | |
| 783 // All marking done; detach code, etc. | 708 // All marking done; detach code, etc. |
| 784 FinalizeResultsFrom(&mark); | 709 FinalizeResultsFrom(&mark); |
| 785 } else { | 710 } else { |
| 786 ThreadBarrier barrier(num_tasks + 1); | 711 ThreadBarrier barrier(num_tasks + 1); |
| 787 // Used to coordinate draining among tasks; all start out as 'busy'. | 712 // Used to coordinate draining among tasks; all start out as 'busy'. |
| 788 uintptr_t num_busy = num_tasks; | 713 uintptr_t num_busy = num_tasks; |
| 789 // Phase 1: Iterate over roots and drain marking stack in tasks. | 714 // Phase 1: Iterate over roots and drain marking stack in tasks. |
| 790 for (intptr_t i = 0; i < num_tasks; ++i) { | 715 for (intptr_t i = 0; i < num_tasks; ++i) { |
| 791 MarkTask* mark_task = | 716 MarkTask* mark_task = |
| 792 new MarkTask(this, isolate, heap_, page_space, &marking_stack, | 717 new MarkTask(this, isolate, heap_, page_space, &marking_stack, |
| 793 &delay_set, &barrier, collect_code, | 718 &delay_set, &barrier, collect_code, |
| 794 visit_prologue_weak_persistent_handles, | |
| 795 i, num_tasks, &num_busy); | 719 i, num_tasks, &num_busy); |
| 796 ThreadPool* pool = Dart::thread_pool(); | 720 ThreadPool* pool = Dart::thread_pool(); |
| 797 pool->Run(mark_task); | 721 pool->Run(mark_task); |
| 798 } | 722 } |
| 799 barrier.Sync(); | 723 barrier.Sync(); |
| 800 | 724 |
| 801 // Phase 2: Weak processing and follow-up marking on main thread. | 725 // Phase 2: Weak processing and follow-up marking on main thread. |
| 802 SkippedCodeFunctions* skipped_code_functions = | 726 SkippedCodeFunctions* skipped_code_functions = |
| 803 collect_code ? new(zone) SkippedCodeFunctions() : NULL; | 727 collect_code ? new(zone) SkippedCodeFunctions() : NULL; |
| 804 SyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack, | 728 SyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack, |
| 805 &delay_set, skipped_code_functions); | 729 &delay_set, skipped_code_functions); |
| 806 IterateWeakReferences(isolate, &mark); | |
| 807 MarkingWeakVisitor mark_weak; | 730 MarkingWeakVisitor mark_weak; |
| 808 IterateWeakRoots(isolate, &mark_weak, | 731 IterateWeakRoots(isolate, &mark_weak); |
| 809 !visit_prologue_weak_persistent_handles); | |
| 810 barrier.Sync(); | 732 barrier.Sync(); |
| 811 | 733 |
| 812 // Phase 3: Finalize results from all markers (detach code, etc.). | 734 // Phase 3: Finalize results from all markers (detach code, etc.). |
| 813 if (FLAG_log_marker_tasks) { | 735 if (FLAG_log_marker_tasks) { |
| 814 THR_Print("Main thread marked %" Pd " bytes.\n", | 736 THR_Print("Main thread marked %" Pd " bytes.\n", |
| 815 mark.marked_bytes()); | 737 mark.marked_bytes()); |
| 816 } | 738 } |
| 817 FinalizeResultsFrom(&mark); | 739 FinalizeResultsFrom(&mark); |
| 818 barrier.Exit(); | 740 barrier.Exit(); |
| 819 } | 741 } |
| 820 delay_set.ClearReferences(); | 742 delay_set.ClearReferences(); |
| 821 ProcessWeakTables(page_space); | 743 ProcessWeakTables(page_space); |
| 822 ProcessObjectIdTable(isolate); | 744 ProcessObjectIdTable(isolate); |
| 823 } | 745 } |
| 824 Epilogue(isolate, invoke_api_callbacks); | 746 Epilogue(isolate, invoke_api_callbacks); |
| 825 } | 747 } |
| 826 | 748 |
| 827 } // namespace dart | 749 } // namespace dart |
| OLD | NEW |