| 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/gc_marker.h" | 5 #include "vm/gc_marker.h" |
| 6 | 6 |
| 7 #include "vm/allocation.h" | 7 #include "vm/allocation.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/log.h" | 10 #include "vm/log.h" |
| 11 #include "vm/object_id_ring.h" |
| 11 #include "vm/pages.h" | 12 #include "vm/pages.h" |
| 12 #include "vm/raw_object.h" | 13 #include "vm/raw_object.h" |
| 13 #include "vm/stack_frame.h" | 14 #include "vm/stack_frame.h" |
| 14 #include "vm/store_buffer.h" | 15 #include "vm/store_buffer.h" |
| 15 #include "vm/thread_barrier.h" | 16 #include "vm/thread_barrier.h" |
| 16 #include "vm/thread_pool.h" | 17 #include "vm/thread_pool.h" |
| 17 #include "vm/thread_registry.h" | 18 #include "vm/thread_registry.h" |
| 18 #include "vm/timeline.h" | 19 #include "vm/timeline.h" |
| 19 #include "vm/visitor.h" | 20 #include "vm/visitor.h" |
| 20 #include "vm/object_id_ring.h" | |
| 21 | 21 |
| 22 namespace dart { | 22 namespace dart { |
| 23 | 23 |
| 24 class SkippedCodeFunctions : public ZoneAllocated { | 24 class SkippedCodeFunctions : public ZoneAllocated { |
| 25 public: | 25 public: |
| 26 SkippedCodeFunctions() {} | 26 SkippedCodeFunctions() {} |
| 27 | 27 |
| 28 void Add(RawFunction* func) { skipped_code_functions_.Add(func); } | 28 void Add(RawFunction* func) { skipped_code_functions_.Add(func); } |
| 29 | 29 |
| 30 void DetachCode() { | 30 void DetachCode() { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 skipped_code_functions_.Clear(); | 78 skipped_code_functions_.Clear(); |
| 79 #endif // !DART_PRECOMPILED_RUNTIME | 79 #endif // !DART_PRECOMPILED_RUNTIME |
| 80 } | 80 } |
| 81 | 81 |
| 82 private: | 82 private: |
| 83 GrowableArray<RawFunction*> skipped_code_functions_; | 83 GrowableArray<RawFunction*> skipped_code_functions_; |
| 84 | 84 |
| 85 DISALLOW_COPY_AND_ASSIGN(SkippedCodeFunctions); | 85 DISALLOW_COPY_AND_ASSIGN(SkippedCodeFunctions); |
| 86 }; | 86 }; |
| 87 | 87 |
| 88 | |
| 89 class MarkerWorkList : public ValueObject { | 88 class MarkerWorkList : public ValueObject { |
| 90 public: | 89 public: |
| 91 explicit MarkerWorkList(MarkingStack* marking_stack) | 90 explicit MarkerWorkList(MarkingStack* marking_stack) |
| 92 : marking_stack_(marking_stack) { | 91 : marking_stack_(marking_stack) { |
| 93 work_ = marking_stack_->PopEmptyBlock(); | 92 work_ = marking_stack_->PopEmptyBlock(); |
| 94 } | 93 } |
| 95 | 94 |
| 96 ~MarkerWorkList() { | 95 ~MarkerWorkList() { |
| 97 ASSERT(work_ == NULL); | 96 ASSERT(work_ == NULL); |
| 98 ASSERT(marking_stack_ == NULL); | 97 ASSERT(marking_stack_ == NULL); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 work_ = NULL; | 129 work_ = NULL; |
| 131 // Fail fast on attempts to mark after finalizing. | 130 // Fail fast on attempts to mark after finalizing. |
| 132 marking_stack_ = NULL; | 131 marking_stack_ = NULL; |
| 133 } | 132 } |
| 134 | 133 |
| 135 private: | 134 private: |
| 136 MarkingStack::Block* work_; | 135 MarkingStack::Block* work_; |
| 137 MarkingStack* marking_stack_; | 136 MarkingStack* marking_stack_; |
| 138 }; | 137 }; |
| 139 | 138 |
| 140 | |
| 141 template <bool sync> | 139 template <bool sync> |
| 142 class MarkingVisitorBase : public ObjectPointerVisitor { | 140 class MarkingVisitorBase : public ObjectPointerVisitor { |
| 143 public: | 141 public: |
| 144 MarkingVisitorBase(Isolate* isolate, | 142 MarkingVisitorBase(Isolate* isolate, |
| 145 PageSpace* page_space, | 143 PageSpace* page_space, |
| 146 MarkingStack* marking_stack, | 144 MarkingStack* marking_stack, |
| 147 SkippedCodeFunctions* skipped_code_functions) | 145 SkippedCodeFunctions* skipped_code_functions) |
| 148 : ObjectPointerVisitor(isolate), | 146 : ObjectPointerVisitor(isolate), |
| 149 thread_(Thread::Current()), | 147 thread_(Thread::Current()), |
| 150 #ifndef PRODUCT | 148 #ifndef PRODUCT |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 PageSpace* page_space_; | 407 PageSpace* page_space_; |
| 410 MarkerWorkList work_list_; | 408 MarkerWorkList work_list_; |
| 411 RawWeakProperty* delayed_weak_properties_; | 409 RawWeakProperty* delayed_weak_properties_; |
| 412 RawObject* visiting_old_object_; | 410 RawObject* visiting_old_object_; |
| 413 SkippedCodeFunctions* skipped_code_functions_; | 411 SkippedCodeFunctions* skipped_code_functions_; |
| 414 uintptr_t marked_bytes_; | 412 uintptr_t marked_bytes_; |
| 415 | 413 |
| 416 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitorBase); | 414 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitorBase); |
| 417 }; | 415 }; |
| 418 | 416 |
| 419 | |
| 420 typedef MarkingVisitorBase<false> UnsyncMarkingVisitor; | 417 typedef MarkingVisitorBase<false> UnsyncMarkingVisitor; |
| 421 typedef MarkingVisitorBase<true> SyncMarkingVisitor; | 418 typedef MarkingVisitorBase<true> SyncMarkingVisitor; |
| 422 | 419 |
| 423 | |
| 424 static bool IsUnreachable(const RawObject* raw_obj) { | 420 static bool IsUnreachable(const RawObject* raw_obj) { |
| 425 if (!raw_obj->IsHeapObject()) { | 421 if (!raw_obj->IsHeapObject()) { |
| 426 return false; | 422 return false; |
| 427 } | 423 } |
| 428 if (raw_obj == Object::null()) { | 424 if (raw_obj == Object::null()) { |
| 429 return true; | 425 return true; |
| 430 } | 426 } |
| 431 if (!raw_obj->IsOldObject()) { | 427 if (!raw_obj->IsOldObject()) { |
| 432 return false; | 428 return false; |
| 433 } | 429 } |
| 434 return !raw_obj->IsMarked(); | 430 return !raw_obj->IsMarked(); |
| 435 } | 431 } |
| 436 | 432 |
| 437 | |
| 438 class MarkingWeakVisitor : public HandleVisitor { | 433 class MarkingWeakVisitor : public HandleVisitor { |
| 439 public: | 434 public: |
| 440 explicit MarkingWeakVisitor(Thread* thread) : HandleVisitor(thread) {} | 435 explicit MarkingWeakVisitor(Thread* thread) : HandleVisitor(thread) {} |
| 441 | 436 |
| 442 void VisitHandle(uword addr) { | 437 void VisitHandle(uword addr) { |
| 443 FinalizablePersistentHandle* handle = | 438 FinalizablePersistentHandle* handle = |
| 444 reinterpret_cast<FinalizablePersistentHandle*>(addr); | 439 reinterpret_cast<FinalizablePersistentHandle*>(addr); |
| 445 RawObject* raw_obj = handle->raw(); | 440 RawObject* raw_obj = handle->raw(); |
| 446 if (IsUnreachable(raw_obj)) { | 441 if (IsUnreachable(raw_obj)) { |
| 447 handle->UpdateUnreachable(thread()->isolate()); | 442 handle->UpdateUnreachable(thread()->isolate()); |
| 448 } | 443 } |
| 449 } | 444 } |
| 450 | 445 |
| 451 private: | 446 private: |
| 452 DISALLOW_COPY_AND_ASSIGN(MarkingWeakVisitor); | 447 DISALLOW_COPY_AND_ASSIGN(MarkingWeakVisitor); |
| 453 }; | 448 }; |
| 454 | 449 |
| 455 | |
| 456 void GCMarker::Prologue(Isolate* isolate, bool invoke_api_callbacks) { | 450 void GCMarker::Prologue(Isolate* isolate, bool invoke_api_callbacks) { |
| 457 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { | 451 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { |
| 458 (isolate->gc_prologue_callback())(); | 452 (isolate->gc_prologue_callback())(); |
| 459 } | 453 } |
| 460 isolate->PrepareForGC(); | 454 isolate->PrepareForGC(); |
| 461 // The store buffers will be rebuilt as part of marking, reset them now. | 455 // The store buffers will be rebuilt as part of marking, reset them now. |
| 462 isolate->store_buffer()->Reset(); | 456 isolate->store_buffer()->Reset(); |
| 463 } | 457 } |
| 464 | 458 |
| 465 | |
| 466 void GCMarker::Epilogue(Isolate* isolate, bool invoke_api_callbacks) { | 459 void GCMarker::Epilogue(Isolate* isolate, bool invoke_api_callbacks) { |
| 467 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { | 460 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { |
| 468 (isolate->gc_epilogue_callback())(); | 461 (isolate->gc_epilogue_callback())(); |
| 469 } | 462 } |
| 470 } | 463 } |
| 471 | 464 |
| 472 | |
| 473 void GCMarker::IterateRoots(Isolate* isolate, | 465 void GCMarker::IterateRoots(Isolate* isolate, |
| 474 ObjectPointerVisitor* visitor, | 466 ObjectPointerVisitor* visitor, |
| 475 intptr_t slice_index, | 467 intptr_t slice_index, |
| 476 intptr_t num_slices) { | 468 intptr_t num_slices) { |
| 477 ASSERT(0 <= slice_index && slice_index < num_slices); | 469 ASSERT(0 <= slice_index && slice_index < num_slices); |
| 478 if ((slice_index == 0) || (num_slices <= 1)) { | 470 if ((slice_index == 0) || (num_slices <= 1)) { |
| 479 isolate->VisitObjectPointers(visitor, | 471 isolate->VisitObjectPointers(visitor, |
| 480 StackFrameIterator::kDontValidateFrames); | 472 StackFrameIterator::kDontValidateFrames); |
| 481 } | 473 } |
| 482 if ((slice_index == 1) || (num_slices <= 1)) { | 474 if ((slice_index == 1) || (num_slices <= 1)) { |
| 483 heap_->new_space()->VisitObjectPointers(visitor); | 475 heap_->new_space()->VisitObjectPointers(visitor); |
| 484 } | 476 } |
| 485 | 477 |
| 486 // For now, we just distinguish two parts of the root set, so any remaining | 478 // For now, we just distinguish two parts of the root set, so any remaining |
| 487 // slices are empty. | 479 // slices are empty. |
| 488 } | 480 } |
| 489 | 481 |
| 490 | |
| 491 void GCMarker::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) { | 482 void GCMarker::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) { |
| 492 ApiState* state = isolate->api_state(); | 483 ApiState* state = isolate->api_state(); |
| 493 ASSERT(state != NULL); | 484 ASSERT(state != NULL); |
| 494 isolate->VisitWeakPersistentHandles(visitor); | 485 isolate->VisitWeakPersistentHandles(visitor); |
| 495 } | 486 } |
| 496 | 487 |
| 497 | |
| 498 void GCMarker::ProcessWeakTables(PageSpace* page_space) { | 488 void GCMarker::ProcessWeakTables(PageSpace* page_space) { |
| 499 for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) { | 489 for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) { |
| 500 WeakTable* table = | 490 WeakTable* table = |
| 501 heap_->GetWeakTable(Heap::kOld, static_cast<Heap::WeakSelector>(sel)); | 491 heap_->GetWeakTable(Heap::kOld, static_cast<Heap::WeakSelector>(sel)); |
| 502 intptr_t size = table->size(); | 492 intptr_t size = table->size(); |
| 503 for (intptr_t i = 0; i < size; i++) { | 493 for (intptr_t i = 0; i < size; i++) { |
| 504 if (table->IsValidEntryAt(i)) { | 494 if (table->IsValidEntryAt(i)) { |
| 505 RawObject* raw_obj = table->ObjectAt(i); | 495 RawObject* raw_obj = table->ObjectAt(i); |
| 506 ASSERT(raw_obj->IsHeapObject()); | 496 ASSERT(raw_obj->IsHeapObject()); |
| 507 if (!raw_obj->IsMarked()) { | 497 if (!raw_obj->IsMarked()) { |
| 508 table->InvalidateAt(i); | 498 table->InvalidateAt(i); |
| 509 } | 499 } |
| 510 } | 500 } |
| 511 } | 501 } |
| 512 } | 502 } |
| 513 } | 503 } |
| 514 | 504 |
| 515 | |
| 516 class ObjectIdRingClearPointerVisitor : public ObjectPointerVisitor { | 505 class ObjectIdRingClearPointerVisitor : public ObjectPointerVisitor { |
| 517 public: | 506 public: |
| 518 explicit ObjectIdRingClearPointerVisitor(Isolate* isolate) | 507 explicit ObjectIdRingClearPointerVisitor(Isolate* isolate) |
| 519 : ObjectPointerVisitor(isolate) {} | 508 : ObjectPointerVisitor(isolate) {} |
| 520 | 509 |
| 521 | |
| 522 void VisitPointers(RawObject** first, RawObject** last) { | 510 void VisitPointers(RawObject** first, RawObject** last) { |
| 523 for (RawObject** current = first; current <= last; current++) { | 511 for (RawObject** current = first; current <= last; current++) { |
| 524 RawObject* raw_obj = *current; | 512 RawObject* raw_obj = *current; |
| 525 ASSERT(raw_obj->IsHeapObject()); | 513 ASSERT(raw_obj->IsHeapObject()); |
| 526 if (raw_obj->IsOldObject() && !raw_obj->IsMarked()) { | 514 if (raw_obj->IsOldObject() && !raw_obj->IsMarked()) { |
| 527 // Object has become garbage. Replace it will null. | 515 // Object has become garbage. Replace it will null. |
| 528 *current = Object::null(); | 516 *current = Object::null(); |
| 529 } | 517 } |
| 530 } | 518 } |
| 531 } | 519 } |
| 532 }; | 520 }; |
| 533 | 521 |
| 534 | |
| 535 void GCMarker::ProcessObjectIdTable(Isolate* isolate) { | 522 void GCMarker::ProcessObjectIdTable(Isolate* isolate) { |
| 536 #ifndef PRODUCT | 523 #ifndef PRODUCT |
| 537 if (!FLAG_support_service) { | 524 if (!FLAG_support_service) { |
| 538 return; | 525 return; |
| 539 } | 526 } |
| 540 ObjectIdRingClearPointerVisitor visitor(isolate); | 527 ObjectIdRingClearPointerVisitor visitor(isolate); |
| 541 ObjectIdRing* ring = isolate->object_id_ring(); | 528 ObjectIdRing* ring = isolate->object_id_ring(); |
| 542 ASSERT(ring != NULL); | 529 ASSERT(ring != NULL); |
| 543 ring->VisitPointers(&visitor); | 530 ring->VisitPointers(&visitor); |
| 544 #endif // !PRODUCT | 531 #endif // !PRODUCT |
| 545 } | 532 } |
| 546 | 533 |
| 547 | |
| 548 class MarkTask : public ThreadPool::Task { | 534 class MarkTask : public ThreadPool::Task { |
| 549 public: | 535 public: |
| 550 MarkTask(GCMarker* marker, | 536 MarkTask(GCMarker* marker, |
| 551 Isolate* isolate, | 537 Isolate* isolate, |
| 552 Heap* heap, | 538 Heap* heap, |
| 553 PageSpace* page_space, | 539 PageSpace* page_space, |
| 554 MarkingStack* marking_stack, | 540 MarkingStack* marking_stack, |
| 555 ThreadBarrier* barrier, | 541 ThreadBarrier* barrier, |
| 556 bool collect_code, | 542 bool collect_code, |
| 557 intptr_t task_index, | 543 intptr_t task_index, |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 661 MarkingStack* marking_stack_; | 647 MarkingStack* marking_stack_; |
| 662 ThreadBarrier* barrier_; | 648 ThreadBarrier* barrier_; |
| 663 bool collect_code_; | 649 bool collect_code_; |
| 664 const intptr_t task_index_; | 650 const intptr_t task_index_; |
| 665 const intptr_t num_tasks_; | 651 const intptr_t num_tasks_; |
| 666 uintptr_t* num_busy_; | 652 uintptr_t* num_busy_; |
| 667 | 653 |
| 668 DISALLOW_COPY_AND_ASSIGN(MarkTask); | 654 DISALLOW_COPY_AND_ASSIGN(MarkTask); |
| 669 }; | 655 }; |
| 670 | 656 |
| 671 | |
| 672 template <class MarkingVisitorType> | 657 template <class MarkingVisitorType> |
| 673 void GCMarker::FinalizeResultsFrom(MarkingVisitorType* visitor) { | 658 void GCMarker::FinalizeResultsFrom(MarkingVisitorType* visitor) { |
| 674 { | 659 { |
| 675 MutexLocker ml(&stats_mutex_); | 660 MutexLocker ml(&stats_mutex_); |
| 676 marked_bytes_ += visitor->marked_bytes(); | 661 marked_bytes_ += visitor->marked_bytes(); |
| 677 #ifndef PRODUCT | 662 #ifndef PRODUCT |
| 678 // Class heap stats are not themselves thread-safe yet, so we update the | 663 // Class heap stats are not themselves thread-safe yet, so we update the |
| 679 // stats while holding stats_mutex_. | 664 // stats while holding stats_mutex_. |
| 680 ClassTable* table = heap_->isolate()->class_table(); | 665 ClassTable* table = heap_->isolate()->class_table(); |
| 681 for (intptr_t i = 0; i < table->NumCids(); ++i) { | 666 for (intptr_t i = 0; i < table->NumCids(); ++i) { |
| 682 const intptr_t count = visitor->live_count(i); | 667 const intptr_t count = visitor->live_count(i); |
| 683 if (count > 0) { | 668 if (count > 0) { |
| 684 const intptr_t size = visitor->live_size(i); | 669 const intptr_t size = visitor->live_size(i); |
| 685 table->UpdateLiveOld(i, size, count); | 670 table->UpdateLiveOld(i, size, count); |
| 686 } | 671 } |
| 687 } | 672 } |
| 688 #endif // !PRODUCT | 673 #endif // !PRODUCT |
| 689 } | 674 } |
| 690 visitor->Finalize(); | 675 visitor->Finalize(); |
| 691 } | 676 } |
| 692 | 677 |
| 693 | |
| 694 void GCMarker::MarkObjects(Isolate* isolate, | 678 void GCMarker::MarkObjects(Isolate* isolate, |
| 695 PageSpace* page_space, | 679 PageSpace* page_space, |
| 696 bool invoke_api_callbacks, | 680 bool invoke_api_callbacks, |
| 697 bool collect_code) { | 681 bool collect_code) { |
| 698 Prologue(isolate, invoke_api_callbacks); | 682 Prologue(isolate, invoke_api_callbacks); |
| 699 // The API prologue/epilogue may create/destroy zones, so we must not | 683 // The API prologue/epilogue may create/destroy zones, so we must not |
| 700 // depend on zone allocations surviving beyond the epilogue callback. | 684 // depend on zone allocations surviving beyond the epilogue callback. |
| 701 { | 685 { |
| 702 Thread* thread = Thread::Current(); | 686 Thread* thread = Thread::Current(); |
| 703 StackZone stack_zone(thread); | 687 StackZone stack_zone(thread); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 765 // Phase 3: Finalize results from all markers (detach code, etc.). | 749 // Phase 3: Finalize results from all markers (detach code, etc.). |
| 766 barrier.Exit(); | 750 barrier.Exit(); |
| 767 } | 751 } |
| 768 ProcessWeakTables(page_space); | 752 ProcessWeakTables(page_space); |
| 769 ProcessObjectIdTable(isolate); | 753 ProcessObjectIdTable(isolate); |
| 770 } | 754 } |
| 771 Epilogue(isolate, invoke_api_callbacks); | 755 Epilogue(isolate, invoke_api_callbacks); |
| 772 } | 756 } |
| 773 | 757 |
| 774 } // namespace dart | 758 } // namespace dart |
| OLD | NEW |