| 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 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 if (to_ == NULL) { | 387 if (to_ == NULL) { |
| 388 // TODO(koda): We could try to recover (collect old space, wait for another | 388 // TODO(koda): We could try to recover (collect old space, wait for another |
| 389 // isolate to finish scavenge, etc.). | 389 // isolate to finish scavenge, etc.). |
| 390 OUT_OF_MEMORY(); | 390 OUT_OF_MEMORY(); |
| 391 } | 391 } |
| 392 UpdateMaxHeapCapacity(); | 392 UpdateMaxHeapCapacity(); |
| 393 top_ = FirstObjectStart(); | 393 top_ = FirstObjectStart(); |
| 394 resolved_top_ = top_; | 394 resolved_top_ = top_; |
| 395 end_ = to_->end(); | 395 end_ = to_->end(); |
| 396 | 396 |
| 397 // Throw out the old information about the from space | |
| 398 if (isolate->IsMutatorThreadScheduled()) { | |
| 399 Thread* mutator_thread = isolate->mutator_thread(); | |
| 400 mutator_thread->set_top(top_); | |
| 401 mutator_thread->set_end(end_); | |
| 402 } | |
| 403 | |
| 404 return from; | 397 return from; |
| 405 } | 398 } |
| 406 | 399 |
| 407 void Scavenger::Epilogue(Isolate* isolate, | 400 void Scavenger::Epilogue(Isolate* isolate, |
| 408 SemiSpace* from, | 401 SemiSpace* from, |
| 409 bool invoke_api_callbacks) { | 402 bool invoke_api_callbacks) { |
| 410 // All objects in the to space have been copied from the from space at this | 403 // All objects in the to space have been copied from the from space at this |
| 411 // moment. | 404 // moment. |
| 412 | 405 |
| 413 // Ensure the mutator thread now has the up-to-date top_ and end_ of the | 406 // Ensure the mutator thread will fail the next allocation. This will force |
| 414 // semispace | 407 // mutator to allocate a new TLAB |
| 415 if (isolate->IsMutatorThreadScheduled()) { | 408 Thread* mutator_thread = isolate->mutator_thread(); |
| 416 Thread* thread = isolate->mutator_thread(); | 409 ASSERT((mutator_thread == NULL) || (!mutator_thread->HasActiveTLAB())); |
| 417 thread->set_top(top_); | |
| 418 thread->set_end(end_); | |
| 419 } | |
| 420 | 410 |
| 421 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); | 411 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); |
| 422 if (stats_history_.Size() >= 2) { | 412 if (stats_history_.Size() >= 2) { |
| 423 // Previous scavenge is only given half as much weight. | 413 // Previous scavenge is only given half as much weight. |
| 424 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); | 414 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); |
| 425 avg_frac /= 1.0 + 0.5; // Normalize. | 415 avg_frac /= 1.0 + 0.5; // Normalize. |
| 426 } | 416 } |
| 427 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { | 417 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { |
| 428 // Remember the limit to which objects have been copied. | 418 // Remember the limit to which objects have been copied. |
| 429 survivor_end_ = top_; | 419 survivor_end_ = top_; |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 #endif // defined(DEBUG) | 705 #endif // defined(DEBUG) |
| 716 | 706 |
| 717 WeakProperty::Clear(cur_weak); | 707 WeakProperty::Clear(cur_weak); |
| 718 | 708 |
| 719 // Advance to next weak property in the queue. | 709 // Advance to next weak property in the queue. |
| 720 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); | 710 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); |
| 721 } | 711 } |
| 722 } | 712 } |
| 723 } | 713 } |
| 724 | 714 |
| 725 void Scavenger::FlushTLS() const { | 715 void Scavenger::MakeNewSpaceIterable() const { |
| 726 ASSERT(heap_ != NULL); | 716 ASSERT(heap_ != NULL); |
| 727 if (heap_->isolate()->IsMutatorThreadScheduled()) { | 717 Thread* mutator_thread = heap_->isolate()->mutator_thread(); |
| 728 Thread* mutator_thread = heap_->isolate()->mutator_thread(); | 718 if (mutator_thread != NULL && !scavenging_) { |
| 729 mutator_thread->heap()->new_space()->set_top(mutator_thread->top()); | 719 if (mutator_thread->HasActiveTLAB()) { |
| 720 ASSERT(mutator_thread->top() <= top_); |
| 721 heap_->FillRemainingTLAB(mutator_thread); |
| 722 } |
| 730 } | 723 } |
| 731 } | 724 } |
| 732 | 725 |
| 733 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { | 726 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { |
| 734 ASSERT(Thread::Current()->IsAtSafepoint() || | 727 ASSERT(Thread::Current()->IsAtSafepoint() || |
| 735 (Thread::Current()->task_kind() == Thread::kMarkerTask)); | 728 (Thread::Current()->task_kind() == Thread::kMarkerTask)); |
| 736 FlushTLS(); | 729 MakeNewSpaceIterable(); |
| 737 uword cur = FirstObjectStart(); | 730 uword cur = FirstObjectStart(); |
| 738 while (cur < top_) { | 731 while (cur < top_) { |
| 739 RawObject* raw_obj = RawObject::FromAddr(cur); | 732 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 740 cur += raw_obj->VisitPointers(visitor); | 733 cur += raw_obj->VisitPointers(visitor); |
| 741 } | 734 } |
| 742 } | 735 } |
| 743 | 736 |
| 744 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { | 737 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { |
| 745 ASSERT(Thread::Current()->IsAtSafepoint() || | 738 ASSERT(Thread::Current()->IsAtSafepoint() || |
| 746 (Thread::Current()->task_kind() == Thread::kMarkerTask)); | 739 (Thread::Current()->task_kind() == Thread::kMarkerTask)); |
| 747 FlushTLS(); | 740 MakeNewSpaceIterable(); |
| 748 uword cur = FirstObjectStart(); | 741 uword cur = FirstObjectStart(); |
| 749 while (cur < top_) { | 742 while (cur < top_) { |
| 750 RawObject* raw_obj = RawObject::FromAddr(cur); | 743 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 751 visitor->VisitObject(raw_obj); | 744 visitor->VisitObject(raw_obj); |
| 752 cur += raw_obj->Size(); | 745 cur += raw_obj->Size(); |
| 753 } | 746 } |
| 754 } | 747 } |
| 755 | 748 |
| 756 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { | 749 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { |
| 757 set->AddRegion(to_->start(), to_->end()); | 750 set->AddRegion(to_->start(), to_->end()); |
| 758 } | 751 } |
| 759 | 752 |
| 760 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { | 753 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { |
| 761 ASSERT(!scavenging_); | 754 ASSERT(!scavenging_); |
| 762 FlushTLS(); | 755 MakeNewSpaceIterable(); |
| 763 uword cur = FirstObjectStart(); | 756 uword cur = FirstObjectStart(); |
| 764 if (visitor->VisitRange(cur, top_)) { | 757 if (visitor->VisitRange(cur, top_)) { |
| 765 while (cur < top_) { | 758 while (cur < top_) { |
| 766 RawObject* raw_obj = RawObject::FromAddr(cur); | 759 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 767 uword next = cur + raw_obj->Size(); | 760 uword next = cur + raw_obj->Size(); |
| 768 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { | 761 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { |
| 769 return raw_obj; // Found object, return it. | 762 return raw_obj; // Found object, return it. |
| 770 } | 763 } |
| 771 cur = next; | 764 cur = next; |
| 772 } | 765 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 799 scavenging_ = true; | 792 scavenging_ = true; |
| 800 | 793 |
| 801 failed_to_promote_ = false; | 794 failed_to_promote_ = false; |
| 802 | 795 |
| 803 PageSpace* page_space = heap_->old_space(); | 796 PageSpace* page_space = heap_->old_space(); |
| 804 NoSafepointScope no_safepoints; | 797 NoSafepointScope no_safepoints; |
| 805 | 798 |
| 806 int64_t post_safe_point = OS::GetCurrentMonotonicMicros(); | 799 int64_t post_safe_point = OS::GetCurrentMonotonicMicros(); |
| 807 heap_->RecordTime(kSafePoint, post_safe_point - pre_safe_point); | 800 heap_->RecordTime(kSafePoint, post_safe_point - pre_safe_point); |
| 808 | 801 |
| 802 Thread* mutator_thread = isolate->mutator_thread(); |
| 803 if ((mutator_thread != NULL) && (mutator_thread->HasActiveTLAB())) { |
| 804 heap_->AbandonRemainingTLAB(mutator_thread); |
| 805 } |
| 806 |
| 809 // TODO(koda): Make verification more compatible with concurrent sweep. | 807 // TODO(koda): Make verification more compatible with concurrent sweep. |
| 810 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { | 808 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { |
| 811 OS::PrintErr("Verifying before Scavenge..."); | 809 OS::PrintErr("Verifying before Scavenge..."); |
| 812 heap_->Verify(kForbidMarked); | 810 heap_->Verify(kForbidMarked); |
| 813 OS::PrintErr(" done.\n"); | 811 OS::PrintErr(" done.\n"); |
| 814 } | 812 } |
| 815 | 813 |
| 816 // Prepare for a scavenge. | 814 // Prepare for a scavenge. |
| 817 SpaceUsage usage_before = GetCurrentUsage(); | 815 SpaceUsage usage_before = GetCurrentUsage(); |
| 818 intptr_t promo_candidate_words = | 816 intptr_t promo_candidate_words = |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 // the scavenge. | 908 // the scavenge. |
| 911 // The former can introduce an object that we might fail to collect. | 909 // The former can introduce an object that we might fail to collect. |
| 912 // The latter means even if the scavenge promotes every object in the new | 910 // The latter means even if the scavenge promotes every object in the new |
| 913 // space, the new allocation means the space is not empty, | 911 // space, the new allocation means the space is not empty, |
| 914 // causing the assertion below to fail. | 912 // causing the assertion below to fail. |
| 915 SafepointOperationScope scope(Thread::Current()); | 913 SafepointOperationScope scope(Thread::Current()); |
| 916 | 914 |
| 917 // Forces the next scavenge to promote all the objects in the new space. | 915 // Forces the next scavenge to promote all the objects in the new space. |
| 918 survivor_end_ = top_; | 916 survivor_end_ = top_; |
| 919 | 917 |
| 920 if (heap_->isolate()->IsMutatorThreadScheduled()) { | |
| 921 Thread* mutator_thread = heap_->isolate()->mutator_thread(); | |
| 922 survivor_end_ = mutator_thread->top(); | |
| 923 } | |
| 924 | |
| 925 Scavenge(); | 918 Scavenge(); |
| 926 | 919 |
| 927 // It is possible for objects to stay in the new space | 920 // It is possible for objects to stay in the new space |
| 928 // if the VM cannot create more pages for these objects. | 921 // if the VM cannot create more pages for these objects. |
| 929 ASSERT((UsedInWords() == 0) || failed_to_promote_); | 922 ASSERT((UsedInWords() == 0) || failed_to_promote_); |
| 930 } | 923 } |
| 931 | 924 |
| 925 int64_t Scavenger::UsedInWords() const { |
| 926 int64_t free_space_in_tlab = 0; |
| 927 if (heap_->isolate()->IsMutatorThreadScheduled()) { |
| 928 Thread* mutator_thread = heap_->isolate()->mutator_thread(); |
| 929 if (mutator_thread->HasActiveTLAB()) { |
| 930 free_space_in_tlab = |
| 931 (mutator_thread->end() - mutator_thread->top()) >> kWordSizeLog2; |
| 932 } |
| 933 } |
| 934 int64_t max_space_used = (top_ - FirstObjectStart()) >> kWordSizeLog2; |
| 935 return max_space_used - free_space_in_tlab; |
| 936 } |
| 937 |
| 932 } // namespace dart | 938 } // namespace dart |
| OLD | NEW |