@@ -177,12 +177,43 @@ class MarkingVisitorBase : public ObjectPointerVisitor {
177177 return class_stats_size_[class_id];
178178 }
179179
180- // Returns true if some non-zero amount of work was performed.
181- bool DrainMarkingStack () {
180+ bool ProcessPendingWeakProperties () {
181+ bool marked = false ;
182+ RawWeakProperty* cur_weak = delayed_weak_properties_;
183+ delayed_weak_properties_ = NULL ;
184+ while (cur_weak != NULL ) {
185+ uword next_weak = cur_weak->ptr ()->next_ ;
186+ RawObject* raw_key = cur_weak->ptr ()->key_ ;
187+ // Reset the next pointer in the weak property.
188+ cur_weak->ptr ()->next_ = 0 ;
189+ if (raw_key->IsMarked ()) {
190+ RawObject* raw_val = cur_weak->ptr ()->value_ ;
191+ marked = marked || (raw_val->IsHeapObject () && !raw_val->IsMarked ());
192+
193+ // The key is marked so we make sure to properly visit all pointers
194+ // originating from this weak property.
195+ VisitingOldObject (cur_weak);
196+ cur_weak->VisitPointers (this );
197+ } else {
198+ // Requeue this weak property to be handled later.
199+ EnqueueWeakProperty (cur_weak);
200+ }
201+ // Advance to next weak property in the queue.
202+ cur_weak = reinterpret_cast <RawWeakProperty*>(next_weak);
203+ }
204+ VisitingOldObject (NULL );
205+ return marked;
206+ }
207+
208+ void DrainMarkingStack () {
182209 RawObject* raw_obj = work_list_.Pop ();
210+ if ((raw_obj == NULL ) && ProcessPendingWeakProperties ()) {
211+ raw_obj = work_list_.Pop ();
212+ }
213+
183214 if (raw_obj == NULL ) {
184215 ASSERT (visiting_old_object_ == NULL );
185- return false ;
216+ return ;
186217 }
187218 do {
188219 do {
@@ -200,33 +231,13 @@ class MarkingVisitorBase : public ObjectPointerVisitor {
200231 } while (raw_obj != NULL );
201232
202233 // Marking stack is empty.
203- // Process all the pending weak properties in this visitor.
204- RawWeakProperty* cur_weak = delayed_weak_properties_;
205- delayed_weak_properties_ = NULL ;
206- while (cur_weak != NULL ) {
207- uword next_weak = cur_weak->ptr ()->next_ ;
208- RawObject* raw_key = cur_weak->ptr ()->key_ ;
209- // Reset the next pointer in the weak property.
210- cur_weak->ptr ()->next_ = 0 ;
211- if (raw_key->IsMarked ()) {
212- // The key is marked so we make sure to properly visit all pointers
213- // originating from this weak property.
214- VisitingOldObject (cur_weak);
215- cur_weak->VisitPointers (this );
216- } else {
217- // Requeue this weak property to be handled later.
218- EnqueueWeakProperty (cur_weak);
219- }
220- // Advance to next weak property in the queue.
221- cur_weak = reinterpret_cast <RawWeakProperty*>(next_weak);
222- }
234+ ProcessPendingWeakProperties ();
223235
224236 // Check whether any further work was pushed either by other markers or
225237 // by the handling of weak properties.
226238 raw_obj = work_list_.Pop ();
227239 } while (raw_obj != NULL );
228240 VisitingOldObject (NULL );
229- return true ;
230241 }
231242
232243 void VisitPointers (RawObject** first, RawObject** last) {
@@ -282,6 +293,7 @@ class MarkingVisitorBase : public ObjectPointerVisitor {
282293 while (cur_weak != NULL ) {
283294 uword next_weak = cur_weak->ptr ()->next_ ;
284295 cur_weak->ptr ()->next_ = 0 ;
296+ RELEASE_ASSERT (!cur_weak->ptr ()->key_ ->IsMarked ());
285297 WeakProperty::Clear (cur_weak);
286298 weak_properties_cleared++;
287299 // Advance to next weak property in the queue.
@@ -569,28 +581,54 @@ class MarkTask : public ThreadPool::Task {
569581 skipped_code_functions);
570582 // Phase 1: Iterate over roots and drain marking stack in tasks.
571583 marker_->IterateRoots (isolate_, &visitor, task_index_, num_tasks_);
572- do {
573- visitor.DrainMarkingStack ();
574584
575- // I can't find more work right now. If no other task is busy,
576- // then there will never be more work (NB: 1 is *before* decrement).
577- if (AtomicOperations::FetchAndDecrement (num_busy_) == 1 ) break ;
578-
579- // Wait for some work to appear.
580- // TODO(iposva): Replace busy-waiting with a solution using Monitor,
581- // and redraw the boundaries between stack/visitor/task as needed.
582- while (marking_stack_->IsEmpty () &&
583- AtomicOperations::LoadRelaxed (num_busy_) > 0 ) {
585+ bool more_to_mark = false ;
586+ do {
587+ do {
588+ visitor.DrainMarkingStack ();
589+
590+ // I can't find more work right now. If no other task is busy,
591+ // then there will never be more work (NB: 1 is *before* decrement).
592+ if (AtomicOperations::FetchAndDecrement (num_busy_) == 1 ) break ;
593+
594+ // Wait for some work to appear.
595+ // TODO(iposva): Replace busy-waiting with a solution using Monitor,
596+ // and redraw the boundaries between stack/visitor/task as needed.
597+ while (marking_stack_->IsEmpty () &&
598+ AtomicOperations::LoadRelaxed (num_busy_) > 0 ) {
599+ }
600+
601+ // If no tasks are busy, there will never be more work.
602+ if (AtomicOperations::LoadRelaxed (num_busy_) == 0 ) break ;
603+
604+ // I saw some work; get busy and compete for it.
605+ AtomicOperations::FetchAndIncrement (num_busy_);
606+ } while (true );
607+ // Wait for all markers to stop.
608+ barrier_->Sync ();
609+ ASSERT (AtomicOperations::LoadRelaxed (num_busy_) == 0 );
610+
611+ // Check if we have any pending properties with marked keys.
612+ // Those might have been marked by another marker.
613+ more_to_mark = visitor.ProcessPendingWeakProperties ();
614+ if (more_to_mark) {
615+ // We have more work to do. Notify others.
616+ AtomicOperations::FetchAndIncrement (num_busy_);
584617 }
585618
586- // If no tasks are busy, there will never be more work.
587- if (AtomicOperations::LoadRelaxed (num_busy_) == 0 ) break ;
588-
589- // I saw some work; get busy and compete for it.
590- AtomicOperations::FetchAndIncrement (num_busy_);
591- } while (true );
592- ASSERT (AtomicOperations::LoadRelaxed (num_busy_) == 0 );
593- barrier_->Sync ();
619+ // Wait for all other markers to finish processing their pending
620+ // weak properties and decide if they need to continue marking.
621+ // Caveat: we need two barriers here to make this decision in lock step
622+ // between all markers and the main thread.
623+ barrier_->Sync ();
624+ if (!more_to_mark && (AtomicOperations::LoadRelaxed (num_busy_) > 0 )) {
625+ // All markers continue to marker as long as any single marker has
626+ // some work to do.
627+ AtomicOperations::FetchAndIncrement (num_busy_);
628+ more_to_mark = true ;
629+ }
630+ barrier_->Sync ();
631+ } while (more_to_mark);
594632
595633 // Phase 2: Weak processing and follow-up marking on main thread.
596634 barrier_->Sync ();
@@ -688,7 +726,19 @@ void GCMarker::MarkObjects(Isolate* isolate,
688726 ThreadPool* pool = Dart::thread_pool ();
689727 pool->Run (mark_task);
690728 }
691- barrier.Sync ();
729+ bool more_to_mark = false ;
730+ do {
731+ // Wait for all markers to stop.
732+ barrier.Sync ();
733+
734+ // Wait for all markers to go through weak properties and verify
735+ // that there are no more objects to mark.
736+ // Note: we need to have two barriers here because we want all markers
737+ // and main thread to make decisions in lock step.
738+ barrier.Sync ();
739+ more_to_mark = AtomicOperations::LoadRelaxed (&num_busy) > 0 ;
740+ barrier.Sync ();
741+ } while (more_to_mark);
692742
693743 // Phase 2: Weak processing on main thread.
694744 {
0 commit comments