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 16:06:22
heap_
koda
2015/08/28 16:09:09
As I already replied above (on earlier patch set),
Ivan Posva
2015/08/28 16:38:08
Missed that comment, sorry. Then the question is,
| |
| 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 visit_prologue_weak_persistent_handles) | |
| 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 visit_prologue_weak_persistent_handles_( | |
| 566 visit_prologue_weak_persistent_handles) { | |
| 567 } | |
| 568 | |
| 569 virtual void Run() { | |
| 570 Thread::EnterIsolateAsHelper(isolate_, true); | |
| 571 { | |
| 572 StackZone stack_zone(Thread::Current()); | |
| 573 Zone* zone = stack_zone.GetZone(); | |
| 574 SkippedCodeFunctions* skipped_code_functions = | |
| 575 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL; | |
| 576 MarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_, | |
| 577 delay_set_, skipped_code_functions); | |
| 578 // Phase 1: Populate and drain marking stack in task. | |
| 579 // TODO(koda): Split root iteration work among multiple tasks. | |
| 580 GCMarker::IterateRoots(isolate_, &visitor, | |
| 581 visit_prologue_weak_persistent_handles_); | |
| 582 visitor.DrainMarkingStack(); | |
| 583 marker_->TaskSync(); | |
| 584 // Phase 2: Weak processing and follow-up marking on main thread. | |
| 585 marker_->TaskSync(); | |
| 586 // Phase 3: Finalize results from all markers (detach code, etc.). | |
| 587 marker_->FinalizeResultsFrom(&visitor); | |
| 588 } | |
| 589 Thread::ExitIsolateAsHelper(true); | |
| 590 // This task is done. Notify the original thread. | |
| 591 marker_->TaskNotifyDone(); | |
| 592 } | |
| 593 | |
| 594 private: | |
| 595 GCMarker* marker_; | |
| 596 Isolate* isolate_; | |
| 597 Heap* heap_; | |
| 598 PageSpace* page_space_; | |
| 599 MarkingStack* marking_stack_; | |
| 600 DelaySet* delay_set_; | |
| 601 bool collect_code_; | |
| 602 bool visit_prologue_weak_persistent_handles_; | |
| 603 | |
| 604 DISALLOW_COPY_AND_ASSIGN(MarkTask); | |
| 605 }; | |
| 606 | |
| 607 | |
| 608 void GCMarker::MainSync(intptr_t num_tasks) { | |
| 609 MonitorLocker ml(&monitor_); | |
| 610 while (done_count_ < num_tasks) { | |
| 611 ml.Wait(); | |
| 612 } | |
| 613 done_count_ = 0; // Tasks may now resume. | |
| 614 // TODO(koda): Add barrier utility with two condition variables to allow for | |
| 615 // Notify rather than NotifyAll. Also use it for safepoints. | |
| 616 ml.NotifyAll(); | |
| 617 } | |
| 618 | |
| 619 | |
| 620 void GCMarker::TaskNotifyDone() { | |
| 621 MonitorLocker ml(&monitor_); | |
| 622 ++done_count_; | |
| 623 // TODO(koda): Add barrier utility with two condition variables to allow for | |
| 624 // Notify rather than NotifyAll. Also use it for safepoints. | |
| 625 ml.NotifyAll(); | |
| 626 } | |
| 627 | |
| 628 | |
| 629 void GCMarker::TaskSync() { | |
| 630 MonitorLocker ml(&monitor_); | |
| 631 ++done_count_; | |
| 632 ml.NotifyAll(); // Notify controller that this thread reached end of phase. | |
| 633 ASSERT(done_count_ > 0); | |
| 634 while (done_count_ > 0) { | |
| 635 // Wait for the controller to release into next phase. | |
| 636 ml.Wait(); | |
| 637 } | |
| 638 } | |
| 639 | |
| 640 | |
| 641 void GCMarker::FinalizeResultsFrom(MarkingVisitor* visitor) { | |
| 642 { | |
| 643 MonitorLocker ml(&monitor_); | |
| 644 marked_bytes_ += visitor->marked_bytes(); | |
| 645 } | |
| 646 visitor->Finalize(); | |
| 647 } | |
| 648 | |
| 649 | |
| 544 void GCMarker::MarkObjects(Isolate* isolate, | 650 void GCMarker::MarkObjects(Isolate* isolate, |
| 545 PageSpace* page_space, | 651 PageSpace* page_space, |
| 546 bool invoke_api_callbacks, | 652 bool invoke_api_callbacks, |
| 547 bool collect_code) { | 653 bool collect_code) { |
| 548 Prologue(isolate, invoke_api_callbacks); | 654 Prologue(isolate, invoke_api_callbacks); |
| 549 // The API prologue/epilogue may create/destroy zones, so we must not | 655 // The API prologue/epilogue may create/destroy zones, so we must not |
| 550 // depend on zone allocations surviving beyond the epilogue callback. | 656 // depend on zone allocations surviving beyond the epilogue callback. |
| 551 { | 657 { |
| 552 StackZone stack_zone(Thread::Current()); | 658 StackZone stack_zone(Thread::Current()); |
| 553 Zone* zone = stack_zone.GetZone(); | 659 Zone* zone = stack_zone.GetZone(); |
| 554 MarkingStack marking_stack; | 660 MarkingStack marking_stack; |
| 555 DelaySet delay_set; | 661 DelaySet delay_set; |
| 556 SkippedCodeFunctions* skipped_code_functions = | 662 const bool visit_prologue_weak_persistent_handles = !invoke_api_callbacks; |
| 557 collect_code ? new(zone) SkippedCodeFunctions() : NULL; | 663 marked_bytes_ = 0; |
| 558 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, | 664 const int num_tasks = FLAG_marker_tasks; |
| 559 &delay_set, skipped_code_functions); | 665 if (num_tasks == 0) { |
| 560 IterateRoots(isolate, &mark, !invoke_api_callbacks); | 666 // Mark everything on main thread. |
| 561 mark.DrainMarkingStack(); | 667 SkippedCodeFunctions* skipped_code_functions = |
| 562 IterateWeakReferences(isolate, &mark); | 668 collect_code ? new(zone) SkippedCodeFunctions() : NULL; |
| 563 MarkingWeakVisitor mark_weak; | 669 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, |
| 564 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks); | 670 &delay_set, skipped_code_functions); |
| 565 // TODO(koda): Add hand-over callback. | 671 IterateRoots(isolate, &mark, visit_prologue_weak_persistent_handles); |
| 566 marked_bytes_ = mark.marked_bytes(); | 672 mark.DrainMarkingStack(); |
| 567 mark.Finalize(); | 673 IterateWeakReferences(isolate, &mark); |
| 674 MarkingWeakVisitor mark_weak; | |
| 675 IterateWeakRoots(isolate, &mark_weak, | |
| 676 !visit_prologue_weak_persistent_handles); | |
| 677 // All marking done; detach code, etc. | |
| 678 FinalizeResultsFrom(&mark); | |
| 679 } else { | |
| 680 if (num_tasks > 1) { | |
| 681 // TODO(koda): Support multiple: | |
| 682 // 1. non-concurrent tasks, after splitting root iteration work, then | |
| 683 // 2. concurrent tasks, after synchronizing headers. | |
| 684 FATAL("Multiple marking tasks not yet supported"); | |
| 685 } | |
| 686 // Phase 1: Populate and drain marking stack in task. | |
| 687 MarkTask* mark_task = | |
| 688 new MarkTask(this, isolate, heap_, page_space, &marking_stack, | |
| 689 &delay_set, collect_code, | |
| 690 visit_prologue_weak_persistent_handles); | |
| 691 ThreadPool* pool = Dart::thread_pool(); | |
| 692 pool->Run(mark_task); | |
| 693 MainSync(num_tasks); | |
| 694 // Phase 2: Weak processing and follow-up marking on main thread. | |
| 695 SkippedCodeFunctions* skipped_code_functions = | |
| 696 collect_code ? new(zone) SkippedCodeFunctions() : NULL; | |
| 697 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, | |
| 698 &delay_set, skipped_code_functions); | |
| 699 IterateWeakReferences(isolate, &mark); | |
| 700 MarkingWeakVisitor mark_weak; | |
| 701 IterateWeakRoots(isolate, &mark_weak, | |
| 702 !visit_prologue_weak_persistent_handles); | |
| 703 // TODO(koda): Move this into Phase 3 after making ISL_Print thread-safe | |
| 704 // (used in SkippedCodeFunctions::DetachCode). | |
| 705 FinalizeResultsFrom(&mark); | |
| 706 MainSync(num_tasks); | |
| 707 // Phase 3: Finalize results from all markers (detach code, etc.). | |
| 708 MainSync(num_tasks); | |
| 709 // Finalization complete and all tasks exited. | |
| 710 } | |
| 568 delay_set.ClearReferences(); | 711 delay_set.ClearReferences(); |
| 569 ProcessWeakTables(page_space); | 712 ProcessWeakTables(page_space); |
| 570 ProcessObjectIdTable(isolate); | 713 ProcessObjectIdTable(isolate); |
| 571 } | 714 } |
| 572 Epilogue(isolate, invoke_api_callbacks); | 715 Epilogue(isolate, invoke_api_callbacks); |
| 573 } | 716 } |
| 574 | 717 |
| 575 } // namespace dart | 718 } // namespace dart |
| OLD | NEW |