| Index: runtime/vm/gc_marker.cc
|
| diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
|
| index cc5db20ce64187a265ec23cd2ad5d2cd8b2ecf5e..237b0a2f50388f4e8b9bb17d88a26a552fa3cd5b 100644
|
| --- a/runtime/vm/gc_marker.cc
|
| +++ b/runtime/vm/gc_marker.cc
|
| @@ -4,10 +4,6 @@
|
|
|
| #include "vm/gc_marker.h"
|
|
|
| -#include <map>
|
| -#include <utility>
|
| -#include <vector>
|
| -
|
| #include "vm/allocation.h"
|
| #include "vm/dart_api_state.h"
|
| #include "vm/isolate.h"
|
| @@ -31,64 +27,6 @@ DEFINE_FLAG(int, marker_tasks, 2,
|
| DEFINE_FLAG(bool, log_marker_tasks, false,
|
| "Log debugging information for old gen GC marking tasks.");
|
|
|
| -class DelaySet {
|
| - private:
|
| - typedef std::multimap<RawObject*, RawWeakProperty*> Map;
|
| - typedef std::pair<RawObject*, RawWeakProperty*> MapEntry;
|
| -
|
| - public:
|
| - DelaySet() : mutex_(new Mutex()) {}
|
| - ~DelaySet() { delete mutex_; }
|
| -
|
| - // After atomically setting the watched bit on a white key (see
|
| - // EnsureWatchedIfWhitewhich; this means the mark bit cannot be set
|
| - // without observing the watched bit), this method atomically
|
| - // inserts raw_weak if its key is *still* white, so that any future
|
| - // call to VisitValuesForKey is guaranteed to include its
|
| - // value. Returns true on success, and false if the key is no longer white.
|
| - bool InsertIfWhite(RawWeakProperty* raw_weak) {
|
| - MutexLocker ml(mutex_);
|
| - RawObject* raw_key = raw_weak->ptr()->key_;
|
| - if (raw_key->IsMarked()) return false;
|
| - // The key was white *after* acquiring the lock. Thus any future call to
|
| - // VisitValuesForKey is guaranteed to include the entry inserted below.
|
| - delay_set_.insert(std::make_pair(raw_key, raw_weak));
|
| - return true;
|
| - }
|
| -
|
| - void ClearReferences() {
|
| - MutexLocker ml(mutex_);
|
| - for (Map::iterator it = delay_set_.begin(); it != delay_set_.end(); ++it) {
|
| - ASSERT(!it->first->IsMarked());
|
| - WeakProperty::Clear(it->second);
|
| - }
|
| - }
|
| -
|
| - // Visit all values with a key equal to raw_obj, which must already be marked.
|
| - void VisitValuesForKey(RawObject* raw_obj, ObjectPointerVisitor* visitor) {
|
| - ASSERT(raw_obj->IsMarked());
|
| - // Extract the range into a temporary vector to iterate over it
|
| - // while delay_set_ may be modified.
|
| - std::vector<MapEntry> temp_copy;
|
| - {
|
| - MutexLocker ml(mutex_);
|
| - std::pair<Map::iterator, Map::iterator> ret =
|
| - delay_set_.equal_range(raw_obj);
|
| - temp_copy.insert(temp_copy.end(), ret.first, ret.second);
|
| - delay_set_.erase(ret.first, ret.second);
|
| - }
|
| - for (std::vector<MapEntry>::iterator it = temp_copy.begin();
|
| - it != temp_copy.end(); ++it) {
|
| - it->second->VisitPointers(visitor);
|
| - }
|
| - }
|
| -
|
| - private:
|
| - Map delay_set_;
|
| - Mutex* mutex_;
|
| -};
|
| -
|
| -
|
| class SkippedCodeFunctions : public ZoneAllocated {
|
| public:
|
| SkippedCodeFunctions() {}
|
| @@ -212,7 +150,6 @@ class MarkingVisitorBase : public ObjectPointerVisitor {
|
| Heap* heap,
|
| PageSpace* page_space,
|
| MarkingStack* marking_stack,
|
| - DelaySet* delay_set,
|
| SkippedCodeFunctions* skipped_code_functions)
|
| : ObjectPointerVisitor(isolate),
|
| thread_(Thread::Current()),
|
| @@ -222,7 +159,7 @@ class MarkingVisitorBase : public ObjectPointerVisitor {
|
| class_stats_size_(isolate->class_table()->NumCids()),
|
| page_space_(page_space),
|
| work_list_(marking_stack),
|
| - delay_set_(delay_set),
|
| + delayed_weak_properties_(NULL),
|
| visiting_old_object_(NULL),
|
| skipped_code_functions_(skipped_code_functions),
|
| marked_bytes_(0) {
|
| @@ -254,15 +191,44 @@ class MarkingVisitorBase : public ObjectPointerVisitor {
|
| return false;
|
| }
|
| do {
|
| - VisitingOldObject(raw_obj);
|
| - const intptr_t class_id = raw_obj->GetClassId();
|
| - if (class_id != kWeakPropertyCid) {
|
| - marked_bytes_ += raw_obj->VisitPointers(this);
|
| - } else {
|
| - RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj);
|
| - marked_bytes_ += raw_weak->Size();
|
| - ProcessWeakProperty(raw_weak);
|
| + do {
|
| + // First drain the marking stacks.
|
| + VisitingOldObject(raw_obj);
|
| + const intptr_t class_id = raw_obj->GetClassId();
|
| + if (class_id != kWeakPropertyCid) {
|
| + marked_bytes_ += raw_obj->VisitPointers(this);
|
| + } else {
|
| + RawWeakProperty* raw_weak =
|
| + reinterpret_cast<RawWeakProperty*>(raw_obj);
|
| + marked_bytes_ += ProcessWeakProperty(raw_weak);
|
| + }
|
| + raw_obj = work_list_.Pop();
|
| + } while (raw_obj != NULL);
|
| +
|
| + // Marking stack is empty.
|
| + // Process all the pending weak properties in this visitor.
|
| + RawWeakProperty* cur_weak = delayed_weak_properties_;
|
| + delayed_weak_properties_ = NULL;
|
| + while (cur_weak != NULL) {
|
| + uword next_weak = cur_weak->ptr()->next_;
|
| + RawObject* raw_key = cur_weak->ptr()->key_;
|
| + // Reset the next pointer in the weak property.
|
| + cur_weak->ptr()->next_ = 0;
|
| + if (raw_key->IsMarked()) {
|
| + // The key is marked so we make sure to properly visit all pointers
|
| + // originating from this weak property.
|
| + VisitingOldObject(cur_weak);
|
| + cur_weak->VisitPointers(this);
|
| + } else {
|
| + // Requeue this weak property to be handled later.
|
| + EnqueueWeakProperty(cur_weak);
|
| + }
|
| + // Advance to next weak property in the queue.
|
| + cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak);
|
| }
|
| +
|
| + // Check whether any further work was pushed either by other markers or
|
| + // by the handling of weak properties.
|
| raw_obj = work_list_.Pop();
|
| } while (raw_obj != NULL);
|
| VisitingOldObject(NULL);
|
| @@ -284,47 +250,49 @@ class MarkingVisitorBase : public ObjectPointerVisitor {
|
| skipped_code_functions_->Add(func);
|
| }
|
|
|
| - // If unmarked, sets the watch bit and returns true.
|
| - // If marked, does nothing and returns false.
|
| - static bool EnsureWatchedIfWhite(RawObject* obj) {
|
| - if (!sync) {
|
| - if (obj->IsMarked()) return false;
|
| - if (!obj->IsWatched()) obj->SetWatchedBitUnsynchronized();
|
| - return true;
|
| - }
|
| - uword tags = obj->ptr()->tags_;
|
| - uword old_tags;
|
| - do {
|
| - old_tags = tags;
|
| - if (RawObject::MarkBit::decode(tags)) return false;
|
| - if (RawObject::WatchedBit::decode(tags)) return true;
|
| - uword new_tags = RawObject::WatchedBit::update(true, old_tags);
|
| - tags = AtomicOperations::CompareAndSwapWord(
|
| - &obj->ptr()->tags_, old_tags, new_tags);
|
| - } while (tags != old_tags);
|
| - return true;
|
| + void EnqueueWeakProperty(RawWeakProperty* raw_weak) {
|
| + ASSERT(raw_weak->IsHeapObject());
|
| + ASSERT(raw_weak->IsOldObject());
|
| + ASSERT(raw_weak->IsWeakProperty());
|
| + ASSERT(raw_weak->IsMarked());
|
| + ASSERT(raw_weak->ptr()->next_ == 0);
|
| + raw_weak->ptr()->next_ = reinterpret_cast<uword>(delayed_weak_properties_);
|
| + delayed_weak_properties_ = raw_weak;
|
| }
|
|
|
| - void ProcessWeakProperty(RawWeakProperty* raw_weak) {
|
| + intptr_t ProcessWeakProperty(RawWeakProperty* raw_weak) {
|
| // The fate of the weak property is determined by its key.
|
| RawObject* raw_key = raw_weak->ptr()->key_;
|
| if (raw_key->IsHeapObject() &&
|
| raw_key->IsOldObject() &&
|
| - EnsureWatchedIfWhite(raw_key) &&
|
| - delay_set_->InsertIfWhite(raw_weak)) {
|
| - // Key was white. Delayed the weak property.
|
| - } else {
|
| - // Key is gray or black. Make the weak property black.
|
| - raw_weak->VisitPointers(this);
|
| + !raw_key->IsMarked()) {
|
| + // Key was white. Enqueue the weak property.
|
| + EnqueueWeakProperty(raw_weak);
|
| + return raw_weak->Size();
|
| }
|
| + // Key is gray or black. Make the weak property black.
|
| + return raw_weak->VisitPointers(this);
|
| }
|
|
|
| // Called when all marking is complete.
|
| void Finalize() {
|
| work_list_.Finalize();
|
| + // Detach code from functions.
|
| if (skipped_code_functions_ != NULL) {
|
| skipped_code_functions_->DetachCode();
|
| }
|
| + // Clear pending weak properties.
|
| + RawWeakProperty* cur_weak = delayed_weak_properties_;
|
| + delayed_weak_properties_ = NULL;
|
| + intptr_t weak_properties_cleared = 0;
|
| + while (cur_weak != NULL) {
|
| + uword next_weak = cur_weak->ptr()->next_;
|
| + cur_weak->ptr()->next_ = 0;
|
| + WeakProperty::Clear(cur_weak);
|
| + weak_properties_cleared++;
|
| + // Advance to next weak property in the queue.
|
| + cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak);
|
| + }
|
| }
|
|
|
| void VisitingOldObject(RawObject* obj) {
|
| @@ -341,15 +309,10 @@ class MarkingVisitorBase : public ObjectPointerVisitor {
|
|
|
| // Push the marked object on the marking stack.
|
| ASSERT(raw_obj->IsMarked());
|
| - const bool is_watched = raw_obj->IsWatched();
|
| // We acquired the mark bit => no other task is modifying the header.
|
| // TODO(koda): For concurrent mutator, this needs synchronization. Consider
|
| // clearing these bits already in the CAS for the mark bit.
|
| raw_obj->ClearRememberedBitUnsynchronized();
|
| - raw_obj->ClearWatchedBitUnsynchronized();
|
| - if (is_watched) {
|
| - delay_set_->VisitValuesForKey(raw_obj, this);
|
| - }
|
| work_list_.Push(raw_obj);
|
| }
|
|
|
| @@ -436,7 +399,7 @@ class MarkingVisitorBase : public ObjectPointerVisitor {
|
| GrowableArray<intptr_t> class_stats_size_;
|
| PageSpace* page_space_;
|
| MarkerWorkList work_list_;
|
| - DelaySet* delay_set_;
|
| + RawWeakProperty* delayed_weak_properties_;
|
| RawObject* visiting_old_object_;
|
| SkippedCodeFunctions* skipped_code_functions_;
|
| uintptr_t marked_bytes_;
|
| @@ -580,7 +543,6 @@ class MarkTask : public ThreadPool::Task {
|
| Heap* heap,
|
| PageSpace* page_space,
|
| MarkingStack* marking_stack,
|
| - DelaySet* delay_set,
|
| ThreadBarrier* barrier,
|
| bool collect_code,
|
| intptr_t task_index,
|
| @@ -591,7 +553,6 @@ class MarkTask : public ThreadPool::Task {
|
| heap_(heap),
|
| page_space_(page_space),
|
| marking_stack_(marking_stack),
|
| - delay_set_(delay_set),
|
| barrier_(barrier),
|
| collect_code_(collect_code),
|
| task_index_(task_index),
|
| @@ -611,7 +572,7 @@ class MarkTask : public ThreadPool::Task {
|
| SkippedCodeFunctions* skipped_code_functions =
|
| collect_code_ ? new(zone) SkippedCodeFunctions() : NULL;
|
| SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_,
|
| - delay_set_, skipped_code_functions);
|
| + skipped_code_functions);
|
| // Phase 1: Iterate over roots and drain marking stack in tasks.
|
| marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_);
|
| do {
|
| @@ -659,7 +620,6 @@ class MarkTask : public ThreadPool::Task {
|
| Heap* heap_;
|
| PageSpace* page_space_;
|
| MarkingStack* marking_stack_;
|
| - DelaySet* delay_set_;
|
| ThreadBarrier* barrier_;
|
| bool collect_code_;
|
| const intptr_t task_index_;
|
| @@ -701,7 +661,6 @@ void GCMarker::MarkObjects(Isolate* isolate,
|
| StackZone stack_zone(Thread::Current());
|
| Zone* zone = stack_zone.GetZone();
|
| MarkingStack marking_stack;
|
| - DelaySet delay_set;
|
| marked_bytes_ = 0;
|
| const int num_tasks = FLAG_marker_tasks;
|
| if (num_tasks == 0) {
|
| @@ -709,7 +668,7 @@ void GCMarker::MarkObjects(Isolate* isolate,
|
| SkippedCodeFunctions* skipped_code_functions =
|
| collect_code ? new(zone) SkippedCodeFunctions() : NULL;
|
| UnsyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
|
| - &delay_set, skipped_code_functions);
|
| + skipped_code_functions);
|
| IterateRoots(isolate, &mark, 0, 1);
|
| mark.DrainMarkingStack();
|
| MarkingWeakVisitor mark_weak;
|
| @@ -726,31 +685,21 @@ void GCMarker::MarkObjects(Isolate* isolate,
|
| for (intptr_t i = 0; i < num_tasks; ++i) {
|
| MarkTask* mark_task =
|
| new MarkTask(this, isolate, heap_, page_space, &marking_stack,
|
| - &delay_set, &barrier, collect_code,
|
| + &barrier, collect_code,
|
| i, num_tasks, &num_busy);
|
| ThreadPool* pool = Dart::thread_pool();
|
| pool->Run(mark_task);
|
| }
|
| barrier.Sync();
|
|
|
| - // Phase 2: Weak processing and follow-up marking on main thread.
|
| - SkippedCodeFunctions* skipped_code_functions =
|
| - collect_code ? new(zone) SkippedCodeFunctions() : NULL;
|
| - SyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
|
| - &delay_set, skipped_code_functions);
|
| + // Phase 2: Weak processing on main thread.
|
| MarkingWeakVisitor mark_weak;
|
| IterateWeakRoots(isolate, &mark_weak);
|
| barrier.Sync();
|
|
|
| // Phase 3: Finalize results from all markers (detach code, etc.).
|
| - if (FLAG_log_marker_tasks) {
|
| - THR_Print("Main thread marked %" Pd " bytes.\n",
|
| - mark.marked_bytes());
|
| - }
|
| - FinalizeResultsFrom(&mark);
|
| barrier.Exit();
|
| }
|
| - delay_set.ClearReferences();
|
| ProcessWeakTables(page_space);
|
| ProcessObjectIdTable(isolate);
|
| }
|
|
|