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 |