Chromium Code Reviews| Index: runtime/vm/gc_marker.cc |
| diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc |
| index 069f34175990a492b4c75280f2062e1e58ad0153..5004920b71cb1dd6a43beca1a9674a0de79fc410 100644 |
| --- a/runtime/vm/gc_marker.cc |
| +++ b/runtime/vm/gc_marker.cc |
| @@ -177,12 +177,43 @@ class MarkingVisitorBase : public ObjectPointerVisitor { |
| return class_stats_size_[class_id]; |
| } |
| - // Returns true if some non-zero amount of work was performed. |
| - bool DrainMarkingStack() { |
| + bool ProcessPendingWeakProperties() { |
| + bool marked = false; |
| + 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()) { |
| + RawObject* raw_val = cur_weak->ptr()->value_; |
| + marked = marked || (raw_val->IsHeapObject() && !raw_val->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); |
| + } |
| + |
| + return marked; |
| + } |
| + |
| + void DrainMarkingStack() { |
| RawObject* raw_obj = work_list_.Pop(); |
| + if ((raw_obj == NULL) && ProcessPendingWeakProperties()) { |
| + raw_obj = work_list_.Pop(); |
| + } |
| + |
| if (raw_obj == NULL) { |
| ASSERT(visiting_old_object_ == NULL); |
| - return false; |
| + return; |
| } |
| do { |
| do { |
| @@ -200,33 +231,13 @@ class MarkingVisitorBase : public ObjectPointerVisitor { |
| } 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); |
| - } |
| + ProcessPendingWeakProperties(); |
| // 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); |
| - return true; |
| } |
| void VisitPointers(RawObject** first, RawObject** last) { |
| @@ -282,6 +293,7 @@ class MarkingVisitorBase : public ObjectPointerVisitor { |
| while (cur_weak != NULL) { |
| uword next_weak = cur_weak->ptr()->next_; |
| cur_weak->ptr()->next_ = 0; |
| + RELEASE_ASSERT(!cur_weak->ptr()->key_->IsMarked()); |
| WeakProperty::Clear(cur_weak); |
| weak_properties_cleared++; |
| // Advance to next weak property in the queue. |
| @@ -569,28 +581,54 @@ class MarkTask : public ThreadPool::Task { |
| skipped_code_functions); |
| // Phase 1: Iterate over roots and drain marking stack in tasks. |
| marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_); |
| - do { |
| - visitor.DrainMarkingStack(); |
| - // I can't find more work right now. If no other task is busy, |
| - // then there will never be more work (NB: 1 is *before* decrement). |
| - if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break; |
| - |
| - // Wait for some work to appear. |
| - // TODO(iposva): Replace busy-waiting with a solution using Monitor, |
| - // and redraw the boundaries between stack/visitor/task as needed. |
| - while (marking_stack_->IsEmpty() && |
| - AtomicOperations::LoadRelaxed(num_busy_) > 0) { |
| + bool more_to_mark = false; |
| + do { |
| + do { |
| + visitor.DrainMarkingStack(); |
| + |
| + // I can't find more work right now. If no other task is busy, |
| + // then there will never be more work (NB: 1 is *before* decrement). |
| + if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break; |
| + |
| + // Wait for some work to appear. |
| + // TODO(iposva): Replace busy-waiting with a solution using Monitor, |
| + // and redraw the boundaries between stack/visitor/task as needed. |
| + while (marking_stack_->IsEmpty() && |
| + AtomicOperations::LoadRelaxed(num_busy_) > 0) { |
| + } |
| + |
| + // If no tasks are busy, there will never be more work. |
| + if (AtomicOperations::LoadRelaxed(num_busy_) == 0) break; |
| + |
| + // I saw some work; get busy and compete for it. |
| + AtomicOperations::FetchAndIncrement(num_busy_); |
| + } while (true); |
| + // Wait for all markers to stop. |
| + barrier_->Sync(); |
| + ASSERT(AtomicOperations::LoadRelaxed(num_busy_) == 0); |
| + |
| + // Check if we have any pending properties with marked keys. |
| + // Those might have been marked by another marker. |
| + more_to_mark = visitor.ProcessPendingWeakProperties(); |
| + if (more_to_mark) { |
| + // We have more work to do. Notify others. |
| + AtomicOperations::FetchAndIncrement(num_busy_); |
| } |
| - // If no tasks are busy, there will never be more work. |
| - if (AtomicOperations::LoadRelaxed(num_busy_) == 0) break; |
| - |
| - // I saw some work; get busy and compete for it. |
| - AtomicOperations::FetchAndIncrement(num_busy_); |
| - } while (true); |
| - ASSERT(AtomicOperations::LoadRelaxed(num_busy_) == 0); |
| - barrier_->Sync(); |
| + // Wait for all other markers to finish processing their pending |
| + // weak properties and decide if they need to continue marking. |
| + // Caveat: we need two barriers here to make this decision in lock step |
| + // between all markers and the main thread. |
| + barrier_->Sync(); |
| + if (!more_to_mark && (AtomicOperations::LoadRelaxed(num_busy_) > 0)) { |
| + // All markers continue to marker as long as any single marker has |
| + // some work to do. |
| + AtomicOperations::FetchAndIncrement(num_busy_); |
| + more_to_mark = true; |
| + } |
| + barrier_->Sync(); |
|
siva
2016/06/08 19:45:20
Why is this barrier_->Sync() necessary? At this po
Vyacheslav Egorov (Google)
2016/06/09 08:17:05
Because strictly speaking one thread that has work
siva
2016/06/09 16:39:53
True if we let the threads run we get into a scena
|
| + } while (more_to_mark); |
| // Phase 2: Weak processing and follow-up marking on main thread. |
| barrier_->Sync(); |
| @@ -688,7 +726,19 @@ void GCMarker::MarkObjects(Isolate* isolate, |
| ThreadPool* pool = Dart::thread_pool(); |
| pool->Run(mark_task); |
| } |
| - barrier.Sync(); |
| + bool more_to_mark = false; |
| + do { |
| + // Wait for all markers to stop. |
| + barrier.Sync(); |
| + |
| + // Wait for all markers to go through weak properties and verify |
| + // that there are no more objects to mark. |
| + // Note: we need to have two barriers here because we want all markers |
| + // and main thread to make decisions in lock step. |
| + barrier.Sync(); |
|
siva
2016/06/08 19:45:20
back to back barrier.Sync() calls with no code bet
Vyacheslav Egorov (Google)
2016/06/09 08:17:06
These barriers correspond to barriers in the marke
siva
2016/06/09 16:39:53
Acknowledged.
|
| + more_to_mark = AtomicOperations::LoadRelaxed(&num_busy) > 0; |
| + barrier.Sync(); |
| + } while (more_to_mark); |
|
siva
2016/06/08 19:45:20
Is this loop necessary could we just assert after
Vyacheslav Egorov (Google)
2016/06/09 08:17:05
Yes, the loop is necessary, because there is a loo
siva
2016/06/09 16:39:53
Acknowledged.
|
| // Phase 2: Weak processing on main thread. |
| { |