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 <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 67 | 67 |
| 68 class ScavengerVisitor : public ObjectPointerVisitor { | 68 class ScavengerVisitor : public ObjectPointerVisitor { |
| 69 public: | 69 public: |
| 70 explicit ScavengerVisitor(Isolate* isolate, Scavenger* scavenger) | 70 explicit ScavengerVisitor(Isolate* isolate, Scavenger* scavenger) |
| 71 : ObjectPointerVisitor(isolate), | 71 : ObjectPointerVisitor(isolate), |
| 72 scavenger_(scavenger), | 72 scavenger_(scavenger), |
| 73 heap_(scavenger->heap_), | 73 heap_(scavenger->heap_), |
| 74 vm_heap_(Dart::vm_isolate()->heap()), | 74 vm_heap_(Dart::vm_isolate()->heap()), |
| 75 delayed_weak_stack_(), | 75 delayed_weak_stack_(), |
| 76 growth_policy_(PageSpace::kControlGrowth), | 76 growth_policy_(PageSpace::kControlGrowth), |
| 77 bytes_promoted_(0), | |
| 78 visiting_old_pointers_(false), | 77 visiting_old_pointers_(false), |
| 79 in_scavenge_pointer_(false) {} | 78 in_scavenge_pointer_(false) {} |
| 80 | 79 |
| 81 void VisitPointers(RawObject** first, RawObject** last) { | 80 void VisitPointers(RawObject** first, RawObject** last) { |
| 82 for (RawObject** current = first; current <= last; current++) { | 81 for (RawObject** current = first; current <= last; current++) { |
| 83 ScavengePointer(current); | 82 ScavengePointer(current); |
| 84 } | 83 } |
| 85 } | 84 } |
| 86 | 85 |
| 87 GrowableArray<RawObject*>* DelayedWeakStack() { | 86 GrowableArray<RawObject*>* DelayedWeakStack() { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 102 delay_set_.insert(std::make_pair(raw_key, raw_weak)); | 101 delay_set_.insert(std::make_pair(raw_key, raw_weak)); |
| 103 } | 102 } |
| 104 | 103 |
| 105 void Finalize() { | 104 void Finalize() { |
| 106 DelaySet::iterator it = delay_set_.begin(); | 105 DelaySet::iterator it = delay_set_.begin(); |
| 107 for (; it != delay_set_.end(); ++it) { | 106 for (; it != delay_set_.end(); ++it) { |
| 108 WeakProperty::Clear(it->second); | 107 WeakProperty::Clear(it->second); |
| 109 } | 108 } |
| 110 } | 109 } |
| 111 | 110 |
| 112 intptr_t bytes_promoted() { return bytes_promoted_; } | |
| 113 | |
| 114 private: | 111 private: |
| 115 void UpdateStoreBuffer(RawObject** p, RawObject* obj) { | 112 void UpdateStoreBuffer(RawObject** p, RawObject* obj) { |
| 116 uword ptr = reinterpret_cast<uword>(p); | 113 uword ptr = reinterpret_cast<uword>(p); |
| 117 ASSERT(obj->IsHeapObject()); | 114 ASSERT(obj->IsHeapObject()); |
| 118 ASSERT(!scavenger_->Contains(ptr)); | 115 ASSERT(!scavenger_->Contains(ptr)); |
| 119 ASSERT(!heap_->CodeContains(ptr)); | 116 ASSERT(!heap_->CodeContains(ptr)); |
| 120 ASSERT(heap_->Contains(ptr)); | 117 ASSERT(heap_->Contains(ptr)); |
| 121 // If the newly written object is not a new object, drop it immediately. | 118 // If the newly written object is not a new object, drop it immediately. |
| 122 if (!obj->IsNewObject()) return; | 119 if (!obj->IsNewObject()) return; |
| 123 isolate()->store_buffer()->AddPointer(ptr); | 120 isolate()->store_buffer()->AddPointer(ptr); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 // a coin toss determines if an object is promoted or whether it should | 177 // a coin toss determines if an object is promoted or whether it should |
| 181 // survive in this generation. | 178 // survive in this generation. |
| 182 // | 179 // |
| 183 // This object is a survivor of a previous scavenge. Attempt to promote | 180 // This object is a survivor of a previous scavenge. Attempt to promote |
| 184 // the object. | 181 // the object. |
| 185 new_addr = heap_->TryAllocate(size, Heap::kOld, growth_policy_); | 182 new_addr = heap_->TryAllocate(size, Heap::kOld, growth_policy_); |
| 186 if (new_addr != 0) { | 183 if (new_addr != 0) { |
| 187 // If promotion succeeded then we need to remember it so that it can | 184 // If promotion succeeded then we need to remember it so that it can |
| 188 // be traversed later. | 185 // be traversed later. |
| 189 scavenger_->PushToPromotedStack(new_addr); | 186 scavenger_->PushToPromotedStack(new_addr); |
| 190 bytes_promoted_ += size; | |
| 191 if (HeapTrace::is_enabled()) { | 187 if (HeapTrace::is_enabled()) { |
| 192 heap_->trace()->TracePromotion(raw_addr, new_addr); | 188 heap_->trace()->TracePromotion(raw_addr, new_addr); |
| 193 } | 189 } |
| 194 } else if (!scavenger_->had_promotion_failure_) { | 190 } else if (!scavenger_->had_promotion_failure_) { |
| 195 // Signal a promotion failure and set the growth policy for | 191 // Signal a promotion failure and set the growth policy for |
| 196 // this, and all subsequent promotion allocations, to force | 192 // this, and all subsequent promotion allocations, to force |
| 197 // growth. | 193 // growth. |
| 198 scavenger_->had_promotion_failure_ = true; | 194 scavenger_->had_promotion_failure_ = true; |
| 199 growth_policy_ = PageSpace::kForceGrowth; | 195 growth_policy_ = PageSpace::kForceGrowth; |
| 200 new_addr = heap_->TryAllocate(size, Heap::kOld, growth_policy_); | 196 new_addr = heap_->TryAllocate(size, Heap::kOld, growth_policy_); |
| 201 if (new_addr != 0) { | 197 if (new_addr != 0) { |
| 202 scavenger_->PushToPromotedStack(new_addr); | 198 scavenger_->PushToPromotedStack(new_addr); |
| 203 bytes_promoted_ += size; | |
| 204 if (HeapTrace::is_enabled()) { | 199 if (HeapTrace::is_enabled()) { |
| 205 heap_->trace()->TracePromotion(raw_addr, new_addr); | 200 heap_->trace()->TracePromotion(raw_addr, new_addr); |
| 206 } | 201 } |
| 207 } else { | 202 } else { |
| 208 // Promotion did not succeed. Copy into the to space | 203 // Promotion did not succeed. Copy into the to space |
| 209 // instead. | 204 // instead. |
| 210 new_addr = scavenger_->TryAllocate(size); | 205 new_addr = scavenger_->TryAllocate(size); |
| 211 if (HeapTrace::is_enabled()) { | 206 if (HeapTrace::is_enabled()) { |
| 212 heap_->trace()->TraceCopy(raw_addr, new_addr); | 207 heap_->trace()->TraceCopy(raw_addr, new_addr); |
| 213 } | 208 } |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 240 } | 235 } |
| 241 } | 236 } |
| 242 | 237 |
| 243 Scavenger* scavenger_; | 238 Scavenger* scavenger_; |
| 244 Heap* heap_; | 239 Heap* heap_; |
| 245 Heap* vm_heap_; | 240 Heap* vm_heap_; |
| 246 typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet; | 241 typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet; |
| 247 DelaySet delay_set_; | 242 DelaySet delay_set_; |
| 248 GrowableArray<RawObject*> delayed_weak_stack_; | 243 GrowableArray<RawObject*> delayed_weak_stack_; |
| 249 PageSpace::GrowthPolicy growth_policy_; | 244 PageSpace::GrowthPolicy growth_policy_; |
| 250 intptr_t bytes_promoted_; | |
| 251 | 245 |
| 252 bool visiting_old_pointers_; | 246 bool visiting_old_pointers_; |
| 253 bool in_scavenge_pointer_; | 247 bool in_scavenge_pointer_; |
| 254 | 248 |
| 255 DISALLOW_COPY_AND_ASSIGN(ScavengerVisitor); | 249 DISALLOW_COPY_AND_ASSIGN(ScavengerVisitor); |
| 256 }; | 250 }; |
| 257 | 251 |
| 258 | 252 |
| 259 class ScavengerWeakVisitor : public HandleVisitor { | 253 class ScavengerWeakVisitor : public HandleVisitor { |
| 260 public: | 254 public: |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 296 private: | 290 private: |
| 297 MemoryRegion* to_; | 291 MemoryRegion* to_; |
| 298 | 292 |
| 299 DISALLOW_COPY_AND_ASSIGN(VerifyStoreBufferPointerVisitor); | 293 DISALLOW_COPY_AND_ASSIGN(VerifyStoreBufferPointerVisitor); |
| 300 }; | 294 }; |
| 301 | 295 |
| 302 | 296 |
| 303 Scavenger::Scavenger(Heap* heap, intptr_t max_capacity, uword object_alignment) | 297 Scavenger::Scavenger(Heap* heap, intptr_t max_capacity, uword object_alignment) |
| 304 : heap_(heap), | 298 : heap_(heap), |
| 305 object_alignment_(object_alignment), | 299 object_alignment_(object_alignment), |
| 306 count_(0), | |
| 307 scavenging_(false) { | 300 scavenging_(false) { |
| 308 // Verify assumptions about the first word in objects which the scavenger is | 301 // Verify assumptions about the first word in objects which the scavenger is |
| 309 // going to use for forwarding pointers. | 302 // going to use for forwarding pointers. |
| 310 ASSERT(Object::tags_offset() == 0); | 303 ASSERT(Object::tags_offset() == 0); |
| 311 ASSERT(kForwardingMask == (1 << RawObject::kFreeBit)); | 304 ASSERT(kForwardingMask == (1 << RawObject::kFreeBit)); |
| 312 | 305 |
| 313 // Allocate the virtual memory for this scavenge heap. | 306 // Allocate the virtual memory for this scavenge heap. |
| 314 space_ = VirtualMemory::Reserve(max_capacity); | 307 space_ = VirtualMemory::Reserve(max_capacity); |
| 315 ASSERT(space_ != NULL); | 308 ASSERT(space_ != NULL); |
| 316 | 309 |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 410 } | 403 } |
| 411 handled++; | 404 handled++; |
| 412 if (handled == count) { | 405 if (handled == count) { |
| 413 break; | 406 break; |
| 414 } | 407 } |
| 415 } | 408 } |
| 416 } | 409 } |
| 417 delete pending; | 410 delete pending; |
| 418 pending = next; | 411 pending = next; |
| 419 } | 412 } |
| 420 if (FLAG_verbose_gc) { | 413 heap_->RecordData(0, entries); |
| 421 OS::PrintErr("StoreBuffer: %"Pd", %"Pd" (entries, dups)\n", | 414 heap_->RecordData(1, duplicates); |
| 422 entries, duplicates); | |
| 423 } | |
| 424 StoreBufferBlock* block = isolate->store_buffer_block(); | 415 StoreBufferBlock* block = isolate->store_buffer_block(); |
| 425 entries = block->Count(); | 416 entries = block->Count(); |
| 426 duplicates = 0; | 417 duplicates = 0; |
| 427 for (intptr_t i = 0; i < entries; i++) { | 418 for (intptr_t i = 0; i < entries; i++) { |
| 428 RawObject** pointer = reinterpret_cast<RawObject**>(block->At(i)); | 419 RawObject** pointer = reinterpret_cast<RawObject**>(block->At(i)); |
| 429 RawObject* value = *pointer; | 420 RawObject* value = *pointer; |
| 430 if (value->IsHeapObject()) { | 421 if (value->IsHeapObject()) { |
| 431 if (from_->Contains(RawObject::ToAddr(value))) { | 422 if (from_->Contains(RawObject::ToAddr(value))) { |
| 432 visitor->VisitPointer(pointer); | 423 visitor->VisitPointer(pointer); |
| 433 } else { | 424 } else { |
| 434 duplicates++; | 425 duplicates++; |
| 435 } | 426 } |
| 436 } | 427 } |
| 437 } | 428 } |
| 438 block->Reset(); | 429 block->Reset(); |
| 439 if (FLAG_verbose_gc) { | 430 heap_->RecordData(2, entries); |
| 440 OS::PrintErr("StoreBufferBlock: %"Pd", %"Pd" (entries, dups)\n", | 431 heap_->RecordData(3, duplicates); |
|
siva
2013/01/04 01:40:12
It might be more readable to have an enumeration o
Ivan Posva
2013/01/04 02:14:31
Done. Here and in pages.cc
| |
| 441 entries, duplicates); | |
| 442 } | |
| 443 } | 432 } |
| 444 | 433 |
| 445 | 434 |
| 446 void Scavenger::IterateRoots(Isolate* isolate, | 435 void Scavenger::IterateRoots(Isolate* isolate, |
| 447 ScavengerVisitor* visitor, | 436 ScavengerVisitor* visitor, |
| 448 bool visit_prologue_weak_persistent_handles) { | 437 bool visit_prologue_weak_persistent_handles) { |
| 449 IterateStoreBuffers(isolate, visitor); | 438 int64_t start = OS::GetCurrentTimeMicros(); |
| 450 isolate->VisitObjectPointers(visitor, | 439 isolate->VisitObjectPointers(visitor, |
| 451 visit_prologue_weak_persistent_handles, | 440 visit_prologue_weak_persistent_handles, |
| 452 StackFrameIterator::kDontValidateFrames); | 441 StackFrameIterator::kDontValidateFrames); |
| 442 int64_t middle = OS::GetCurrentTimeMicros(); | |
| 443 IterateStoreBuffers(isolate, visitor); | |
| 444 int64_t end = OS::GetCurrentTimeMicros(); | |
| 445 heap_->RecordTime(0, middle - start); | |
| 446 heap_->RecordTime(1, end - middle); | |
| 453 } | 447 } |
| 454 | 448 |
| 455 | 449 |
| 456 bool Scavenger::IsUnreachable(RawObject** p) { | 450 bool Scavenger::IsUnreachable(RawObject** p) { |
| 457 RawObject* raw_obj = *p; | 451 RawObject* raw_obj = *p; |
| 458 if (!raw_obj->IsHeapObject()) { | 452 if (!raw_obj->IsHeapObject()) { |
| 459 return false; | 453 return false; |
| 460 } | 454 } |
| 461 if (!raw_obj->IsNewObject()) { | 455 if (!raw_obj->IsNewObject()) { |
| 462 return false; | 456 return false; |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 619 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { | 613 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { |
| 620 uword cur = FirstObjectStart(); | 614 uword cur = FirstObjectStart(); |
| 621 while (cur < top_) { | 615 while (cur < top_) { |
| 622 RawObject* raw_obj = RawObject::FromAddr(cur); | 616 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 623 visitor->VisitObject(raw_obj); | 617 visitor->VisitObject(raw_obj); |
| 624 cur += raw_obj->Size(); | 618 cur += raw_obj->Size(); |
| 625 } | 619 } |
| 626 } | 620 } |
| 627 | 621 |
| 628 | 622 |
| 629 void Scavenger::Scavenge(const char* gc_reason) { | 623 void Scavenger::Scavenge() { |
| 630 // TODO(cshapiro): Add a decision procedure for determining when the | 624 // TODO(cshapiro): Add a decision procedure for determining when the |
| 631 // the API callbacks should be invoked. | 625 // the API callbacks should be invoked. |
| 632 Scavenge(false, gc_reason); | 626 Scavenge(false); |
| 633 } | 627 } |
| 634 | 628 |
| 635 | 629 |
| 636 void Scavenger::Scavenge(bool invoke_api_callbacks, const char* gc_reason) { | 630 void Scavenger::Scavenge(bool invoke_api_callbacks) { |
| 637 // Scavenging is not reentrant. Make sure that is the case. | 631 // Scavenging is not reentrant. Make sure that is the case. |
| 638 ASSERT(!scavenging_); | 632 ASSERT(!scavenging_); |
| 639 scavenging_ = true; | 633 scavenging_ = true; |
| 640 had_promotion_failure_ = false; | 634 had_promotion_failure_ = false; |
| 641 Isolate* isolate = Isolate::Current(); | 635 Isolate* isolate = Isolate::Current(); |
| 642 NoHandleScope no_handles(isolate); | 636 NoHandleScope no_handles(isolate); |
| 643 | 637 |
| 644 if (FLAG_verify_before_gc) { | 638 if (FLAG_verify_before_gc) { |
| 645 OS::PrintErr("Verifying before Scavenge..."); | 639 OS::PrintErr("Verifying before Scavenge..."); |
| 646 heap_->Verify(); | 640 heap_->Verify(); |
| 647 OS::PrintErr(" done.\n"); | 641 OS::PrintErr(" done.\n"); |
| 648 } | 642 } |
| 649 | 643 |
| 650 if (FLAG_verbose_gc) { | |
| 651 OS::PrintErr("Start scavenge for %s collection\n", gc_reason); | |
| 652 } | |
| 653 uword prev_first_obj_start = FirstObjectStart(); | 644 uword prev_first_obj_start = FirstObjectStart(); |
| 654 uword prev_top_addr = *(TopAddress()); | 645 uword prev_top_addr = *(TopAddress()); |
| 655 Timer timer(FLAG_verbose_gc, "Scavenge"); | |
| 656 timer.Start(); | |
| 657 | |
| 658 intptr_t in_use_before = in_use(); | |
| 659 | 646 |
| 660 // Setup the visitor and run a scavenge. | 647 // Setup the visitor and run a scavenge. |
| 661 ScavengerVisitor visitor(isolate, this); | 648 ScavengerVisitor visitor(isolate, this); |
| 662 Prologue(isolate, invoke_api_callbacks); | 649 Prologue(isolate, invoke_api_callbacks); |
| 663 IterateRoots(isolate, &visitor, !invoke_api_callbacks); | 650 IterateRoots(isolate, &visitor, !invoke_api_callbacks); |
| 651 int64_t start = OS::GetCurrentTimeMicros(); | |
| 664 ProcessToSpace(&visitor); | 652 ProcessToSpace(&visitor); |
| 653 int64_t middle = OS::GetCurrentTimeMicros(); | |
| 665 IterateWeakReferences(isolate, &visitor); | 654 IterateWeakReferences(isolate, &visitor); |
| 666 ScavengerWeakVisitor weak_visitor(this); | 655 ScavengerWeakVisitor weak_visitor(this); |
| 667 IterateWeakRoots(isolate, &weak_visitor, invoke_api_callbacks); | 656 IterateWeakRoots(isolate, &weak_visitor, invoke_api_callbacks); |
| 668 visitor.Finalize(); | 657 visitor.Finalize(); |
| 669 ProcessPeerReferents(); | 658 ProcessPeerReferents(); |
| 659 int64_t end = OS::GetCurrentTimeMicros(); | |
| 660 heap_->RecordTime(2, middle - start); | |
| 661 heap_->RecordTime(3, end - middle); | |
|
siva
2013/01/04 01:40:12
Ditto for these 0, 1, 2, 3 values.
| |
| 670 Epilogue(isolate, invoke_api_callbacks); | 662 Epilogue(isolate, invoke_api_callbacks); |
| 671 timer.Stop(); | |
| 672 | |
| 673 if (FLAG_verbose_gc) { | |
| 674 const intptr_t KB2 = KB / 2; | |
| 675 double survival = ((in_use() + visitor.bytes_promoted()) / | |
| 676 static_cast<double>(in_use_before)) * 100.0; | |
| 677 double promoted = (visitor.bytes_promoted() / | |
| 678 static_cast<double>(in_use() + visitor.bytes_promoted())) | |
| 679 * 100.0; | |
| 680 OS::PrintErr("Scavenge[%d]: %"Pd64"us (%"Pd"K -> %"Pd"K, %"Pd"K)\n" | |
| 681 "Surviving %"Pd"K %.1f%%\n" | |
| 682 "Promoted survivors %"Pd"K %.1f%%\n", | |
| 683 count_, | |
| 684 timer.TotalElapsedTime(), | |
| 685 (in_use_before + KB2) / KB, | |
| 686 (in_use() + KB2) / KB, | |
| 687 (capacity() + KB2) / KB, | |
| 688 (in_use() + visitor.bytes_promoted() + KB2) / KB, | |
| 689 survival, | |
| 690 (visitor.bytes_promoted() + KB2) / KB, | |
| 691 promoted); | |
| 692 } | |
| 693 | 663 |
| 694 if (FLAG_verify_after_gc) { | 664 if (FLAG_verify_after_gc) { |
| 695 OS::PrintErr("Verifying after Scavenge..."); | 665 OS::PrintErr("Verifying after Scavenge..."); |
| 696 heap_->Verify(); | 666 heap_->Verify(); |
| 697 OS::PrintErr(" done.\n"); | 667 OS::PrintErr(" done.\n"); |
| 698 } | 668 } |
| 699 | 669 |
| 700 if (HeapTrace::is_enabled()) { | 670 if (HeapTrace::is_enabled()) { |
| 701 heap_->trace()->TraceDeathRange(prev_first_obj_start, prev_top_addr); | 671 heap_->trace()->TraceDeathRange(prev_first_obj_start, prev_top_addr); |
| 702 } | 672 } |
| 703 | 673 |
| 704 count_++; | |
| 705 // Done scavenging. Reset the marker. | 674 // Done scavenging. Reset the marker. |
| 706 ASSERT(scavenging_); | 675 ASSERT(scavenging_); |
| 707 scavenging_ = false; | 676 scavenging_ = false; |
| 708 } | 677 } |
| 709 | 678 |
| 710 | 679 |
| 711 void Scavenger::WriteProtect(bool read_only) { | 680 void Scavenger::WriteProtect(bool read_only) { |
| 712 space_->Protect( | 681 space_->Protect( |
| 713 read_only ? VirtualMemory::kReadOnly : VirtualMemory::kReadWrite); | 682 read_only ? VirtualMemory::kReadOnly : VirtualMemory::kReadWrite); |
| 714 } | 683 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 727 PeerTable::iterator it = peer_table_.find(raw_obj); | 696 PeerTable::iterator it = peer_table_.find(raw_obj); |
| 728 return (it == peer_table_.end()) ? NULL : it->second; | 697 return (it == peer_table_.end()) ? NULL : it->second; |
| 729 } | 698 } |
| 730 | 699 |
| 731 | 700 |
| 732 int64_t Scavenger::PeerCount() const { | 701 int64_t Scavenger::PeerCount() const { |
| 733 return static_cast<int64_t>(peer_table_.size()); | 702 return static_cast<int64_t>(peer_table_.size()); |
| 734 } | 703 } |
| 735 | 704 |
| 736 } // namespace dart | 705 } // namespace dart |
| OLD | NEW |