| 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()) { | |
| 329 // Verify assumptions about the first word in objects which the scavenger is | 328 // Verify assumptions about the first word in objects which the scavenger is |
| 330 // going to use for forwarding pointers. | 329 // going to use for forwarding pointers. |
| 331 ASSERT(Object::tags_offset() == 0); | 330 ASSERT(Object::tags_offset() == 0); |
| 332 | 331 |
| 333 // Set initial size resulting in a total of three different levels. | 332 // Set initial size resulting in a total of three different levels. |
| 334 const intptr_t initial_semi_capacity_in_words = | 333 const intptr_t initial_semi_capacity_in_words = |
| 335 max_semi_capacity_in_words / | 334 max_semi_capacity_in_words / |
| 336 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); | 335 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); |
| 337 | 336 |
| 338 const intptr_t kVmNameSize = 128; | 337 const intptr_t kVmNameSize = 128; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 349 | 348 |
| 350 survivor_end_ = FirstObjectStart(); | 349 survivor_end_ = FirstObjectStart(); |
| 351 | 350 |
| 352 UpdateMaxHeapCapacity(); | 351 UpdateMaxHeapCapacity(); |
| 353 UpdateMaxHeapUsage(); | 352 UpdateMaxHeapUsage(); |
| 354 } | 353 } |
| 355 | 354 |
| 356 Scavenger::~Scavenger() { | 355 Scavenger::~Scavenger() { |
| 357 ASSERT(!scavenging_); | 356 ASSERT(!scavenging_); |
| 358 to_->Delete(); | 357 to_->Delete(); |
| 359 delete space_lock_; | |
| 360 } | 358 } |
| 361 | 359 |
| 362 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { | 360 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { |
| 363 if (stats_history_.Size() == 0) { | 361 if (stats_history_.Size() == 0) { |
| 364 return old_size_in_words; | 362 return old_size_in_words; |
| 365 } | 363 } |
| 366 double garbage = stats_history_.Get(0).ExpectedGarbageFraction(); | 364 double garbage = stats_history_.Get(0).ExpectedGarbageFraction(); |
| 367 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { | 365 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { |
| 368 return Utils::Minimum(max_semi_capacity_in_words_, | 366 return Utils::Minimum(max_semi_capacity_in_words_, |
| 369 old_size_in_words * FLAG_new_gen_growth_factor); | 367 old_size_in_words * FLAG_new_gen_growth_factor); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 386 if (to_ == NULL) { | 384 if (to_ == NULL) { |
| 387 // TODO(koda): We could try to recover (collect old space, wait for another | 385 // TODO(koda): We could try to recover (collect old space, wait for another |
| 388 // isolate to finish scavenge, etc.). | 386 // isolate to finish scavenge, etc.). |
| 389 OUT_OF_MEMORY(); | 387 OUT_OF_MEMORY(); |
| 390 } | 388 } |
| 391 UpdateMaxHeapCapacity(); | 389 UpdateMaxHeapCapacity(); |
| 392 top_ = FirstObjectStart(); | 390 top_ = FirstObjectStart(); |
| 393 resolved_top_ = top_; | 391 resolved_top_ = top_; |
| 394 end_ = to_->end(); | 392 end_ = to_->end(); |
| 395 | 393 |
| 394 // Throw out the old information about the from space |
| 395 if (isolate->IsMutatorThreadScheduled()) { |
| 396 Thread* mutator_thread = isolate->mutator_thread(); |
| 397 mutator_thread->set_top(top_); |
| 398 mutator_thread->set_end(end_); |
| 399 } |
| 400 |
| 396 return from; | 401 return from; |
| 397 } | 402 } |
| 398 | 403 |
| 399 void Scavenger::Epilogue(Isolate* isolate, SemiSpace* from) { | 404 void Scavenger::Epilogue(Isolate* isolate, SemiSpace* from) { |
| 400 // All objects in the to space have been copied from the from space at this | 405 // All objects in the to space have been copied from the from space at this |
| 401 // moment. | 406 // moment. |
| 402 | 407 |
| 403 // Ensure the mutator thread will fail the next allocation. This will force | 408 // Ensure the mutator thread now has the up-to-date top_ and end_ of the |
| 404 // mutator to allocate a new TLAB | 409 // semispace |
| 405 Thread* mutator_thread = isolate->mutator_thread(); | 410 if (isolate->IsMutatorThreadScheduled()) { |
| 406 ASSERT((mutator_thread == NULL) || (!mutator_thread->HasActiveTLAB())); | 411 Thread* thread = isolate->mutator_thread(); |
| 412 thread->set_top(top_); |
| 413 thread->set_end(end_); |
| 414 } |
| 407 | 415 |
| 408 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); | 416 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); |
| 409 if (stats_history_.Size() >= 2) { | 417 if (stats_history_.Size() >= 2) { |
| 410 // Previous scavenge is only given half as much weight. | 418 // Previous scavenge is only given half as much weight. |
| 411 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); | 419 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); |
| 412 avg_frac /= 1.0 + 0.5; // Normalize. | 420 avg_frac /= 1.0 + 0.5; // Normalize. |
| 413 } | 421 } |
| 414 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { | 422 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { |
| 415 // Remember the limit to which objects have been copied. | 423 // Remember the limit to which objects have been copied. |
| 416 survivor_end_ = top_; | 424 survivor_end_ = top_; |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 #endif // defined(DEBUG) | 707 #endif // defined(DEBUG) |
| 700 | 708 |
| 701 WeakProperty::Clear(cur_weak); | 709 WeakProperty::Clear(cur_weak); |
| 702 | 710 |
| 703 // Advance to next weak property in the queue. | 711 // Advance to next weak property in the queue. |
| 704 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); | 712 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); |
| 705 } | 713 } |
| 706 } | 714 } |
| 707 } | 715 } |
| 708 | 716 |
| 709 void Scavenger::MakeAllTLABsIterable(Isolate* isolate) const { | 717 void Scavenger::FlushTLS() const { |
| 710 MonitorLocker ml(isolate->threads_lock(), false); | |
| 711 Thread* current = heap_->isolate()->thread_registry()->active_list(); | |
| 712 while (current != NULL) { | |
| 713 if (current->HasActiveTLAB()) { | |
| 714 heap_->MakeTLABIterable(current); | |
| 715 } | |
| 716 current = current->next(); | |
| 717 } | |
| 718 Thread* mutator_thread = isolate->mutator_thread(); | |
| 719 if ((mutator_thread != NULL) && (!isolate->IsMutatorThreadScheduled())) { | |
| 720 heap_->MakeTLABIterable(mutator_thread); | |
| 721 } | |
| 722 } | |
| 723 | |
| 724 void Scavenger::MakeNewSpaceIterable() const { | |
| 725 ASSERT(heap_ != NULL); | 718 ASSERT(heap_ != NULL); |
| 726 if (!scavenging_) { | 719 if (heap_->isolate()->IsMutatorThreadScheduled()) { |
| 727 MakeAllTLABsIterable(heap_->isolate()); | 720 Thread* mutator_thread = heap_->isolate()->mutator_thread(); |
| 728 } | 721 mutator_thread->heap()->new_space()->set_top(mutator_thread->top()); |
| 729 } | |
| 730 | |
| 731 void Scavenger::AbandonAllTLABs(Isolate* isolate) { | |
| 732 MonitorLocker ml(isolate->threads_lock(), false); | |
| 733 Thread* current = isolate->thread_registry()->active_list(); | |
| 734 while (current != NULL) { | |
| 735 heap_->AbandonRemainingTLAB(current); | |
| 736 current = current->next(); | |
| 737 } | |
| 738 Thread* mutator_thread = isolate->mutator_thread(); | |
| 739 if ((mutator_thread != NULL) && (!isolate->IsMutatorThreadScheduled())) { | |
| 740 heap_->AbandonRemainingTLAB(mutator_thread); | |
| 741 } | 722 } |
| 742 } | 723 } |
| 743 | 724 |
| 744 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { | 725 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { |
| 745 ASSERT(Thread::Current()->IsAtSafepoint() || | 726 ASSERT(Thread::Current()->IsAtSafepoint() || |
| 746 (Thread::Current()->task_kind() == Thread::kMarkerTask)); | 727 (Thread::Current()->task_kind() == Thread::kMarkerTask)); |
| 747 MakeNewSpaceIterable(); | 728 FlushTLS(); |
| 748 uword cur = FirstObjectStart(); | 729 uword cur = FirstObjectStart(); |
| 749 while (cur < top_) { | 730 while (cur < top_) { |
| 750 RawObject* raw_obj = RawObject::FromAddr(cur); | 731 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 751 cur += raw_obj->VisitPointers(visitor); | 732 cur += raw_obj->VisitPointers(visitor); |
| 752 } | 733 } |
| 753 } | 734 } |
| 754 | 735 |
| 755 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { | 736 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { |
| 756 ASSERT(Thread::Current()->IsAtSafepoint() || | 737 ASSERT(Thread::Current()->IsAtSafepoint() || |
| 757 (Thread::Current()->task_kind() == Thread::kMarkerTask)); | 738 (Thread::Current()->task_kind() == Thread::kMarkerTask)); |
| 758 MakeNewSpaceIterable(); | 739 FlushTLS(); |
| 759 uword cur = FirstObjectStart(); | 740 uword cur = FirstObjectStart(); |
| 760 while (cur < top_) { | 741 while (cur < top_) { |
| 761 RawObject* raw_obj = RawObject::FromAddr(cur); | 742 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 762 visitor->VisitObject(raw_obj); | 743 visitor->VisitObject(raw_obj); |
| 763 cur += raw_obj->Size(); | 744 cur += raw_obj->Size(); |
| 764 } | 745 } |
| 765 } | 746 } |
| 766 | 747 |
| 767 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { | 748 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { |
| 768 set->AddRegion(to_->start(), to_->end()); | 749 set->AddRegion(to_->start(), to_->end()); |
| 769 } | 750 } |
| 770 | 751 |
| 771 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { | 752 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { |
| 772 ASSERT(!scavenging_); | 753 ASSERT(!scavenging_); |
| 773 MakeNewSpaceIterable(); | 754 FlushTLS(); |
| 774 uword cur = FirstObjectStart(); | 755 uword cur = FirstObjectStart(); |
| 775 if (visitor->VisitRange(cur, top_)) { | 756 if (visitor->VisitRange(cur, top_)) { |
| 776 while (cur < top_) { | 757 while (cur < top_) { |
| 777 RawObject* raw_obj = RawObject::FromAddr(cur); | 758 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 778 uword next = cur + raw_obj->Size(); | 759 uword next = cur + raw_obj->Size(); |
| 779 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { | 760 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { |
| 780 return raw_obj; // Found object, return it. | 761 return raw_obj; // Found object, return it. |
| 781 } | 762 } |
| 782 cur = next; | 763 cur = next; |
| 783 } | 764 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 804 scavenging_ = true; | 785 scavenging_ = true; |
| 805 | 786 |
| 806 failed_to_promote_ = false; | 787 failed_to_promote_ = false; |
| 807 | 788 |
| 808 PageSpace* page_space = heap_->old_space(); | 789 PageSpace* page_space = heap_->old_space(); |
| 809 NoSafepointScope no_safepoints; | 790 NoSafepointScope no_safepoints; |
| 810 | 791 |
| 811 int64_t post_safe_point = OS::GetCurrentMonotonicMicros(); | 792 int64_t post_safe_point = OS::GetCurrentMonotonicMicros(); |
| 812 heap_->RecordTime(kSafePoint, post_safe_point - pre_safe_point); | 793 heap_->RecordTime(kSafePoint, post_safe_point - pre_safe_point); |
| 813 | 794 |
| 814 AbandonAllTLABs(isolate); | |
| 815 | |
| 816 // TODO(koda): Make verification more compatible with concurrent sweep. | 795 // TODO(koda): Make verification more compatible with concurrent sweep. |
| 817 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { | 796 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { |
| 818 OS::PrintErr("Verifying before Scavenge..."); | 797 OS::PrintErr("Verifying before Scavenge..."); |
| 819 heap_->Verify(kForbidMarked); | 798 heap_->Verify(kForbidMarked); |
| 820 OS::PrintErr(" done.\n"); | 799 OS::PrintErr(" done.\n"); |
| 821 } | 800 } |
| 822 | 801 |
| 823 // Prepare for a scavenge. | 802 // Prepare for a scavenge. |
| 824 SpaceUsage usage_before = GetCurrentUsage(); | 803 SpaceUsage usage_before = GetCurrentUsage(); |
| 825 intptr_t promo_candidate_words = | 804 intptr_t promo_candidate_words = |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 917 // the scavenge. | 896 // the scavenge. |
| 918 // The former can introduce an object that we might fail to collect. | 897 // The former can introduce an object that we might fail to collect. |
| 919 // The latter means even if the scavenge promotes every object in the new | 898 // The latter means even if the scavenge promotes every object in the new |
| 920 // space, the new allocation means the space is not empty, | 899 // space, the new allocation means the space is not empty, |
| 921 // causing the assertion below to fail. | 900 // causing the assertion below to fail. |
| 922 SafepointOperationScope scope(Thread::Current()); | 901 SafepointOperationScope scope(Thread::Current()); |
| 923 | 902 |
| 924 // Forces the next scavenge to promote all the objects in the new space. | 903 // Forces the next scavenge to promote all the objects in the new space. |
| 925 survivor_end_ = top_; | 904 survivor_end_ = top_; |
| 926 | 905 |
| 906 if (heap_->isolate()->IsMutatorThreadScheduled()) { |
| 907 Thread* mutator_thread = heap_->isolate()->mutator_thread(); |
| 908 survivor_end_ = mutator_thread->top(); |
| 909 } |
| 910 |
| 927 Scavenge(); | 911 Scavenge(); |
| 928 | 912 |
| 929 // It is possible for objects to stay in the new space | 913 // It is possible for objects to stay in the new space |
| 930 // if the VM cannot create more pages for these objects. | 914 // if the VM cannot create more pages for these objects. |
| 931 ASSERT((UsedInWords() == 0) || failed_to_promote_); | 915 ASSERT((UsedInWords() == 0) || failed_to_promote_); |
| 932 } | 916 } |
| 933 | 917 |
| 934 int64_t Scavenger::FreeSpaceInWords(Isolate* isolate) const { | |
| 935 MonitorLocker ml(isolate->threads_lock(), false); | |
| 936 Thread* current = isolate->thread_registry()->active_list(); | |
| 937 int64_t free_space = 0; | |
| 938 while (current != NULL) { | |
| 939 if (current->HasActiveTLAB()) { | |
| 940 free_space += current->end() - current->top(); | |
| 941 } | |
| 942 current = current->next(); | |
| 943 } | |
| 944 | |
| 945 Thread* mutator_thread = isolate->mutator_thread(); | |
| 946 if ((mutator_thread != NULL) && (!isolate->IsMutatorThreadScheduled())) { | |
| 947 free_space += mutator_thread->end() - mutator_thread->top(); | |
| 948 } | |
| 949 return free_space >> kWordSizeLog2; | |
| 950 } | |
| 951 | |
| 952 int64_t Scavenger::UsedInWords() const { | |
| 953 int64_t free_space_in_tlab = FreeSpaceInWords(heap_->isolate()); | |
| 954 int64_t max_space_used = (top_ - FirstObjectStart()) >> kWordSizeLog2; | |
| 955 return max_space_used - free_space_in_tlab; | |
| 956 } | |
| 957 | |
| 958 } // namespace dart | 918 } // namespace dart |
| OLD | NEW |