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