| 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 354 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 365   } | 365   } | 
| 366   double garbage = stats_history_.Get(0).GarbageFraction(); | 366   double garbage = stats_history_.Get(0).GarbageFraction(); | 
| 367   if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { | 367   if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { | 
| 368     return Utils::Minimum(max_semi_capacity_in_words_, | 368     return Utils::Minimum(max_semi_capacity_in_words_, | 
| 369                           old_size_in_words * FLAG_new_gen_growth_factor); | 369                           old_size_in_words * FLAG_new_gen_growth_factor); | 
| 370   } else { | 370   } else { | 
| 371     return old_size_in_words; | 371     return old_size_in_words; | 
| 372   } | 372   } | 
| 373 } | 373 } | 
| 374 | 374 | 
| 375 SemiSpace* Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { | 375 SemiSpace* Scavenger::Prologue(Isolate* isolate) { | 
| 376   if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { |  | 
| 377     (isolate->gc_prologue_callback())(); |  | 
| 378   } |  | 
| 379   isolate->PrepareForGC(); | 376   isolate->PrepareForGC(); | 
| 380 | 377 | 
| 381   // Flip the two semi-spaces so that to_ is always the space for allocating | 378   // Flip the two semi-spaces so that to_ is always the space for allocating | 
| 382   // objects. | 379   // objects. | 
| 383   SemiSpace* from = to_; | 380   SemiSpace* from = to_; | 
| 384 | 381 | 
| 385   const intptr_t kVmNameSize = 128; | 382   const intptr_t kVmNameSize = 128; | 
| 386   char vm_name[kVmNameSize]; | 383   char vm_name[kVmNameSize]; | 
| 387   Heap::RegionName(heap_, Heap::kNew, vm_name, kVmNameSize); | 384   Heap::RegionName(heap_, Heap::kNew, vm_name, kVmNameSize); | 
| 388   to_ = SemiSpace::New(NewSizeInWords(from->size_in_words()), vm_name); | 385   to_ = SemiSpace::New(NewSizeInWords(from->size_in_words()), vm_name); | 
| 389   if (to_ == NULL) { | 386   if (to_ == NULL) { | 
| 390     // TODO(koda): We could try to recover (collect old space, wait for another | 387     // TODO(koda): We could try to recover (collect old space, wait for another | 
| 391     // isolate to finish scavenge, etc.). | 388     // isolate to finish scavenge, etc.). | 
| 392     OUT_OF_MEMORY(); | 389     OUT_OF_MEMORY(); | 
| 393   } | 390   } | 
| 394   UpdateMaxHeapCapacity(); | 391   UpdateMaxHeapCapacity(); | 
| 395   top_ = FirstObjectStart(); | 392   top_ = FirstObjectStart(); | 
| 396   resolved_top_ = top_; | 393   resolved_top_ = top_; | 
| 397   end_ = to_->end(); | 394   end_ = to_->end(); | 
| 398 | 395 | 
| 399   return from; | 396   return from; | 
| 400 } | 397 } | 
| 401 | 398 | 
| 402 void Scavenger::Epilogue(Isolate* isolate, | 399 void Scavenger::Epilogue(Isolate* isolate, SemiSpace* from) { | 
| 403                          SemiSpace* from, |  | 
| 404                          bool invoke_api_callbacks) { |  | 
| 405   // All objects in the to space have been copied from the from space at this | 400   // All objects in the to space have been copied from the from space at this | 
| 406   // moment. | 401   // moment. | 
| 407 | 402 | 
| 408   // Ensure the mutator thread will fail the next allocation. This will force | 403   // Ensure the mutator thread will fail the next allocation. This will force | 
| 409   // mutator to allocate a new TLAB | 404   // mutator to allocate a new TLAB | 
| 410   Thread* mutator_thread = isolate->mutator_thread(); | 405   Thread* mutator_thread = isolate->mutator_thread(); | 
| 411   ASSERT((mutator_thread == NULL) || (!mutator_thread->HasActiveTLAB())); | 406   ASSERT((mutator_thread == NULL) || (!mutator_thread->HasActiveTLAB())); | 
| 412 | 407 | 
| 413   double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); | 408   double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); | 
| 414   if (stats_history_.Size() >= 2) { | 409   if (stats_history_.Size() >= 2) { | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 435       VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_); | 430       VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_); | 
| 436       heap_->old_space()->VisitObjectPointers(&verify_store_buffer_visitor); | 431       heap_->old_space()->VisitObjectPointers(&verify_store_buffer_visitor); | 
| 437     } | 432     } | 
| 438   } | 433   } | 
| 439 #endif  // defined(DEBUG) | 434 #endif  // defined(DEBUG) | 
| 440   from->Delete(); | 435   from->Delete(); | 
| 441   UpdateMaxHeapUsage(); | 436   UpdateMaxHeapUsage(); | 
| 442   if (heap_ != NULL) { | 437   if (heap_ != NULL) { | 
| 443     heap_->UpdateGlobalMaxUsed(); | 438     heap_->UpdateGlobalMaxUsed(); | 
| 444   } | 439   } | 
| 445   if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { |  | 
| 446     (isolate->gc_epilogue_callback())(); |  | 
| 447   } |  | 
| 448 } | 440 } | 
| 449 | 441 | 
| 450 void Scavenger::IterateStoreBuffers(Isolate* isolate, | 442 void Scavenger::IterateStoreBuffers(Isolate* isolate, | 
| 451                                     ScavengerVisitor* visitor) { | 443                                     ScavengerVisitor* visitor) { | 
| 452   // Iterating through the store buffers. | 444   // Iterating through the store buffers. | 
| 453   // Grab the deduplication sets out of the isolate's consolidated store buffer. | 445   // Grab the deduplication sets out of the isolate's consolidated store buffer. | 
| 454   StoreBufferBlock* pending = isolate->store_buffer()->Blocks(); | 446   StoreBufferBlock* pending = isolate->store_buffer()->Blocks(); | 
| 455   intptr_t total_count = 0; | 447   intptr_t total_count = 0; | 
| 456   while (pending != NULL) { | 448   while (pending != NULL) { | 
| 457     StoreBufferBlock* next = pending->next(); | 449     StoreBufferBlock* next = pending->next(); | 
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 788         return raw_obj;  // Found object, return it. | 780         return raw_obj;  // Found object, return it. | 
| 789       } | 781       } | 
| 790       cur = next; | 782       cur = next; | 
| 791     } | 783     } | 
| 792     ASSERT(cur == top_); | 784     ASSERT(cur == top_); | 
| 793   } | 785   } | 
| 794   return Object::null(); | 786   return Object::null(); | 
| 795 } | 787 } | 
| 796 | 788 | 
| 797 void Scavenger::Scavenge() { | 789 void Scavenger::Scavenge() { | 
| 798   // TODO(cshapiro): Add a decision procedure for determining when the |  | 
| 799   // the API callbacks should be invoked. |  | 
| 800   Scavenge(false); |  | 
| 801 } |  | 
| 802 |  | 
| 803 void Scavenger::Scavenge(bool invoke_api_callbacks) { |  | 
| 804   Isolate* isolate = heap_->isolate(); | 790   Isolate* isolate = heap_->isolate(); | 
| 805   // Ensure that all threads for this isolate are at a safepoint (either stopped | 791   // Ensure that all threads for this isolate are at a safepoint (either stopped | 
| 806   // or in native code). If two threads are racing at this point, the loser | 792   // or in native code). If two threads are racing at this point, the loser | 
| 807   // will continue with its scavenge after waiting for the winner to complete. | 793   // will continue with its scavenge after waiting for the winner to complete. | 
| 808   // TODO(koda): Consider moving SafepointThreads into allocation failure/retry | 794   // TODO(koda): Consider moving SafepointThreads into allocation failure/retry | 
| 809   // logic to avoid needless collections. | 795   // logic to avoid needless collections. | 
| 810 | 796 | 
| 811   int64_t pre_safe_point = OS::GetCurrentMonotonicMicros(); | 797   int64_t pre_safe_point = OS::GetCurrentMonotonicMicros(); | 
| 812 | 798 | 
| 813   Thread* thread = Thread::Current(); | 799   Thread* thread = Thread::Current(); | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 831   if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { | 817   if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { | 
| 832     OS::PrintErr("Verifying before Scavenge..."); | 818     OS::PrintErr("Verifying before Scavenge..."); | 
| 833     heap_->Verify(kForbidMarked); | 819     heap_->Verify(kForbidMarked); | 
| 834     OS::PrintErr(" done.\n"); | 820     OS::PrintErr(" done.\n"); | 
| 835   } | 821   } | 
| 836 | 822 | 
| 837   // Prepare for a scavenge. | 823   // Prepare for a scavenge. | 
| 838   SpaceUsage usage_before = GetCurrentUsage(); | 824   SpaceUsage usage_before = GetCurrentUsage(); | 
| 839   intptr_t promo_candidate_words = | 825   intptr_t promo_candidate_words = | 
| 840       (survivor_end_ - FirstObjectStart()) / kWordSize; | 826       (survivor_end_ - FirstObjectStart()) / kWordSize; | 
| 841   SemiSpace* from = Prologue(isolate, invoke_api_callbacks); | 827   SemiSpace* from = Prologue(isolate); | 
| 842   // The API prologue/epilogue may create/destroy zones, so we must not | 828   // The API prologue/epilogue may create/destroy zones, so we must not | 
| 843   // depend on zone allocations surviving beyond the epilogue callback. | 829   // depend on zone allocations surviving beyond the epilogue callback. | 
| 844   { | 830   { | 
| 845     StackZone zone(thread); | 831     StackZone zone(thread); | 
| 846     // Setup the visitor and run the scavenge. | 832     // Setup the visitor and run the scavenge. | 
| 847     ScavengerVisitor visitor(isolate, this, from); | 833     ScavengerVisitor visitor(isolate, this, from); | 
| 848     page_space->AcquireDataLock(); | 834     page_space->AcquireDataLock(); | 
| 849     IterateRoots(isolate, &visitor); | 835     IterateRoots(isolate, &visitor); | 
| 850     int64_t start = OS::GetCurrentMonotonicMicros(); | 836     int64_t start = OS::GetCurrentMonotonicMicros(); | 
| 851     ProcessToSpace(&visitor); | 837     ProcessToSpace(&visitor); | 
| 852     int64_t middle = OS::GetCurrentMonotonicMicros(); | 838     int64_t middle = OS::GetCurrentMonotonicMicros(); | 
| 853     { | 839     { | 
| 854       TIMELINE_FUNCTION_GC_DURATION(thread, "WeakHandleProcessing"); | 840       TIMELINE_FUNCTION_GC_DURATION(thread, "WeakHandleProcessing"); | 
| 855       ScavengerWeakVisitor weak_visitor(thread, this); | 841       ScavengerWeakVisitor weak_visitor(thread, this); | 
| 856       IterateWeakRoots(isolate, &weak_visitor); | 842       IterateWeakRoots(isolate, &weak_visitor); | 
| 857     } | 843     } | 
| 858     ProcessWeakReferences(); | 844     ProcessWeakReferences(); | 
| 859     page_space->ReleaseDataLock(); | 845     page_space->ReleaseDataLock(); | 
| 860 | 846 | 
| 861     // Scavenge finished. Run accounting. | 847     // Scavenge finished. Run accounting. | 
| 862     int64_t end = OS::GetCurrentMonotonicMicros(); | 848     int64_t end = OS::GetCurrentMonotonicMicros(); | 
| 863     heap_->RecordTime(kProcessToSpace, middle - start); | 849     heap_->RecordTime(kProcessToSpace, middle - start); | 
| 864     heap_->RecordTime(kIterateWeaks, end - middle); | 850     heap_->RecordTime(kIterateWeaks, end - middle); | 
| 865     stats_history_.Add(ScavengeStats( | 851     stats_history_.Add(ScavengeStats( | 
| 866         start, end, usage_before, GetCurrentUsage(), promo_candidate_words, | 852         start, end, usage_before, GetCurrentUsage(), promo_candidate_words, | 
| 867         visitor.bytes_promoted() >> kWordSizeLog2)); | 853         visitor.bytes_promoted() >> kWordSizeLog2)); | 
| 868   } | 854   } | 
| 869   Epilogue(isolate, from, invoke_api_callbacks); | 855   Epilogue(isolate, from); | 
| 870 | 856 | 
| 871   // TODO(koda): Make verification more compatible with concurrent sweep. | 857   // TODO(koda): Make verification more compatible with concurrent sweep. | 
| 872   if (FLAG_verify_after_gc && !FLAG_concurrent_sweep) { | 858   if (FLAG_verify_after_gc && !FLAG_concurrent_sweep) { | 
| 873     OS::PrintErr("Verifying after Scavenge..."); | 859     OS::PrintErr("Verifying after Scavenge..."); | 
| 874     heap_->Verify(kForbidMarked); | 860     heap_->Verify(kForbidMarked); | 
| 875     OS::PrintErr(" done.\n"); | 861     OS::PrintErr(" done.\n"); | 
| 876   } | 862   } | 
| 877 | 863 | 
| 878   // Done scavenging. Reset the marker. | 864   // Done scavenging. Reset the marker. | 
| 879   ASSERT(scavenging_); | 865   ASSERT(scavenging_); | 
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 963   return free_space >> kWordSizeLog2; | 949   return free_space >> kWordSizeLog2; | 
| 964 } | 950 } | 
| 965 | 951 | 
| 966 int64_t Scavenger::UsedInWords() const { | 952 int64_t Scavenger::UsedInWords() const { | 
| 967   int64_t free_space_in_tlab = FreeSpaceInWords(heap_->isolate()); | 953   int64_t free_space_in_tlab = FreeSpaceInWords(heap_->isolate()); | 
| 968   int64_t max_space_used = (top_ - FirstObjectStart()) >> kWordSizeLog2; | 954   int64_t max_space_used = (top_ - FirstObjectStart()) >> kWordSizeLog2; | 
| 969   return max_space_used - free_space_in_tlab; | 955   return max_space_used - free_space_in_tlab; | 
| 970 } | 956 } | 
| 971 | 957 | 
| 972 }  // namespace dart | 958 }  // namespace dart | 
| OLD | NEW | 
|---|