Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: runtime/vm/gc_marker.cc

Issue 2041413005: VM: Fix WeakProperty processing during parallel marking. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: restore assertion in the right place Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/platform/assert.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "vm/allocation.h" 7 #include "vm/allocation.h"
8 #include "vm/dart_api_state.h" 8 #include "vm/dart_api_state.h"
9 #include "vm/isolate.h" 9 #include "vm/isolate.h"
10 #include "vm/log.h" 10 #include "vm/log.h"
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 uintptr_t marked_bytes() const { return marked_bytes_; } 170 uintptr_t marked_bytes() const { return marked_bytes_; }
171 171
172 intptr_t live_count(intptr_t class_id) { 172 intptr_t live_count(intptr_t class_id) {
173 return class_stats_count_[class_id]; 173 return class_stats_count_[class_id];
174 } 174 }
175 175
176 intptr_t live_size(intptr_t class_id) { 176 intptr_t live_size(intptr_t class_id) {
177 return class_stats_size_[class_id]; 177 return class_stats_size_[class_id];
178 } 178 }
179 179
180 // Returns true if some non-zero amount of work was performed. 180 bool ProcessPendingWeakProperties() {
181 bool DrainMarkingStack() { 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
205 return marked;
206 }
207
208 void DrainMarkingStack() {
182 RawObject* raw_obj = work_list_.Pop(); 209 RawObject* raw_obj = work_list_.Pop();
210 if ((raw_obj == NULL) && ProcessPendingWeakProperties()) {
211 raw_obj = work_list_.Pop();
212 }
213
183 if (raw_obj == NULL) { 214 if (raw_obj == NULL) {
184 ASSERT(visiting_old_object_ == NULL); 215 ASSERT(visiting_old_object_ == NULL);
185 return false; 216 return;
186 } 217 }
187 do { 218 do {
188 do { 219 do {
189 // First drain the marking stacks. 220 // First drain the marking stacks.
190 VisitingOldObject(raw_obj); 221 VisitingOldObject(raw_obj);
191 const intptr_t class_id = raw_obj->GetClassId(); 222 const intptr_t class_id = raw_obj->GetClassId();
192 if (class_id != kWeakPropertyCid) { 223 if (class_id != kWeakPropertyCid) {
193 marked_bytes_ += raw_obj->VisitPointers(this); 224 marked_bytes_ += raw_obj->VisitPointers(this);
194 } else { 225 } else {
195 RawWeakProperty* raw_weak = 226 RawWeakProperty* raw_weak =
196 reinterpret_cast<RawWeakProperty*>(raw_obj); 227 reinterpret_cast<RawWeakProperty*>(raw_obj);
197 marked_bytes_ += ProcessWeakProperty(raw_weak); 228 marked_bytes_ += ProcessWeakProperty(raw_weak);
198 } 229 }
199 raw_obj = work_list_.Pop(); 230 raw_obj = work_list_.Pop();
200 } while (raw_obj != NULL); 231 } while (raw_obj != NULL);
201 232
202 // Marking stack is empty. 233 // Marking stack is empty.
203 // Process all the pending weak properties in this visitor. 234 ProcessPendingWeakProperties();
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 }
223 235
224 // Check whether any further work was pushed either by other markers or 236 // Check whether any further work was pushed either by other markers or
225 // by the handling of weak properties. 237 // by the handling of weak properties.
226 raw_obj = work_list_.Pop(); 238 raw_obj = work_list_.Pop();
227 } while (raw_obj != NULL); 239 } while (raw_obj != NULL);
228 VisitingOldObject(NULL); 240 VisitingOldObject(NULL);
229 return true;
230 } 241 }
231 242
232 void VisitPointers(RawObject** first, RawObject** last) { 243 void VisitPointers(RawObject** first, RawObject** last) {
233 for (RawObject** current = first; current <= last; current++) { 244 for (RawObject** current = first; current <= last; current++) {
234 MarkObject(*current, current); 245 MarkObject(*current, current);
235 } 246 }
236 } 247 }
237 248
238 bool visit_function_code() const { 249 bool visit_function_code() const {
239 return skipped_code_functions_ == NULL; 250 return skipped_code_functions_ == NULL;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 if (skipped_code_functions_ != NULL) { 286 if (skipped_code_functions_ != NULL) {
276 skipped_code_functions_->DetachCode(); 287 skipped_code_functions_->DetachCode();
277 } 288 }
278 // Clear pending weak properties. 289 // Clear pending weak properties.
279 RawWeakProperty* cur_weak = delayed_weak_properties_; 290 RawWeakProperty* cur_weak = delayed_weak_properties_;
280 delayed_weak_properties_ = NULL; 291 delayed_weak_properties_ = NULL;
281 intptr_t weak_properties_cleared = 0; 292 intptr_t weak_properties_cleared = 0;
282 while (cur_weak != NULL) { 293 while (cur_weak != NULL) {
283 uword next_weak = cur_weak->ptr()->next_; 294 uword next_weak = cur_weak->ptr()->next_;
284 cur_weak->ptr()->next_ = 0; 295 cur_weak->ptr()->next_ = 0;
296 RELEASE_ASSERT(!cur_weak->ptr()->key_->IsMarked());
285 WeakProperty::Clear(cur_weak); 297 WeakProperty::Clear(cur_weak);
286 weak_properties_cleared++; 298 weak_properties_cleared++;
287 // Advance to next weak property in the queue. 299 // Advance to next weak property in the queue.
288 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); 300 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak);
289 } 301 }
290 } 302 }
291 303
292 void VisitingOldObject(RawObject* obj) { 304 void VisitingOldObject(RawObject* obj) {
293 ASSERT((obj == NULL) || obj->IsOldObject()); 305 ASSERT((obj == NULL) || obj->IsOldObject());
294 visiting_old_object_ = obj; 306 visiting_old_object_ = obj;
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
562 Thread* thread = Thread::Current(); 574 Thread* thread = Thread::Current();
563 TIMELINE_FUNCTION_GC_DURATION(thread, "MarkTask"); 575 TIMELINE_FUNCTION_GC_DURATION(thread, "MarkTask");
564 StackZone stack_zone(thread); 576 StackZone stack_zone(thread);
565 Zone* zone = stack_zone.GetZone(); 577 Zone* zone = stack_zone.GetZone();
566 SkippedCodeFunctions* skipped_code_functions = 578 SkippedCodeFunctions* skipped_code_functions =
567 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL; 579 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL;
568 SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_, 580 SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_,
569 skipped_code_functions); 581 skipped_code_functions);
570 // Phase 1: Iterate over roots and drain marking stack in tasks. 582 // Phase 1: Iterate over roots and drain marking stack in tasks.
571 marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_); 583 marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_);
584
585 bool more_to_mark = false;
572 do { 586 do {
573 visitor.DrainMarkingStack(); 587 do {
588 visitor.DrainMarkingStack();
574 589
575 // I can't find more work right now. If no other task is busy, 590 // 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). 591 // then there will never be more work (NB: 1 is *before* decrement).
577 if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break; 592 if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break;
578 593
579 // Wait for some work to appear. 594 // Wait for some work to appear.
580 // TODO(iposva): Replace busy-waiting with a solution using Monitor, 595 // TODO(iposva): Replace busy-waiting with a solution using Monitor,
581 // and redraw the boundaries between stack/visitor/task as needed. 596 // and redraw the boundaries between stack/visitor/task as needed.
582 while (marking_stack_->IsEmpty() && 597 while (marking_stack_->IsEmpty() &&
583 AtomicOperations::LoadRelaxed(num_busy_) > 0) { 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_);
584 } 617 }
585 618
586 // If no tasks are busy, there will never be more work. 619 // Wait for all other markers to finish processing their pending
587 if (AtomicOperations::LoadRelaxed(num_busy_) == 0) break; 620 // weak properties and decide if they need to continue marking.
588 621 // Caveat: we need two barriers here to make this decision in lock step
589 // I saw some work; get busy and compete for it. 622 // between all markers and the main thread.
590 AtomicOperations::FetchAndIncrement(num_busy_); 623 barrier_->Sync();
591 } while (true); 624 if (!more_to_mark && (AtomicOperations::LoadRelaxed(num_busy_) > 0)) {
592 ASSERT(AtomicOperations::LoadRelaxed(num_busy_) == 0); 625 // All markers continue to marker as long as any single marker has
593 barrier_->Sync(); 626 // some work to do.
627 AtomicOperations::FetchAndIncrement(num_busy_);
628 more_to_mark = true;
629 }
630 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
631 } while (more_to_mark);
594 632
595 // Phase 2: Weak processing and follow-up marking on main thread. 633 // Phase 2: Weak processing and follow-up marking on main thread.
596 barrier_->Sync(); 634 barrier_->Sync();
597 635
598 // Phase 3: Finalize results from all markers (detach code, etc.). 636 // Phase 3: Finalize results from all markers (detach code, etc.).
599 if (FLAG_log_marker_tasks) { 637 if (FLAG_log_marker_tasks) {
600 THR_Print("Task %" Pd " marked %" Pd " bytes.\n", 638 THR_Print("Task %" Pd " marked %" Pd " bytes.\n",
601 task_index_, visitor.marked_bytes()); 639 task_index_, visitor.marked_bytes());
602 } 640 }
603 marker_->FinalizeResultsFrom(&visitor); 641 marker_->FinalizeResultsFrom(&visitor);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
681 uintptr_t num_busy = num_tasks; 719 uintptr_t num_busy = num_tasks;
682 // Phase 1: Iterate over roots and drain marking stack in tasks. 720 // Phase 1: Iterate over roots and drain marking stack in tasks.
683 for (intptr_t i = 0; i < num_tasks; ++i) { 721 for (intptr_t i = 0; i < num_tasks; ++i) {
684 MarkTask* mark_task = 722 MarkTask* mark_task =
685 new MarkTask(this, isolate, heap_, page_space, &marking_stack, 723 new MarkTask(this, isolate, heap_, page_space, &marking_stack,
686 &barrier, collect_code, 724 &barrier, collect_code,
687 i, num_tasks, &num_busy); 725 i, num_tasks, &num_busy);
688 ThreadPool* pool = Dart::thread_pool(); 726 ThreadPool* pool = Dart::thread_pool();
689 pool->Run(mark_task); 727 pool->Run(mark_task);
690 } 728 }
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();
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.
739 more_to_mark = AtomicOperations::LoadRelaxed(&num_busy) > 0;
740 barrier.Sync();
741 } 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.
692 742
693 // Phase 2: Weak processing on main thread. 743 // Phase 2: Weak processing on main thread.
694 { 744 {
695 TIMELINE_FUNCTION_GC_DURATION(thread, "WeakHandleProcessing"); 745 TIMELINE_FUNCTION_GC_DURATION(thread, "WeakHandleProcessing");
696 MarkingWeakVisitor mark_weak; 746 MarkingWeakVisitor mark_weak;
697 IterateWeakRoots(isolate, &mark_weak); 747 IterateWeakRoots(isolate, &mark_weak);
698 } 748 }
699 barrier.Sync(); 749 barrier.Sync();
700 750
701 // Phase 3: Finalize results from all markers (detach code, etc.). 751 // Phase 3: Finalize results from all markers (detach code, etc.).
702 barrier.Exit(); 752 barrier.Exit();
703 } 753 }
704 ProcessWeakTables(page_space); 754 ProcessWeakTables(page_space);
705 ProcessObjectIdTable(isolate); 755 ProcessObjectIdTable(isolate);
706 } 756 }
707 Epilogue(isolate, invoke_api_callbacks); 757 Epilogue(isolate, invoke_api_callbacks);
708 } 758 }
709 759
710 } // namespace dart 760 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/platform/assert.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698