Chromium Code Reviews| 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/scavenger.h" | 5 #include "vm/scavenger.h" |
| 6 | 6 |
| 7 #include "vm/dart.h" | 7 #include "vm/dart.h" |
| 8 #include "vm/dart_api_state.h" | 8 #include "vm/dart_api_state.h" |
| 9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
| 10 #include "vm/lockers.h" | 10 #include "vm/lockers.h" |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 317 intptr_t max_semi_capacity_in_words, | 317 intptr_t max_semi_capacity_in_words, |
| 318 uword object_alignment) | 318 uword object_alignment) |
| 319 : heap_(heap), | 319 : heap_(heap), |
| 320 max_semi_capacity_in_words_(max_semi_capacity_in_words), | 320 max_semi_capacity_in_words_(max_semi_capacity_in_words), |
| 321 object_alignment_(object_alignment), | 321 object_alignment_(object_alignment), |
| 322 scavenging_(false), | 322 scavenging_(false), |
| 323 delayed_weak_properties_(NULL), | 323 delayed_weak_properties_(NULL), |
| 324 gc_time_micros_(0), | 324 gc_time_micros_(0), |
| 325 collections_(0), | 325 collections_(0), |
| 326 external_size_(0), | 326 external_size_(0), |
| 327 failed_to_promote_(false) { | 327 failed_to_promote_(false), |
| 328 space_lock_(new Mutex()) { | |
| 328 // Verify assumptions about the first word in objects which the scavenger is | 329 // Verify assumptions about the first word in objects which the scavenger is |
| 329 // going to use for forwarding pointers. | 330 // going to use for forwarding pointers. |
| 330 ASSERT(Object::tags_offset() == 0); | 331 ASSERT(Object::tags_offset() == 0); |
| 331 | 332 |
| 332 // Set initial size resulting in a total of three different levels. | 333 // Set initial size resulting in a total of three different levels. |
| 333 const intptr_t initial_semi_capacity_in_words = | 334 const intptr_t initial_semi_capacity_in_words = |
| 334 max_semi_capacity_in_words / | 335 max_semi_capacity_in_words / |
| 335 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); | 336 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); |
| 336 | 337 |
| 337 const intptr_t kVmNameSize = 128; | 338 const intptr_t kVmNameSize = 128; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 348 | 349 |
| 349 survivor_end_ = FirstObjectStart(); | 350 survivor_end_ = FirstObjectStart(); |
| 350 | 351 |
| 351 UpdateMaxHeapCapacity(); | 352 UpdateMaxHeapCapacity(); |
| 352 UpdateMaxHeapUsage(); | 353 UpdateMaxHeapUsage(); |
| 353 } | 354 } |
| 354 | 355 |
| 355 Scavenger::~Scavenger() { | 356 Scavenger::~Scavenger() { |
| 356 ASSERT(!scavenging_); | 357 ASSERT(!scavenging_); |
| 357 to_->Delete(); | 358 to_->Delete(); |
| 359 delete space_lock_; | |
| 358 } | 360 } |
| 359 | 361 |
| 360 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { | 362 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { |
| 361 if (stats_history_.Size() == 0) { | 363 if (stats_history_.Size() == 0) { |
| 362 return old_size_in_words; | 364 return old_size_in_words; |
| 363 } | 365 } |
| 364 double garbage = stats_history_.Get(0).GarbageFraction(); | 366 double garbage = stats_history_.Get(0).GarbageFraction(); |
| 365 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { | 367 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { |
| 366 return Utils::Minimum(max_semi_capacity_in_words_, | 368 return Utils::Minimum(max_semi_capacity_in_words_, |
| 367 old_size_in_words * FLAG_new_gen_growth_factor); | 369 old_size_in_words * FLAG_new_gen_growth_factor); |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 708 #endif // defined(DEBUG) | 710 #endif // defined(DEBUG) |
| 709 | 711 |
| 710 WeakProperty::Clear(cur_weak); | 712 WeakProperty::Clear(cur_weak); |
| 711 | 713 |
| 712 // Advance to next weak property in the queue. | 714 // Advance to next weak property in the queue. |
| 713 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); | 715 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); |
| 714 } | 716 } |
| 715 } | 717 } |
| 716 } | 718 } |
| 717 | 719 |
| 718 uword Scavenger::FlushTLS() const { | 720 void Scavenger::MakeALLTLABsIterable(Isolate* isolate) const { |
| 719 ASSERT(heap_ != NULL); | 721 Thread* current = heap_->isolate()->thread_registry()->active_list(); |
| 720 uword saved_top = top_; | 722 while (current != NULL) { |
| 721 if (heap_->isolate()->IsMutatorThreadScheduled() && !scavenging_) { | 723 if (current->HasActiveTLAB()) { |
| 722 Thread* mutator_thread = heap_->isolate()->mutator_thread(); | 724 heap_->MakeTLABIterable(current); |
| 723 saved_top = mutator_thread->heap()->new_space()->top(); | |
| 724 if (mutator_thread->HasActiveTLAB()) { | |
| 725 ASSERT(mutator_thread->top() <= | |
| 726 mutator_thread->heap()->new_space()->top()); | |
| 727 mutator_thread->heap()->new_space()->set_top(mutator_thread->top()); | |
| 728 } | 725 } |
| 726 current = current->next(); | |
| 729 } | 727 } |
| 730 return saved_top; | |
| 731 } | 728 } |
| 732 | 729 |
| 733 void Scavenger::UnflushTLS(uword value) const { | 730 void Scavenger::FlushTLS() const { |
| 734 ASSERT(heap_ != NULL); | 731 ASSERT(heap_ != NULL); |
| 735 if (heap_->isolate()->IsMutatorThreadScheduled() && !scavenging_) { | 732 if (!scavenging_) { |
| 736 Thread* mutator_thread = heap_->isolate()->mutator_thread(); | 733 MakeALLTLABsIterable(heap_->isolate()); |
| 737 mutator_thread->heap()->new_space()->set_top(value); | 734 } |
| 738 ASSERT(mutator_thread->top() <= mutator_thread->heap()->new_space()->top()); | 735 } |
| 736 | |
| 737 void Scavenger::AbandonAllTLABs() { | |
| 738 Thread* current = heap_->isolate()->thread_registry()->active_list(); | |
| 739 while (current != NULL) { | |
| 740 heap_->AbandonRemainingTLAB(current); | |
| 741 current = current->next(); | |
| 739 } | 742 } |
| 740 } | 743 } |
| 741 | 744 |
| 742 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { | 745 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { |
| 743 uword saved_top = FlushTLS(); | 746 FlushTLS(); |
| 744 uword cur = FirstObjectStart(); | 747 uword cur = FirstObjectStart(); |
| 745 while (cur < top_) { | 748 while (cur < top_) { |
| 746 RawObject* raw_obj = RawObject::FromAddr(cur); | 749 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 747 cur += raw_obj->VisitPointers(visitor); | 750 cur += raw_obj->VisitPointers(visitor); |
| 748 } | 751 } |
| 749 UnflushTLS(saved_top); | |
| 750 } | 752 } |
| 751 | 753 |
| 752 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { | 754 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { |
| 753 uword saved_top = FlushTLS(); | 755 FlushTLS(); |
| 754 uword cur = FirstObjectStart(); | 756 uword cur = FirstObjectStart(); |
| 755 while (cur < top_) { | 757 while (cur < top_) { |
| 756 RawObject* raw_obj = RawObject::FromAddr(cur); | 758 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 757 visitor->VisitObject(raw_obj); | 759 visitor->VisitObject(raw_obj); |
| 758 cur += raw_obj->Size(); | 760 cur += raw_obj->Size(); |
| 759 } | 761 } |
| 760 UnflushTLS(saved_top); | |
| 761 } | 762 } |
| 762 | 763 |
| 763 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { | 764 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { |
| 764 set->AddRegion(to_->start(), to_->end()); | 765 set->AddRegion(to_->start(), to_->end()); |
| 765 } | 766 } |
| 766 | 767 |
| 767 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { | 768 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { |
| 768 ASSERT(!scavenging_); | 769 ASSERT(!scavenging_); |
| 769 uword saved_top = FlushTLS(); | 770 FlushTLS(); |
| 770 uword cur = FirstObjectStart(); | 771 uword cur = FirstObjectStart(); |
| 771 if (visitor->VisitRange(cur, top_)) { | 772 if (visitor->VisitRange(cur, top_)) { |
| 772 while (cur < top_) { | 773 while (cur < top_) { |
| 773 RawObject* raw_obj = RawObject::FromAddr(cur); | 774 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 774 uword next = cur + raw_obj->Size(); | 775 uword next = cur + raw_obj->Size(); |
| 775 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { | 776 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { |
| 776 UnflushTLS(saved_top); | |
| 777 return raw_obj; // Found object, return it. | 777 return raw_obj; // Found object, return it. |
| 778 } | 778 } |
| 779 cur = next; | 779 cur = next; |
| 780 } | 780 } |
| 781 ASSERT(cur == top_); | 781 ASSERT(cur == top_); |
| 782 } | 782 } |
| 783 UnflushTLS(saved_top); | |
| 784 return Object::null(); | 783 return Object::null(); |
| 785 } | 784 } |
| 786 | 785 |
| 787 void Scavenger::Scavenge() { | 786 void Scavenger::Scavenge() { |
| 788 // TODO(cshapiro): Add a decision procedure for determining when the | 787 // TODO(cshapiro): Add a decision procedure for determining when the |
| 789 // the API callbacks should be invoked. | 788 // the API callbacks should be invoked. |
| 790 Scavenge(false); | 789 Scavenge(false); |
| 791 } | 790 } |
| 792 | 791 |
| 793 void Scavenger::Scavenge(bool invoke_api_callbacks) { | 792 void Scavenger::Scavenge(bool invoke_api_callbacks) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 808 scavenging_ = true; | 807 scavenging_ = true; |
| 809 | 808 |
| 810 failed_to_promote_ = false; | 809 failed_to_promote_ = false; |
| 811 | 810 |
| 812 PageSpace* page_space = heap_->old_space(); | 811 PageSpace* page_space = heap_->old_space(); |
| 813 NoSafepointScope no_safepoints; | 812 NoSafepointScope no_safepoints; |
| 814 | 813 |
| 815 int64_t post_safe_point = OS::GetCurrentMonotonicMicros(); | 814 int64_t post_safe_point = OS::GetCurrentMonotonicMicros(); |
| 816 heap_->RecordTime(kSafePoint, post_safe_point - pre_safe_point); | 815 heap_->RecordTime(kSafePoint, post_safe_point - pre_safe_point); |
| 817 | 816 |
| 818 if (isolate->IsMutatorThreadScheduled()) { | 817 // TODO(danunez): Abandon all threads' TLABs. Every thread should be stopped |
|
rmacnak
2017/08/02 19:20:48
Why TODO? Looks implemented to me.
danunez
2017/08/02 19:36:08
It is implemented (minus some locking with thread_
| |
| 819 Thread* mutator_thread = isolate->mutator_thread(); | 818 // here anyway. |
| 820 if (mutator_thread->HasActiveTLAB()) { | 819 AbandonAllTLABs(); |
| 821 heap_->AbandonRemainingTLAB(mutator_thread); | |
| 822 } | |
| 823 } | |
| 824 | 820 |
| 825 // TODO(koda): Make verification more compatible with concurrent sweep. | 821 // TODO(koda): Make verification more compatible with concurrent sweep. |
| 826 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { | 822 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { |
| 827 OS::PrintErr("Verifying before Scavenge..."); | 823 OS::PrintErr("Verifying before Scavenge..."); |
| 828 heap_->Verify(kForbidMarked); | 824 heap_->Verify(kForbidMarked); |
| 829 OS::PrintErr(" done.\n"); | 825 OS::PrintErr(" done.\n"); |
| 830 } | 826 } |
| 831 | 827 |
| 832 // Prepare for a scavenge. | 828 // Prepare for a scavenge. |
| 833 SpaceUsage usage_before = GetCurrentUsage(); | 829 SpaceUsage usage_before = GetCurrentUsage(); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 941 } | 937 } |
| 942 } | 938 } |
| 943 | 939 |
| 944 Scavenge(); | 940 Scavenge(); |
| 945 | 941 |
| 946 // It is possible for objects to stay in the new space | 942 // It is possible for objects to stay in the new space |
| 947 // if the VM cannot create more pages for these objects. | 943 // if the VM cannot create more pages for these objects. |
| 948 ASSERT((UsedInWords() == 0) || failed_to_promote_); | 944 ASSERT((UsedInWords() == 0) || failed_to_promote_); |
| 949 } | 945 } |
| 950 | 946 |
| 947 uword Scavenger::FindTopOfSpace(Isolate* isolate) const { | |
| 948 Thread* current = heap_->isolate()->thread_registry()->active_list(); | |
| 949 uword furthest_addr = 0; | |
| 950 while (current != NULL) { | |
| 951 if (current->HasActiveTLAB() && current->top() > furthest_addr) { | |
| 952 furthest_addr = current->top(); | |
| 953 } | |
| 954 current = current->next(); | |
| 955 } | |
| 956 if (furthest_addr == 0) { | |
| 957 return top_; | |
| 958 } | |
| 959 return furthest_addr; | |
| 960 } | |
| 961 | |
| 951 int64_t Scavenger::UsedInWords() const { | 962 int64_t Scavenger::UsedInWords() const { |
| 952 uword saved_top = FlushTLS(); | 963 uword top_of_space = FindTopOfSpace(heap_->isolate()); |
|
rmacnak
2017/08/02 19:20:48
This will count of the unallocated space in all bu
danunez
2017/08/02 19:36:08
If each thread allocates at most one TLAB, then we
| |
| 953 int64_t used_in_words = (top_ - FirstObjectStart()) >> kWordSizeLog2; | 964 int64_t used_in_words = (top_of_space - FirstObjectStart()) >> kWordSizeLog2; |
| 954 UnflushTLS(saved_top); | |
| 955 return used_in_words; | 965 return used_in_words; |
| 956 } | 966 } |
| 957 | 967 |
| 958 } // namespace dart | 968 } // namespace dart |
| OLD | NEW |