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 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 330 Scavenger::Scavenger(Heap* heap, | 330 Scavenger::Scavenger(Heap* heap, |
| 331 intptr_t max_semi_capacity_in_words, | 331 intptr_t max_semi_capacity_in_words, |
| 332 uword object_alignment) | 332 uword object_alignment) |
| 333 : heap_(heap), | 333 : heap_(heap), |
| 334 max_semi_capacity_in_words_(max_semi_capacity_in_words), | 334 max_semi_capacity_in_words_(max_semi_capacity_in_words), |
| 335 object_alignment_(object_alignment), | 335 object_alignment_(object_alignment), |
| 336 scavenging_(false), | 336 scavenging_(false), |
| 337 delayed_weak_properties_(NULL), | 337 delayed_weak_properties_(NULL), |
| 338 gc_time_micros_(0), | 338 gc_time_micros_(0), |
| 339 collections_(0), | 339 collections_(0), |
| 340 external_size_(0) { | 340 external_size_(0), |
| 341 space_lock_(new Mutex()) { | |
| 341 // Verify assumptions about the first word in objects which the scavenger is | 342 // Verify assumptions about the first word in objects which the scavenger is |
| 342 // going to use for forwarding pointers. | 343 // going to use for forwarding pointers. |
| 343 ASSERT(Object::tags_offset() == 0); | 344 ASSERT(Object::tags_offset() == 0); |
| 344 | 345 |
| 345 // Set initial size resulting in a total of three different levels. | 346 // Set initial size resulting in a total of three different levels. |
| 346 const intptr_t initial_semi_capacity_in_words = | 347 const intptr_t initial_semi_capacity_in_words = |
| 347 max_semi_capacity_in_words / | 348 max_semi_capacity_in_words / |
| 348 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); | 349 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); |
| 349 to_ = SemiSpace::New(initial_semi_capacity_in_words); | 350 to_ = SemiSpace::New(initial_semi_capacity_in_words); |
| 350 if (to_ == NULL) { | 351 if (to_ == NULL) { |
| 351 OUT_OF_MEMORY(); | 352 OUT_OF_MEMORY(); |
| 352 } | 353 } |
| 353 // Setup local fields. | 354 // Setup local fields. |
| 354 top_ = FirstObjectStart(); | 355 top_ = FirstObjectStart(); |
| 355 resolved_top_ = top_; | 356 resolved_top_ = top_; |
| 356 end_ = to_->end(); | 357 end_ = to_->end(); |
| 357 | 358 |
| 358 survivor_end_ = FirstObjectStart(); | 359 survivor_end_ = FirstObjectStart(); |
| 359 | 360 |
| 360 UpdateMaxHeapCapacity(); | 361 UpdateMaxHeapCapacity(); |
| 361 UpdateMaxHeapUsage(); | 362 UpdateMaxHeapUsage(); |
| 362 } | 363 } |
| 363 | 364 |
| 364 | 365 |
| 365 Scavenger::~Scavenger() { | 366 Scavenger::~Scavenger() { |
| 366 ASSERT(!scavenging_); | 367 ASSERT(!scavenging_); |
| 367 to_->Delete(); | 368 to_->Delete(); |
| 369 delete space_lock_; | |
| 368 } | 370 } |
| 369 | 371 |
| 370 | 372 |
| 371 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { | 373 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { |
| 372 if (stats_history_.Size() == 0) { | 374 if (stats_history_.Size() == 0) { |
| 373 return old_size_in_words; | 375 return old_size_in_words; |
| 374 } | 376 } |
| 375 double garbage = stats_history_.Get(0).GarbageFraction(); | 377 double garbage = stats_history_.Get(0).GarbageFraction(); |
| 376 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { | 378 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { |
| 377 return Utils::Minimum(max_semi_capacity_in_words_, | 379 return Utils::Minimum(max_semi_capacity_in_words_, |
| 378 old_size_in_words * FLAG_new_gen_growth_factor); | 380 old_size_in_words * FLAG_new_gen_growth_factor); |
| 379 } else { | 381 } else { |
| 380 return old_size_in_words; | 382 return old_size_in_words; |
| 381 } | 383 } |
| 382 } | 384 } |
| 383 | 385 |
| 384 | 386 |
| 385 SemiSpace* Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { | 387 SemiSpace* Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { |
| 386 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { | 388 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { |
| 387 (isolate->gc_prologue_callback())(); | 389 (isolate->gc_prologue_callback())(); |
| 388 } | 390 } |
| 389 isolate->PrepareForGC(); | 391 isolate->PrepareForGC(); |
| 392 | |
| 393 ASSERT(isolate->mutator_thread()->top() == top_); | |
| 394 | |
| 390 // Flip the two semi-spaces so that to_ is always the space for allocating | 395 // Flip the two semi-spaces so that to_ is always the space for allocating |
| 391 // objects. | 396 // objects. |
| 392 SemiSpace* from = to_; | 397 SemiSpace* from = to_; |
| 393 to_ = SemiSpace::New(NewSizeInWords(from->size_in_words())); | 398 to_ = SemiSpace::New(NewSizeInWords(from->size_in_words())); |
| 394 if (to_ == NULL) { | 399 if (to_ == NULL) { |
| 395 // TODO(koda): We could try to recover (collect old space, wait for another | 400 // TODO(koda): We could try to recover (collect old space, wait for another |
| 396 // isolate to finish scavenge, etc.). | 401 // isolate to finish scavenge, etc.). |
| 397 OUT_OF_MEMORY(); | 402 OUT_OF_MEMORY(); |
| 398 } | 403 } |
| 399 UpdateMaxHeapCapacity(); | 404 UpdateMaxHeapCapacity(); |
| 400 top_ = FirstObjectStart(); | 405 top_ = FirstObjectStart(); |
| 401 resolved_top_ = top_; | 406 resolved_top_ = top_; |
| 402 end_ = to_->end(); | 407 end_ = to_->end(); |
| 408 | |
| 409 isolate->mutator_thread()->set_top_offset(top_); | |
| 410 isolate->mutator_thread()->set_end_offset(end_); | |
| 411 | |
| 403 return from; | 412 return from; |
| 404 } | 413 } |
| 405 | 414 |
| 406 | 415 |
| 407 void Scavenger::Epilogue(Isolate* isolate, | 416 void Scavenger::Epilogue(Isolate* isolate, |
| 408 SemiSpace* from, | 417 SemiSpace* from, |
| 409 bool invoke_api_callbacks) { | 418 bool invoke_api_callbacks) { |
| 410 // All objects in the to space have been copied from the from space at this | 419 // All objects in the to space have been copied from the from space at this |
| 411 // moment. | 420 // moment. |
| 421 | |
| 422 isolate->mutator_thread()->set_top_offset(top_); | |
| 423 isolate->mutator_thread()->set_end_offset(end_); | |
| 424 | |
| 412 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); | 425 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); |
| 413 if (stats_history_.Size() >= 2) { | 426 if (stats_history_.Size() >= 2) { |
| 414 // Previous scavenge is only given half as much weight. | 427 // Previous scavenge is only given half as much weight. |
| 415 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); | 428 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); |
| 416 avg_frac /= 1.0 + 0.5; // Normalize. | 429 avg_frac /= 1.0 + 0.5; // Normalize. |
| 417 } | 430 } |
| 418 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { | 431 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { |
| 419 // Remember the limit to which objects have been copied. | 432 // Remember the limit to which objects have been copied. |
| 420 survivor_end_ = top_; | 433 survivor_end_ = top_; |
| 421 } else { | 434 } else { |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 538 } | 551 } |
| 539 | 552 |
| 540 | 553 |
| 541 void Scavenger::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) { | 554 void Scavenger::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) { |
| 542 isolate->VisitWeakPersistentHandles(visitor); | 555 isolate->VisitWeakPersistentHandles(visitor); |
| 543 } | 556 } |
| 544 | 557 |
| 545 | 558 |
| 546 void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) { | 559 void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) { |
| 547 // Iterate until all work has been drained. | 560 // Iterate until all work has been drained. |
| 561 | |
| 562 ASSERT(Isolate::Current()->mutator_thread()->top() == top_); | |
| 563 | |
| 548 while ((resolved_top_ < top_) || PromotedStackHasMore()) { | 564 while ((resolved_top_ < top_) || PromotedStackHasMore()) { |
| 549 while (resolved_top_ < top_) { | 565 while (resolved_top_ < top_) { |
| 550 RawObject* raw_obj = RawObject::FromAddr(resolved_top_); | 566 RawObject* raw_obj = RawObject::FromAddr(resolved_top_); |
| 551 intptr_t class_id = raw_obj->GetClassId(); | 567 intptr_t class_id = raw_obj->GetClassId(); |
| 552 if (class_id != kWeakPropertyCid) { | 568 if (class_id != kWeakPropertyCid) { |
| 553 resolved_top_ += raw_obj->VisitPointersNonvirtual(visitor); | 569 resolved_top_ += raw_obj->VisitPointersNonvirtual(visitor); |
| 554 } else { | 570 } else { |
| 555 RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj); | 571 RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj); |
| 556 resolved_top_ += ProcessWeakProperty(raw_weak, visitor); | 572 resolved_top_ += ProcessWeakProperty(raw_weak, visitor); |
| 557 } | 573 } |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 716 | 732 |
| 717 // Advance to next weak property in the queue. | 733 // Advance to next weak property in the queue. |
| 718 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); | 734 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); |
| 719 } | 735 } |
| 720 } | 736 } |
| 721 } | 737 } |
| 722 | 738 |
| 723 | 739 |
| 724 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { | 740 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { |
| 725 uword cur = FirstObjectStart(); | 741 uword cur = FirstObjectStart(); |
| 726 while (cur < top_) { | 742 while (cur < top_) { |
|
rmacnak
2017/06/22 22:31:50
top_ may be stale
danunez
2017/06/30 20:35:57
Right. top_ is now retrieved from the mutator thre
| |
| 727 RawObject* raw_obj = RawObject::FromAddr(cur); | 743 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 728 cur += raw_obj->VisitPointers(visitor); | 744 cur += raw_obj->VisitPointers(visitor); |
| 729 } | 745 } |
| 730 } | 746 } |
| 731 | 747 |
| 732 | 748 |
| 733 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { | 749 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { |
| 734 uword cur = FirstObjectStart(); | 750 uword cur = FirstObjectStart(); |
| 735 while (cur < top_) { | 751 while (cur < top_) { |
|
rmacnak
2017/06/22 22:31:50
top_ may be stale
danunez
2017/06/30 20:35:57
Right. top_ is now retrieved from the mutator thre
| |
| 736 RawObject* raw_obj = RawObject::FromAddr(cur); | 752 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 737 visitor->VisitObject(raw_obj); | 753 visitor->VisitObject(raw_obj); |
| 738 cur += raw_obj->Size(); | 754 cur += raw_obj->Size(); |
| 739 } | 755 } |
| 740 } | 756 } |
| 741 | 757 |
| 742 | 758 |
| 743 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { | 759 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { |
| 744 set->AddRegion(to_->start(), to_->end()); | 760 set->AddRegion(to_->start(), to_->end()); |
| 745 } | 761 } |
| 746 | 762 |
| 747 | 763 |
| 748 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { | 764 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { |
| 749 ASSERT(!scavenging_); | 765 ASSERT(!scavenging_); |
| 750 uword cur = FirstObjectStart(); | 766 uword cur = FirstObjectStart(); |
| 751 if (visitor->VisitRange(cur, top_)) { | 767 if (visitor->VisitRange(cur, top_)) { |
|
rmacnak
2017/06/22 22:31:50
top_ may be stale
danunez
2017/06/30 20:35:57
Right. top_ is now retrieved from the mutator thre
| |
| 752 while (cur < top_) { | 768 while (cur < top_) { |
| 753 RawObject* raw_obj = RawObject::FromAddr(cur); | 769 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 754 uword next = cur + raw_obj->Size(); | 770 uword next = cur + raw_obj->Size(); |
| 755 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { | 771 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { |
| 756 return raw_obj; // Found object, return it. | 772 return raw_obj; // Found object, return it. |
| 757 } | 773 } |
| 758 cur = next; | 774 cur = next; |
| 759 } | 775 } |
| 760 ASSERT(cur == top_); | 776 ASSERT(cur == top_); |
| 761 } | 777 } |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 890 } | 906 } |
| 891 | 907 |
| 892 | 908 |
| 893 void Scavenger::FreeExternal(intptr_t size) { | 909 void Scavenger::FreeExternal(intptr_t size) { |
| 894 ASSERT(size >= 0); | 910 ASSERT(size >= 0); |
| 895 external_size_ -= size; | 911 external_size_ -= size; |
| 896 ASSERT(external_size_ >= 0); | 912 ASSERT(external_size_ >= 0); |
| 897 } | 913 } |
| 898 | 914 |
| 899 } // namespace dart | 915 } // namespace dart |
| OLD | NEW |