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 <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <map> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
71 } | 71 } |
72 | 72 |
73 private: | 73 private: |
74 bool* _addr; | 74 bool* _addr; |
75 bool _value; | 75 bool _value; |
76 }; | 76 }; |
77 | 77 |
78 | 78 |
79 class ScavengerVisitor : public ObjectPointerVisitor { | 79 class ScavengerVisitor : public ObjectPointerVisitor { |
80 public: | 80 public: |
81 explicit ScavengerVisitor(Isolate* isolate, Scavenger* scavenger) | 81 explicit ScavengerVisitor(Isolate* isolate, |
82 Scavenger* scavenger, | |
83 SemiSpace* from) | |
82 : ObjectPointerVisitor(isolate), | 84 : ObjectPointerVisitor(isolate), |
83 thread_(Thread::Current()), | 85 thread_(Thread::Current()), |
84 scavenger_(scavenger), | 86 scavenger_(scavenger), |
85 from_start_(scavenger_->from_->start()), | 87 from_(from), |
86 from_size_(scavenger_->from_->end() - scavenger_->from_->start()), | |
87 heap_(scavenger->heap_), | 88 heap_(scavenger->heap_), |
88 vm_heap_(Dart::vm_isolate()->heap()), | 89 vm_heap_(Dart::vm_isolate()->heap()), |
89 page_space_(scavenger->heap_->old_space()), | 90 page_space_(scavenger->heap_->old_space()), |
90 delayed_weak_stack_(), | 91 delayed_weak_stack_(), |
91 bytes_promoted_(0), | 92 bytes_promoted_(0), |
92 visiting_old_object_(NULL), | 93 visiting_old_object_(NULL), |
93 in_scavenge_pointer_(false) { } | 94 in_scavenge_pointer_(false) { } |
94 | 95 |
95 void VisitPointers(RawObject** first, RawObject** last) { | 96 void VisitPointers(RawObject** first, RawObject** last) { |
96 for (RawObject** current = first; current <= last; current++) { | 97 for (RawObject** current = first; current <= last; current++) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
150 BoolScope bs(&in_scavenge_pointer_, true); | 151 BoolScope bs(&in_scavenge_pointer_, true); |
151 #endif | 152 #endif |
152 | 153 |
153 RawObject* raw_obj = *p; | 154 RawObject* raw_obj = *p; |
154 | 155 |
155 if (raw_obj->IsSmiOrOldObject()) { | 156 if (raw_obj->IsSmiOrOldObject()) { |
156 return; | 157 return; |
157 } | 158 } |
158 | 159 |
159 // The scavenger is only interested in objects located in the from space. | 160 // The scavenger is only interested in objects located in the from space. |
160 // | 161 ASSERT(from_->Contains(RawObject::ToAddr(raw_obj))); |
koda
2015/08/12 01:22:33
You could rearrange and use "raw_addr" here; it mi
Ivan Posva
2015/08/14 20:19:32
Done.
| |
161 // We are using address math here and relying on the unsigned underflow | |
162 // in the code below to avoid having two checks. | |
163 uword obj_offset = reinterpret_cast<uword>(raw_obj) - from_start_; | |
164 if (obj_offset > from_size_) { | |
165 ASSERT(scavenger_->to_->Contains(RawObject::ToAddr(raw_obj))); | |
166 return; | |
167 } | |
168 | 162 |
169 uword raw_addr = RawObject::ToAddr(raw_obj); | 163 uword raw_addr = RawObject::ToAddr(raw_obj); |
170 // Read the header word of the object and determine if the object has | 164 // Read the header word of the object and determine if the object has |
171 // already been copied. | 165 // already been copied. |
172 uword header = *reinterpret_cast<uword*>(raw_addr); | 166 uword header = *reinterpret_cast<uword*>(raw_addr); |
173 uword new_addr = 0; | 167 uword new_addr = 0; |
174 if (IsForwarding(header)) { | 168 if (IsForwarding(header)) { |
175 // Get the new location of the object. | 169 // Get the new location of the object. |
176 new_addr = ForwardedAddr(header); | 170 new_addr = ForwardedAddr(header); |
177 } else { | 171 } else { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
235 *p = new_obj; | 229 *p = new_obj; |
236 // Update the store buffer as needed. | 230 // Update the store buffer as needed. |
237 if (visiting_old_object_ != NULL) { | 231 if (visiting_old_object_ != NULL) { |
238 VerifiedMemory::Accept(reinterpret_cast<uword>(p), sizeof(*p)); | 232 VerifiedMemory::Accept(reinterpret_cast<uword>(p), sizeof(*p)); |
239 UpdateStoreBuffer(p, new_obj); | 233 UpdateStoreBuffer(p, new_obj); |
240 } | 234 } |
241 } | 235 } |
242 | 236 |
243 Thread* thread_; | 237 Thread* thread_; |
244 Scavenger* scavenger_; | 238 Scavenger* scavenger_; |
245 uword from_start_; | 239 SemiSpace* from_; |
246 uword from_size_; | |
247 Heap* heap_; | 240 Heap* heap_; |
248 Heap* vm_heap_; | 241 Heap* vm_heap_; |
249 PageSpace* page_space_; | 242 PageSpace* page_space_; |
250 typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet; | 243 typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet; |
251 DelaySet delay_set_; | 244 DelaySet delay_set_; |
252 GrowableArray<RawObject*> delayed_weak_stack_; | 245 GrowableArray<RawObject*> delayed_weak_stack_; |
253 // TODO(cshapiro): use this value to compute survival statistics for | 246 // TODO(cshapiro): use this value to compute survival statistics for |
254 // new space growth policy. | 247 // new space growth policy. |
255 intptr_t bytes_promoted_; | 248 intptr_t bytes_promoted_; |
256 RawObject* visiting_old_object_; | 249 RawObject* visiting_old_object_; |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
415 // going to use for forwarding pointers. | 408 // going to use for forwarding pointers. |
416 ASSERT(Object::tags_offset() == 0); | 409 ASSERT(Object::tags_offset() == 0); |
417 | 410 |
418 // Set initial size resulting in a total of three different levels. | 411 // Set initial size resulting in a total of three different levels. |
419 const intptr_t initial_semi_capacity_in_words = max_semi_capacity_in_words / | 412 const intptr_t initial_semi_capacity_in_words = max_semi_capacity_in_words / |
420 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); | 413 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); |
421 to_ = SemiSpace::New(initial_semi_capacity_in_words); | 414 to_ = SemiSpace::New(initial_semi_capacity_in_words); |
422 if (to_ == NULL) { | 415 if (to_ == NULL) { |
423 FATAL("Out of memory.\n"); | 416 FATAL("Out of memory.\n"); |
424 } | 417 } |
425 from_ = NULL; | |
426 | 418 |
427 // Setup local fields. | 419 // Setup local fields. |
428 top_ = FirstObjectStart(); | 420 top_ = FirstObjectStart(); |
429 resolved_top_ = top_; | 421 resolved_top_ = top_; |
430 end_ = to_->end(); | 422 end_ = to_->end(); |
431 | 423 |
432 survivor_end_ = FirstObjectStart(); | 424 survivor_end_ = FirstObjectStart(); |
433 } | 425 } |
434 | 426 |
435 | 427 |
436 Scavenger::~Scavenger() { | 428 Scavenger::~Scavenger() { |
437 ASSERT(!scavenging_); | 429 ASSERT(!scavenging_); |
438 ASSERT(from_ == NULL); | |
439 to_->Delete(); | 430 to_->Delete(); |
440 } | 431 } |
441 | 432 |
442 | 433 |
443 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { | 434 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { |
444 if (stats_history_.Size() == 0) { | 435 if (stats_history_.Size() == 0) { |
445 return old_size_in_words; | 436 return old_size_in_words; |
446 } | 437 } |
447 double garbage = stats_history_.Get(0).GarbageFraction(); | 438 double garbage = stats_history_.Get(0).GarbageFraction(); |
448 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { | 439 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { |
449 return Utils::Minimum(max_semi_capacity_in_words_, | 440 return Utils::Minimum(max_semi_capacity_in_words_, |
450 old_size_in_words * FLAG_new_gen_growth_factor); | 441 old_size_in_words * FLAG_new_gen_growth_factor); |
451 } else { | 442 } else { |
452 return old_size_in_words; | 443 return old_size_in_words; |
453 } | 444 } |
454 } | 445 } |
455 | 446 |
456 | 447 |
457 void Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { | 448 SemiSpace* Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { |
458 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { | 449 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { |
459 (isolate->gc_prologue_callback())(); | 450 (isolate->gc_prologue_callback())(); |
460 } | 451 } |
461 Thread::PrepareForGC(); | 452 Thread::PrepareForGC(); |
462 // Flip the two semi-spaces so that to_ is always the space for allocating | 453 // Flip the two semi-spaces so that to_ is always the space for allocating |
463 // objects. | 454 // objects. |
464 from_ = to_; | 455 SemiSpace* from = to_; |
465 to_ = SemiSpace::New(NewSizeInWords(from_->size_in_words())); | 456 to_ = SemiSpace::New(NewSizeInWords(from->size_in_words())); |
466 if (to_ == NULL) { | 457 if (to_ == NULL) { |
467 // TODO(koda): We could try to recover (collect old space, wait for another | 458 // TODO(koda): We could try to recover (collect old space, wait for another |
468 // isolate to finish scavenge, etc.). | 459 // isolate to finish scavenge, etc.). |
469 FATAL("Out of memory.\n"); | 460 FATAL("Out of memory.\n"); |
470 } | 461 } |
471 top_ = FirstObjectStart(); | 462 top_ = FirstObjectStart(); |
472 resolved_top_ = top_; | 463 resolved_top_ = top_; |
473 end_ = to_->end(); | 464 end_ = to_->end(); |
465 return from; | |
474 } | 466 } |
475 | 467 |
476 | 468 |
477 void Scavenger::Epilogue(Isolate* isolate, | 469 void Scavenger::Epilogue(Isolate* isolate, |
470 SemiSpace* from, | |
478 bool invoke_api_callbacks) { | 471 bool invoke_api_callbacks) { |
479 // All objects in the to space have been copied from the from space at this | 472 // All objects in the to space have been copied from the from space at this |
480 // moment. | 473 // moment. |
481 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); | 474 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); |
482 if (stats_history_.Size() >= 2) { | 475 if (stats_history_.Size() >= 2) { |
483 // Previous scavenge is only given half as much weight. | 476 // Previous scavenge is only given half as much weight. |
484 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); | 477 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); |
485 avg_frac /= 1.0 + 0.5; // Normalize. | 478 avg_frac /= 1.0 + 0.5; // Normalize. |
486 } | 479 } |
487 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { | 480 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { |
(...skipping 11 matching lines...) Expand all Loading... | |
499 // being spawned. | 492 // being spawned. |
500 { | 493 { |
501 PageSpace* page_space = heap_->old_space(); | 494 PageSpace* page_space = heap_->old_space(); |
502 MonitorLocker ml(page_space->tasks_lock()); | 495 MonitorLocker ml(page_space->tasks_lock()); |
503 if (page_space->tasks() == 0) { | 496 if (page_space->tasks() == 0) { |
504 VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_); | 497 VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_); |
505 heap_->old_space()->VisitObjectPointers(&verify_store_buffer_visitor); | 498 heap_->old_space()->VisitObjectPointers(&verify_store_buffer_visitor); |
506 } | 499 } |
507 } | 500 } |
508 #endif // defined(DEBUG) | 501 #endif // defined(DEBUG) |
509 from_->Delete(); | 502 from->Delete(); |
510 from_ = NULL; | |
511 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { | 503 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { |
512 (isolate->gc_epilogue_callback())(); | 504 (isolate->gc_epilogue_callback())(); |
513 } | 505 } |
514 } | 506 } |
515 | 507 |
516 | 508 |
517 void Scavenger::IterateStoreBuffers(Isolate* isolate, | 509 void Scavenger::IterateStoreBuffers(Isolate* isolate, |
518 ScavengerVisitor* visitor) { | 510 ScavengerVisitor* visitor) { |
519 // Iterating through the store buffers. | 511 // Iterating through the store buffers. |
520 // Grab the deduplication sets out of the isolate's consolidated store buffer. | 512 // Grab the deduplication sets out of the isolate's consolidated store buffer. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
576 | 568 |
577 bool Scavenger::IsUnreachable(RawObject** p) { | 569 bool Scavenger::IsUnreachable(RawObject** p) { |
578 RawObject* raw_obj = *p; | 570 RawObject* raw_obj = *p; |
579 if (!raw_obj->IsHeapObject()) { | 571 if (!raw_obj->IsHeapObject()) { |
580 return false; | 572 return false; |
581 } | 573 } |
582 if (!raw_obj->IsNewObject()) { | 574 if (!raw_obj->IsNewObject()) { |
583 return false; | 575 return false; |
584 } | 576 } |
585 uword raw_addr = RawObject::ToAddr(raw_obj); | 577 uword raw_addr = RawObject::ToAddr(raw_obj); |
586 if (!from_->Contains(raw_addr)) { | 578 if (to_->Contains(raw_addr)) { |
587 return false; | 579 return false; |
588 } | 580 } |
589 uword header = *reinterpret_cast<uword*>(raw_addr); | 581 uword header = *reinterpret_cast<uword*>(raw_addr); |
590 if (IsForwarding(header)) { | 582 if (IsForwarding(header)) { |
591 uword new_addr = ForwardedAddr(header); | 583 uword new_addr = ForwardedAddr(header); |
592 *p = RawObject::FromAddr(new_addr); | 584 *p = RawObject::FromAddr(new_addr); |
593 return false; | 585 return false; |
594 } | 586 } |
595 return true; | 587 return true; |
596 } | 588 } |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
810 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { | 802 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { |
811 OS::PrintErr("Verifying before Scavenge..."); | 803 OS::PrintErr("Verifying before Scavenge..."); |
812 heap_->Verify(kForbidMarked); | 804 heap_->Verify(kForbidMarked); |
813 OS::PrintErr(" done.\n"); | 805 OS::PrintErr(" done.\n"); |
814 } | 806 } |
815 | 807 |
816 // Prepare for a scavenge. | 808 // Prepare for a scavenge. |
817 SpaceUsage usage_before = GetCurrentUsage(); | 809 SpaceUsage usage_before = GetCurrentUsage(); |
818 intptr_t promo_candidate_words = | 810 intptr_t promo_candidate_words = |
819 (survivor_end_ - FirstObjectStart()) / kWordSize; | 811 (survivor_end_ - FirstObjectStart()) / kWordSize; |
820 Prologue(isolate, invoke_api_callbacks); | 812 SemiSpace* from = Prologue(isolate, invoke_api_callbacks); |
821 // The API prologue/epilogue may create/destroy zones, so we must not | 813 // The API prologue/epilogue may create/destroy zones, so we must not |
822 // depend on zone allocations surviving beyond the epilogue callback. | 814 // depend on zone allocations surviving beyond the epilogue callback. |
823 { | 815 { |
824 StackZone zone(isolate); | 816 StackZone zone(isolate); |
825 // Setup the visitor and run the scavenge. | 817 // Setup the visitor and run the scavenge. |
826 ScavengerVisitor visitor(isolate, this); | 818 ScavengerVisitor visitor(isolate, this, from); |
827 page_space->AcquireDataLock(); | 819 page_space->AcquireDataLock(); |
828 const bool prologue_weak_are_strong = !invoke_api_callbacks; | 820 const bool prologue_weak_are_strong = !invoke_api_callbacks; |
829 IterateRoots(isolate, &visitor, prologue_weak_are_strong); | 821 IterateRoots(isolate, &visitor, prologue_weak_are_strong); |
830 int64_t start = OS::GetCurrentTimeMicros(); | 822 int64_t start = OS::GetCurrentTimeMicros(); |
831 ProcessToSpace(&visitor); | 823 ProcessToSpace(&visitor); |
832 int64_t middle = OS::GetCurrentTimeMicros(); | 824 int64_t middle = OS::GetCurrentTimeMicros(); |
833 IterateWeakReferences(isolate, &visitor); | 825 IterateWeakReferences(isolate, &visitor); |
834 ScavengerWeakVisitor weak_visitor(this, prologue_weak_are_strong); | 826 ScavengerWeakVisitor weak_visitor(this, prologue_weak_are_strong); |
835 // Include the prologue weak handles, since we must process any promotion. | 827 // Include the prologue weak handles, since we must process any promotion. |
836 const bool visit_prologue_weak_handles = true; | 828 const bool visit_prologue_weak_handles = true; |
837 IterateWeakRoots(isolate, &weak_visitor, visit_prologue_weak_handles); | 829 IterateWeakRoots(isolate, &weak_visitor, visit_prologue_weak_handles); |
838 visitor.Finalize(); | 830 visitor.Finalize(); |
839 ProcessWeakTables(); | 831 ProcessWeakTables(); |
840 page_space->ReleaseDataLock(); | 832 page_space->ReleaseDataLock(); |
841 | 833 |
842 // Scavenge finished. Run accounting. | 834 // Scavenge finished. Run accounting. |
843 int64_t end = OS::GetCurrentTimeMicros(); | 835 int64_t end = OS::GetCurrentTimeMicros(); |
844 heap_->RecordTime(kProcessToSpace, middle - start); | 836 heap_->RecordTime(kProcessToSpace, middle - start); |
845 heap_->RecordTime(kIterateWeaks, end - middle); | 837 heap_->RecordTime(kIterateWeaks, end - middle); |
846 stats_history_.Add( | 838 stats_history_.Add( |
847 ScavengeStats(start, end, | 839 ScavengeStats(start, end, |
848 usage_before, GetCurrentUsage(), | 840 usage_before, GetCurrentUsage(), |
849 promo_candidate_words, | 841 promo_candidate_words, |
850 visitor.bytes_promoted() >> kWordSizeLog2)); | 842 visitor.bytes_promoted() >> kWordSizeLog2)); |
851 } | 843 } |
852 Epilogue(isolate, invoke_api_callbacks); | 844 Epilogue(isolate, from, invoke_api_callbacks); |
853 | 845 |
854 // TODO(koda): Make verification more compatible with concurrent sweep. | 846 // TODO(koda): Make verification more compatible with concurrent sweep. |
855 if (FLAG_verify_after_gc && !FLAG_concurrent_sweep) { | 847 if (FLAG_verify_after_gc && !FLAG_concurrent_sweep) { |
856 OS::PrintErr("Verifying after Scavenge..."); | 848 OS::PrintErr("Verifying after Scavenge..."); |
857 heap_->Verify(kForbidMarked); | 849 heap_->Verify(kForbidMarked); |
858 OS::PrintErr(" done.\n"); | 850 OS::PrintErr(" done.\n"); |
859 } | 851 } |
860 | 852 |
861 // Done scavenging. Reset the marker. | 853 // Done scavenging. Reset the marker. |
862 ASSERT(scavenging_); | 854 ASSERT(scavenging_); |
863 scavenging_ = false; | 855 scavenging_ = false; |
864 } | 856 } |
865 | 857 |
866 | 858 |
867 void Scavenger::WriteProtect(bool read_only) { | 859 void Scavenger::WriteProtect(bool read_only) { |
868 ASSERT(!scavenging_); | 860 ASSERT(!scavenging_); |
869 ASSERT(from_ == NULL); | |
870 to_->WriteProtect(read_only); | 861 to_->WriteProtect(read_only); |
871 } | 862 } |
872 | 863 |
873 | 864 |
874 void Scavenger::PrintToJSONObject(JSONObject* object) const { | 865 void Scavenger::PrintToJSONObject(JSONObject* object) const { |
875 Isolate* isolate = Isolate::Current(); | 866 Isolate* isolate = Isolate::Current(); |
876 ASSERT(isolate != NULL); | 867 ASSERT(isolate != NULL); |
877 JSONObject space(object, "new"); | 868 JSONObject space(object, "new"); |
878 space.AddProperty("type", "HeapSpace"); | 869 space.AddProperty("type", "HeapSpace"); |
879 space.AddProperty("name", "new"); | 870 space.AddProperty("name", "new"); |
(...skipping 23 matching lines...) Expand all Loading... | |
903 } | 894 } |
904 | 895 |
905 | 896 |
906 void Scavenger::FreeExternal(intptr_t size) { | 897 void Scavenger::FreeExternal(intptr_t size) { |
907 ASSERT(size >= 0); | 898 ASSERT(size >= 0); |
908 external_size_ -= size; | 899 external_size_ -= size; |
909 ASSERT(external_size_ >= 0); | 900 ASSERT(external_size_ >= 0); |
910 } | 901 } |
911 | 902 |
912 } // namespace dart | 903 } // namespace dart |
OLD | NEW |