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/gc_marker.h" | 5 #include "vm/gc_marker.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "vm/allocation.h" | 11 #include "vm/allocation.h" |
| 12 #include "vm/dart_api_state.h" | 12 #include "vm/dart_api_state.h" |
| 13 #include "vm/isolate.h" | 13 #include "vm/isolate.h" |
| 14 #include "vm/log.h" | 14 #include "vm/log.h" |
| 15 #include "vm/pages.h" | 15 #include "vm/pages.h" |
| 16 #include "vm/raw_object.h" | 16 #include "vm/raw_object.h" |
| 17 #include "vm/stack_frame.h" | 17 #include "vm/stack_frame.h" |
| 18 #include "vm/store_buffer.h" | 18 #include "vm/store_buffer.h" |
| 19 #include "vm/thread_pool.h" | 19 #include "vm/thread_pool.h" |
| 20 #include "vm/visitor.h" | 20 #include "vm/visitor.h" |
| 21 #include "vm/object_id_ring.h" | 21 #include "vm/object_id_ring.h" |
| 22 | 22 |
| 23 namespace dart { | 23 namespace dart { |
| 24 | 24 |
| 25 DEFINE_FLAG(int, marker_tasks, 1, | |
| 26 "The number of tasks to spawn during old gen GC marking (0 means " | |
| 27 "perform all marking on main thread)."); | |
| 28 | |
| 25 typedef StoreBufferBlock PointerBlock; // TODO(koda): Rename to PointerBlock. | 29 typedef StoreBufferBlock PointerBlock; // TODO(koda): Rename to PointerBlock. |
| 26 typedef StoreBuffer MarkingStack; // TODO(koda): Create shared base class. | 30 typedef StoreBuffer MarkingStack; // TODO(koda): Create shared base class. |
| 27 | 31 |
| 28 class DelaySet { | 32 class DelaySet { |
| 29 private: | 33 private: |
| 30 typedef std::multimap<RawObject*, RawWeakProperty*> Map; | 34 typedef std::multimap<RawObject*, RawWeakProperty*> Map; |
| 31 typedef std::pair<RawObject*, RawWeakProperty*> MapEntry; | 35 typedef std::pair<RawObject*, RawWeakProperty*> MapEntry; |
| 32 | 36 |
| 33 public: | 37 public: |
| 34 DelaySet() : mutex_(new Mutex()) {} | 38 DelaySet() : mutex_(new Mutex()) {} |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 414 } | 418 } |
| 415 } | 419 } |
| 416 | 420 |
| 417 | 421 |
| 418 void GCMarker::IterateRoots(Isolate* isolate, | 422 void GCMarker::IterateRoots(Isolate* isolate, |
| 419 ObjectPointerVisitor* visitor, | 423 ObjectPointerVisitor* visitor, |
| 420 bool visit_prologue_weak_persistent_handles) { | 424 bool visit_prologue_weak_persistent_handles) { |
| 421 isolate->VisitObjectPointers(visitor, | 425 isolate->VisitObjectPointers(visitor, |
| 422 visit_prologue_weak_persistent_handles, | 426 visit_prologue_weak_persistent_handles, |
| 423 StackFrameIterator::kDontValidateFrames); | 427 StackFrameIterator::kDontValidateFrames); |
| 424 heap_->new_space()->VisitObjectPointers(visitor); | 428 isolate->heap()->new_space()->VisitObjectPointers(visitor); |
|
Ivan Posva
2015/08/28 05:23:22
The GCMarker still has a heap_ reference, why has
koda
2015/08/28 13:27:53
Because I made this method static, since it doesn'
| |
| 425 } | 429 } |
| 426 | 430 |
| 427 | 431 |
| 428 void GCMarker::IterateWeakRoots(Isolate* isolate, | 432 void GCMarker::IterateWeakRoots(Isolate* isolate, |
| 429 HandleVisitor* visitor, | 433 HandleVisitor* visitor, |
| 430 bool visit_prologue_weak_persistent_handles) { | 434 bool visit_prologue_weak_persistent_handles) { |
| 431 ApiState* state = isolate->api_state(); | 435 ApiState* state = isolate->api_state(); |
| 432 ASSERT(state != NULL); | 436 ASSERT(state != NULL); |
| 433 isolate->VisitWeakPersistentHandles(visitor, | 437 isolate->VisitWeakPersistentHandles(visitor, |
| 434 visit_prologue_weak_persistent_handles); | 438 visit_prologue_weak_persistent_handles); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 534 | 538 |
| 535 | 539 |
| 536 void GCMarker::ProcessObjectIdTable(Isolate* isolate) { | 540 void GCMarker::ProcessObjectIdTable(Isolate* isolate) { |
| 537 ObjectIdRingClearPointerVisitor visitor(isolate); | 541 ObjectIdRingClearPointerVisitor visitor(isolate); |
| 538 ObjectIdRing* ring = isolate->object_id_ring(); | 542 ObjectIdRing* ring = isolate->object_id_ring(); |
| 539 ASSERT(ring != NULL); | 543 ASSERT(ring != NULL); |
| 540 ring->VisitPointers(&visitor); | 544 ring->VisitPointers(&visitor); |
| 541 } | 545 } |
| 542 | 546 |
| 543 | 547 |
| 548 class MarkTask : public ThreadPool::Task { | |
| 549 public: | |
| 550 MarkTask(GCMarker* marker, | |
| 551 Isolate* isolate, | |
| 552 Heap* heap, | |
| 553 PageSpace* page_space, | |
| 554 MarkingStack* marking_stack, | |
| 555 DelaySet* delay_set, | |
| 556 bool collect_code, | |
| 557 bool invoke_api_callbacks) | |
| 558 : marker_(marker), | |
| 559 isolate_(isolate), | |
| 560 heap_(heap), | |
| 561 page_space_(page_space), | |
| 562 marking_stack_(marking_stack), | |
| 563 delay_set_(delay_set), | |
| 564 collect_code_(collect_code), | |
| 565 invoke_api_callbacks_(invoke_api_callbacks) { | |
| 566 } | |
| 567 | |
| 568 virtual void Run() { | |
| 569 Thread::EnterIsolateAsHelper(isolate_, true); | |
| 570 { | |
| 571 StackZone stack_zone(Thread::Current()); | |
| 572 Zone* zone = stack_zone.GetZone(); | |
| 573 SkippedCodeFunctions* skipped_code_functions = | |
| 574 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL; | |
| 575 MarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_, | |
| 576 delay_set_, skipped_code_functions); | |
| 577 // TODO(koda): Split root iteration work among multiple tasks. | |
| 578 GCMarker::IterateRoots(isolate_, &visitor, !invoke_api_callbacks_); | |
| 579 visitor.DrainMarkingStack(); | |
| 580 marker_->TaskSync(); | |
| 581 // Wait for weak processing on main thread... | |
| 582 marker_->TaskSync(); | |
| 583 // All marking done; detach code, etc. | |
| 584 marker_->FinalizeResultsFrom(&visitor); | |
| 585 } | |
| 586 Thread::ExitIsolateAsHelper(true); | |
| 587 // This task is done. Notify the original thread. | |
| 588 marker_->TaskNotifyDone(); | |
| 589 } | |
| 590 | |
| 591 private: | |
| 592 GCMarker* marker_; | |
| 593 Isolate* isolate_; | |
| 594 Heap* heap_; | |
| 595 PageSpace* page_space_; | |
| 596 MarkingStack* marking_stack_; | |
| 597 DelaySet* delay_set_; | |
| 598 bool collect_code_; | |
| 599 bool invoke_api_callbacks_; | |
| 600 | |
| 601 DISALLOW_COPY_AND_ASSIGN(MarkTask); | |
| 602 }; | |
| 603 | |
| 604 | |
| 605 void GCMarker::MainSync(intptr_t num_tasks) { | |
| 606 MonitorLocker ml(&monitor_); | |
| 607 while (done_count_ < num_tasks) { | |
| 608 ml.Wait(); | |
| 609 } | |
| 610 done_count_ = 0; // Tasks may now resume. | |
| 611 // TODO(koda): Add barrier utility with two condition variables to allow for | |
| 612 // Notify rather than NotifyAll. Also use it for safepoints. | |
| 613 ml.NotifyAll(); | |
| 614 } | |
| 615 | |
| 616 | |
| 617 void GCMarker::TaskNotifyDone() { | |
| 618 MonitorLocker ml(&monitor_); | |
| 619 ++done_count_; | |
| 620 // TODO(koda): Add barrier utility with two condition variables to allow for | |
| 621 // Notify rather than NotifyAll. Also use it for safepoints. | |
| 622 ml.NotifyAll(); | |
| 623 } | |
| 624 | |
| 625 | |
| 626 void GCMarker::TaskSync() { | |
| 627 TaskNotifyDone(); | |
| 628 MonitorLocker ml(&monitor_); | |
| 629 while (done_count_ > 0) { | |
| 630 ml.Wait(); | |
| 631 } | |
| 632 } | |
| 633 | |
| 634 | |
| 635 void GCMarker::FinalizeResultsFrom(MarkingVisitor* visitor) { | |
| 636 { | |
| 637 MonitorLocker ml(&monitor_); | |
| 638 marked_bytes_ += visitor->marked_bytes(); | |
| 639 } | |
| 640 visitor->Finalize(); | |
| 641 } | |
| 642 | |
| 643 | |
| 544 void GCMarker::MarkObjects(Isolate* isolate, | 644 void GCMarker::MarkObjects(Isolate* isolate, |
| 545 PageSpace* page_space, | 645 PageSpace* page_space, |
| 546 bool invoke_api_callbacks, | 646 bool invoke_api_callbacks, |
| 547 bool collect_code) { | 647 bool collect_code) { |
| 548 Prologue(isolate, invoke_api_callbacks); | 648 Prologue(isolate, invoke_api_callbacks); |
| 549 // The API prologue/epilogue may create/destroy zones, so we must not | 649 // The API prologue/epilogue may create/destroy zones, so we must not |
| 550 // depend on zone allocations surviving beyond the epilogue callback. | 650 // depend on zone allocations surviving beyond the epilogue callback. |
| 551 { | 651 { |
| 552 StackZone stack_zone(Thread::Current()); | 652 StackZone stack_zone(Thread::Current()); |
| 553 Zone* zone = stack_zone.GetZone(); | 653 Zone* zone = stack_zone.GetZone(); |
| 554 MarkingStack marking_stack; | 654 MarkingStack marking_stack; |
| 555 DelaySet delay_set; | 655 DelaySet delay_set; |
| 556 SkippedCodeFunctions* skipped_code_functions = | 656 marked_bytes_ = 0; |
| 557 collect_code ? new(zone) SkippedCodeFunctions() : NULL; | 657 const int num_tasks = FLAG_marker_tasks; |
| 558 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, | 658 if (num_tasks == 0) { |
| 559 &delay_set, skipped_code_functions); | 659 // Mark everything on main thread. |
| 560 IterateRoots(isolate, &mark, !invoke_api_callbacks); | 660 SkippedCodeFunctions* skipped_code_functions = |
| 561 mark.DrainMarkingStack(); | 661 collect_code ? new(zone) SkippedCodeFunctions() : NULL; |
| 562 IterateWeakReferences(isolate, &mark); | 662 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, |
| 563 MarkingWeakVisitor mark_weak; | 663 &delay_set, skipped_code_functions); |
| 564 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks); | 664 IterateRoots(isolate, &mark, !invoke_api_callbacks); |
| 565 // TODO(koda): Add hand-over callback. | 665 mark.DrainMarkingStack(); |
| 566 marked_bytes_ = mark.marked_bytes(); | 666 IterateWeakReferences(isolate, &mark); |
| 567 mark.Finalize(); | 667 MarkingWeakVisitor mark_weak; |
| 668 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks); | |
| 669 // All marking done; detach code, etc. | |
| 670 FinalizeResultsFrom(&mark); | |
| 671 } else { | |
| 672 if (num_tasks > 1) { | |
| 673 // TODO(koda): Support multiple: | |
| 674 // 1. non-concurrent tasks, after splitting root iteration work, then | |
| 675 // 2. concurrent tasks, after synchronizing headers. | |
| 676 FATAL("Multiple marking tasks not yet supported"); | |
| 677 } | |
| 678 // Spawn a marking task on a separate thread. | |
| 679 MarkTask* mark_task = | |
| 680 new MarkTask(this, isolate, heap_, page_space, &marking_stack, | |
| 681 &delay_set, collect_code, invoke_api_callbacks); | |
| 682 ThreadPool* pool = Dart::thread_pool(); | |
| 683 pool->Run(mark_task); | |
| 684 MainSync(num_tasks); | |
| 685 { | |
| 686 // Perform weak processing on main thread. | |
| 687 SkippedCodeFunctions* skipped_code_functions = | |
| 688 collect_code ? new(zone) SkippedCodeFunctions() : NULL; | |
| 689 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, | |
| 690 &delay_set, skipped_code_functions); | |
| 691 IterateWeakReferences(isolate, &mark); | |
| 692 MarkingWeakVisitor mark_weak; | |
| 693 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks); | |
| 694 // All marking done; detach code, etc. | |
| 695 FinalizeResultsFrom(&mark); | |
| 696 } | |
| 697 MainSync(num_tasks); | |
| 698 // Wait for mark task finalization... | |
| 699 MainSync(num_tasks); | |
| 700 } | |
| 568 delay_set.ClearReferences(); | 701 delay_set.ClearReferences(); |
| 569 ProcessWeakTables(page_space); | 702 ProcessWeakTables(page_space); |
| 570 ProcessObjectIdTable(isolate); | 703 ProcessObjectIdTable(isolate); |
| 571 } | 704 } |
| 572 Epilogue(isolate, invoke_api_callbacks); | 705 Epilogue(isolate, invoke_api_callbacks); |
| 573 } | 706 } |
| 574 | 707 |
| 575 } // namespace dart | 708 } // namespace dart |
| OLD | NEW |