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 |