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

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

Issue 1351453008: Parallel marking. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Add TODO about smi/new check. Created 5 years, 3 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/vm/gc_marker.h ('k') | runtime/vm/heap_test.cc » ('j') | 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 <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_barrier.h" 19 #include "vm/thread_barrier.h"
20 #include "vm/thread_pool.h" 20 #include "vm/thread_pool.h"
21 #include "vm/visitor.h" 21 #include "vm/visitor.h"
22 #include "vm/object_id_ring.h" 22 #include "vm/object_id_ring.h"
23 23
24 namespace dart { 24 namespace dart {
25 25
26 DEFINE_FLAG(int, marker_tasks, 1, 26 DEFINE_FLAG(int, marker_tasks, 4,
27 "The number of tasks to spawn during old gen GC marking (0 means " 27 "The number of tasks to spawn during old gen GC marking (0 means "
28 "perform all marking on main thread)."); 28 "perform all marking on main thread).");
29 DEFINE_FLAG(bool, log_marker_tasks, false,
30 "Log debugging information for old gen GC marking tasks.");
29 31
30 class DelaySet { 32 class DelaySet {
31 private: 33 private:
32 typedef std::multimap<RawObject*, RawWeakProperty*> Map; 34 typedef std::multimap<RawObject*, RawWeakProperty*> Map;
33 typedef std::pair<RawObject*, RawWeakProperty*> MapEntry; 35 typedef std::pair<RawObject*, RawWeakProperty*> MapEntry;
34 36
35 public: 37 public:
36 DelaySet() : mutex_(new Mutex()) {} 38 DelaySet() : mutex_(new Mutex()) {}
37 ~DelaySet() { delete mutex_; } 39 ~DelaySet() { delete mutex_; }
38 40
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 skipped_code_functions_.Clear(); 135 skipped_code_functions_.Clear();
134 } 136 }
135 137
136 private: 138 private:
137 GrowableArray<RawFunction*> skipped_code_functions_; 139 GrowableArray<RawFunction*> skipped_code_functions_;
138 140
139 DISALLOW_COPY_AND_ASSIGN(SkippedCodeFunctions); 141 DISALLOW_COPY_AND_ASSIGN(SkippedCodeFunctions);
140 }; 142 };
141 143
142 144
143 class MarkingVisitor : public ObjectPointerVisitor { 145 template<bool sync>
146 class MarkingVisitorBase : public ObjectPointerVisitor {
144 public: 147 public:
145 MarkingVisitor(Isolate* isolate, 148 MarkingVisitorBase(Isolate* isolate,
146 Heap* heap, 149 Heap* heap,
147 PageSpace* page_space, 150 PageSpace* page_space,
148 MarkingStack* marking_stack, 151 MarkingStack* marking_stack,
149 DelaySet* delay_set, 152 DelaySet* delay_set,
150 SkippedCodeFunctions* skipped_code_functions) 153 SkippedCodeFunctions* skipped_code_functions)
151 : ObjectPointerVisitor(isolate), 154 : ObjectPointerVisitor(isolate),
152 thread_(Thread::Current()), 155 thread_(Thread::Current()),
153 heap_(heap), 156 heap_(heap),
154 vm_heap_(Dart::vm_isolate()->heap()), 157 vm_heap_(Dart::vm_isolate()->heap()),
155 class_stats_count_(isolate->class_table()->NumCids()), 158 class_stats_count_(isolate->class_table()->NumCids()),
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 217
215 bool visit_function_code() const { 218 bool visit_function_code() const {
216 return skipped_code_functions_ == NULL; 219 return skipped_code_functions_ == NULL;
217 } 220 }
218 221
219 virtual void add_skipped_code_function(RawFunction* func) { 222 virtual void add_skipped_code_function(RawFunction* func) {
220 ASSERT(!visit_function_code()); 223 ASSERT(!visit_function_code());
221 skipped_code_functions_->Add(func); 224 skipped_code_functions_->Add(func);
222 } 225 }
223 226
224 // Returns the mark bit. Sets the watch bit if unmarked. (The prior value of 227 // If unmarked, sets the watch bit and returns true.
225 // the watched bit is returned in 'watched_before' for validation purposes.) 228 // If marked, does nothing and returns false.
226 // TODO(koda): When synchronizing header bits, this goes in a single CAS loop. 229 static bool EnsureWatchedIfWhite(RawObject* obj) {
227 static bool EnsureWatchedIfWhite(RawObject* obj, bool* watched_before) { 230 if (!sync) {
228 if (obj->IsMarked()) { 231 if (obj->IsMarked()) return false;
229 return false; 232 if (!obj->IsWatched()) obj->SetWatchedBitUnsynchronized();
233 return true;
230 } 234 }
231 if (!obj->IsWatched()) { 235 uword tags = obj->ptr()->tags_;
232 *watched_before = false; 236 uword old_tags;
233 obj->SetWatchedBitUnsynchronized(); 237 do {
234 } else { 238 old_tags = tags;
235 *watched_before = true; 239 if (RawObject::MarkBit::decode(tags)) return false;
236 } 240 if (RawObject::WatchedBit::decode(tags)) return true;
241 uword new_tags = RawObject::WatchedBit::update(true, old_tags);
242 tags = AtomicOperations::CompareAndSwapWord(
243 &obj->ptr()->tags_, old_tags, new_tags);
244 } while (tags != old_tags);
237 return true; 245 return true;
238 } 246 }
239 247
240 void ProcessWeakProperty(RawWeakProperty* raw_weak) { 248 void ProcessWeakProperty(RawWeakProperty* raw_weak) {
241 // The fate of the weak property is determined by its key. 249 // The fate of the weak property is determined by its key.
242 RawObject* raw_key = raw_weak->ptr()->key_; 250 RawObject* raw_key = raw_weak->ptr()->key_;
243 bool watched_before = false;
244 if (raw_key->IsHeapObject() && 251 if (raw_key->IsHeapObject() &&
245 raw_key->IsOldObject() && 252 raw_key->IsOldObject() &&
246 EnsureWatchedIfWhite(raw_key, &watched_before)) { 253 EnsureWatchedIfWhite(raw_key)) {
247 // Key is white. Delay the weak property. 254 // Key is white. Delay the weak property.
248 bool new_key = delay_set_->Insert(raw_weak); 255 delay_set_->Insert(raw_weak);
Ivan Posva 2015/10/01 11:22:44 There is a race here: - This thread (A) observes t
koda 2015/10/01 20:30:11 Good catch; fixed by re-checking mark bit after ac
249 ASSERT(new_key == !watched_before);
250 } else { 256 } else {
251 // Key is gray or black. Make the weak property black. 257 // Key is gray or black. Make the weak property black.
252 raw_weak->VisitPointers(this); 258 raw_weak->VisitPointers(this);
253 } 259 }
254 } 260 }
255 261
256 // Called when all marking is complete. 262 // Called when all marking is complete.
257 void Finalize() { 263 void Finalize() {
258 work_list_.Finalize(); 264 work_list_.Finalize();
259 if (skipped_code_functions_ != NULL) { 265 if (skipped_code_functions_ != NULL) {
260 skipped_code_functions_->DetachCode(); 266 skipped_code_functions_->DetachCode();
261 } 267 }
262 } 268 }
263 269
264 void VisitingOldObject(RawObject* obj) { 270 void VisitingOldObject(RawObject* obj) {
265 ASSERT((obj == NULL) || obj->IsOldObject()); 271 ASSERT((obj == NULL) || obj->IsOldObject());
266 visiting_old_object_ = obj; 272 visiting_old_object_ = obj;
267 } 273 }
268 274
269 private: 275 private:
276 // TODO(koda): Independent of sync; move out.
Ivan Posva 2015/10/01 11:22:44 Please do this in this CL. The class can be local
koda 2015/10/01 20:30:11 Done.
270 class WorkList : public ValueObject { 277 class WorkList : public ValueObject {
271 public: 278 public:
272 explicit WorkList(MarkingStack* marking_stack) 279 explicit WorkList(MarkingStack* marking_stack)
273 : marking_stack_(marking_stack) { 280 : marking_stack_(marking_stack) {
274 work_ = marking_stack_->PopEmptyBlock(); 281 work_ = marking_stack_->PopEmptyBlock();
275 } 282 }
276 283
277 ~WorkList() { 284 ~WorkList() {
278 ASSERT(work_ == NULL); 285 ASSERT(work_ == NULL);
279 ASSERT(marking_stack_ == NULL); 286 ASSERT(marking_stack_ == NULL);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 work_ = NULL; 318 work_ = NULL;
312 // Fail fast on attempts to mark after finalizing. 319 // Fail fast on attempts to mark after finalizing.
313 marking_stack_ = NULL; 320 marking_stack_ = NULL;
314 } 321 }
315 322
316 private: 323 private:
317 MarkingStack::Block* work_; 324 MarkingStack::Block* work_;
318 MarkingStack* marking_stack_; 325 MarkingStack* marking_stack_;
319 }; 326 };
320 327
321 void MarkAndPush(RawObject* raw_obj) { 328 void PushMarked(RawObject* raw_obj) {
322 ASSERT(raw_obj->IsHeapObject()); 329 ASSERT(raw_obj->IsHeapObject());
323 ASSERT((FLAG_verify_before_gc || FLAG_verify_before_gc) ? 330 ASSERT((FLAG_verify_before_gc || FLAG_verify_before_gc) ?
324 page_space_->Contains(RawObject::ToAddr(raw_obj)) : 331 page_space_->Contains(RawObject::ToAddr(raw_obj)) :
325 true); 332 true);
326 333
327 // Mark the object and push it on the marking stack. 334 // Push the marked object on the marking stack.
328 ASSERT(!raw_obj->IsMarked()); 335 ASSERT(raw_obj->IsMarked());
329 const bool is_watched = raw_obj->IsWatched(); 336 const bool is_watched = raw_obj->IsWatched();
330 raw_obj->SetMarkBitUnsynchronized(); 337 // We acquired the mark bit => no other task is modifying the header.
338 // TODO(koda): For concurrent mutator, this needs synchronization. Consider
339 // clearing these bits already in the CAS for the mark bit.
331 raw_obj->ClearRememberedBitUnsynchronized(); 340 raw_obj->ClearRememberedBitUnsynchronized();
332 raw_obj->ClearWatchedBitUnsynchronized(); 341 raw_obj->ClearWatchedBitUnsynchronized();
333 if (is_watched) { 342 if (is_watched) {
334 delay_set_->VisitValuesForKey(raw_obj, this); 343 delay_set_->VisitValuesForKey(raw_obj, this);
335 } 344 }
336 work_list_.Push(raw_obj); 345 work_list_.Push(raw_obj);
337 } 346 }
338 347
348 static bool TryAcquireMarkBit(RawObject* raw_obj) {
349 if (!sync) {
350 if (raw_obj->IsMarked()) return false;
351 raw_obj->SetMarkBitUnsynchronized();
352 return true;
353 }
354 return raw_obj->TryAcquireMarkBit();
355 }
356
339 void MarkObject(RawObject* raw_obj, RawObject** p) { 357 void MarkObject(RawObject* raw_obj, RawObject** p) {
340 // Fast exit if the raw object is a Smi. 358 // Fast exit if the raw object is a Smi.
341 if (!raw_obj->IsHeapObject()) { 359 if (!raw_obj->IsHeapObject()) {
342 return; 360 return;
343 } 361 }
344 362
345 // Fast exit if the raw object is marked. 363 // Fast exit if the raw object is marked.
364 // TODO(koda): Reduce number of branches in generated code by combining
365 // new/smi check.
Ivan Posva 2015/10/01 11:22:44 Comment on wrong line. This is the IsMarked check.
koda 2015/10/01 20:30:10 Moved and expanded comment to clarify: The total n
346 if (raw_obj->IsMarked()) { 366 if (raw_obj->IsMarked()) {
347 return; 367 return;
348 } 368 }
349 369
350 // Skip over new objects, but verify consistency of heap while at it.
351 if (raw_obj->IsNewObject()) { 370 if (raw_obj->IsNewObject()) {
352 // TODO(iposva): Add consistency check. 371 ProcessNewSpaceObject(raw_obj, p);
353 if ((visiting_old_object_ != NULL) && 372 return;
354 !visiting_old_object_->IsRemembered()) { 373 }
355 ASSERT(p != NULL); 374
356 visiting_old_object_->SetRememberedBitUnsynchronized(); 375 if (!TryAcquireMarkBit(raw_obj)) {
357 thread_->StoreBufferAddObjectGC(visiting_old_object_); 376 // Already marked.
358 }
359 return; 377 return;
360 } 378 }
361 if (RawObject::IsVariableSizeClassId(raw_obj->GetClassId())) { 379 if (RawObject::IsVariableSizeClassId(raw_obj->GetClassId())) {
362 UpdateLiveOld(raw_obj->GetClassId(), raw_obj->Size()); 380 UpdateLiveOld(raw_obj->GetClassId(), raw_obj->Size());
363 } else { 381 } else {
364 UpdateLiveOld(raw_obj->GetClassId(), 0); 382 UpdateLiveOld(raw_obj->GetClassId(), 0);
365 } 383 }
366 384
367 MarkAndPush(raw_obj); 385 PushMarked(raw_obj);
386 }
387
388 static bool TryAcquireRememberedBit(RawObject* raw_obj) {
389 if (!sync) {
390 if (raw_obj->IsRemembered()) return false;
391 raw_obj->SetRememberedBitUnsynchronized();
392 return true;
393 }
394 return raw_obj->TryAcquireRememberedBit();
395 }
396
397 void ProcessNewSpaceObject(RawObject* raw_obj, RawObject** p) {
398 // TODO(iposva): Add consistency check.
399 if ((visiting_old_object_ != NULL) &&
400 TryAcquireRememberedBit(visiting_old_object_)) {
401 ASSERT(p != NULL); // TODO(koda): Why?
Ivan Posva 2015/10/01 17:02:54 Because the pointer to the address we are visiting
koda 2015/10/01 20:30:11 Thanks for clarifying; added comment.
402 thread_->StoreBufferAddObjectGC(visiting_old_object_);
403 }
368 } 404 }
369 405
370 void UpdateLiveOld(intptr_t class_id, intptr_t size) { 406 void UpdateLiveOld(intptr_t class_id, intptr_t size) {
371 // TODO(koda): Support growing the array once mutator runs concurrently. 407 // TODO(koda): Support growing the array once mutator runs concurrently.
372 ASSERT(class_id < class_stats_count_.length()); 408 ASSERT(class_id < class_stats_count_.length());
373 class_stats_count_[class_id] += 1; 409 class_stats_count_[class_id] += 1;
374 class_stats_size_[class_id] += size; 410 class_stats_size_[class_id] += size;
375 } 411 }
376 412
377 Thread* thread_; 413 Thread* thread_;
378 Heap* heap_; 414 Heap* heap_;
379 Heap* vm_heap_; 415 Heap* vm_heap_;
380 GrowableArray<intptr_t> class_stats_count_; 416 GrowableArray<intptr_t> class_stats_count_;
381 GrowableArray<intptr_t> class_stats_size_; 417 GrowableArray<intptr_t> class_stats_size_;
382 PageSpace* page_space_; 418 PageSpace* page_space_;
383 WorkList work_list_; 419 WorkList work_list_;
384 DelaySet* delay_set_; 420 DelaySet* delay_set_;
385 RawObject* visiting_old_object_; 421 RawObject* visiting_old_object_;
386 SkippedCodeFunctions* skipped_code_functions_; 422 SkippedCodeFunctions* skipped_code_functions_;
387 uintptr_t marked_bytes_; 423 uintptr_t marked_bytes_;
388 424
389 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitor); 425 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitorBase);
390 }; 426 };
391 427
392 428
429 typedef MarkingVisitorBase<false> UnsyncMarkingVisitor;
Ivan Posva 2015/10/01 11:22:44 What is the performance impact of making the sync
koda 2015/10/01 20:30:11 I will investigate and update this thread.
430 typedef MarkingVisitorBase<true> SyncMarkingVisitor;
431
432
393 static bool IsUnreachable(const RawObject* raw_obj) { 433 static bool IsUnreachable(const RawObject* raw_obj) {
394 if (!raw_obj->IsHeapObject()) { 434 if (!raw_obj->IsHeapObject()) {
395 return false; 435 return false;
396 } 436 }
397 if (raw_obj == Object::null()) { 437 if (raw_obj == Object::null()) {
398 return true; 438 return true;
399 } 439 }
400 if (!raw_obj->IsOldObject()) { 440 if (!raw_obj->IsOldObject()) {
401 return false; 441 return false;
402 } 442 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 475
436 void GCMarker::Epilogue(Isolate* isolate, bool invoke_api_callbacks) { 476 void GCMarker::Epilogue(Isolate* isolate, bool invoke_api_callbacks) {
437 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { 477 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) {
438 (isolate->gc_epilogue_callback())(); 478 (isolate->gc_epilogue_callback())();
439 } 479 }
440 } 480 }
441 481
442 482
443 void GCMarker::IterateRoots(Isolate* isolate, 483 void GCMarker::IterateRoots(Isolate* isolate,
444 ObjectPointerVisitor* visitor, 484 ObjectPointerVisitor* visitor,
445 bool visit_prologue_weak_persistent_handles) { 485 bool visit_prologue_weak_persistent_handles,
446 isolate->VisitObjectPointers(visitor, 486 intptr_t slice_index, intptr_t num_slices) {
447 visit_prologue_weak_persistent_handles, 487 ASSERT(0 <= slice_index && slice_index < num_slices);
448 StackFrameIterator::kDontValidateFrames); 488 if (slice_index == 0 || num_slices <= 1) {
449 heap_->new_space()->VisitObjectPointers(visitor); 489 isolate->VisitObjectPointers(visitor,
490 visit_prologue_weak_persistent_handles,
491 StackFrameIterator::kDontValidateFrames);
492 }
493 if (slice_index == 1 || num_slices <= 1) {
494 heap_->new_space()->VisitObjectPointers(visitor);
495 }
496 // For now, we just distinguish two parts of the root set, so any remaining
497 // slices are empty.
450 } 498 }
451 499
452 500
453 void GCMarker::IterateWeakRoots(Isolate* isolate, 501 void GCMarker::IterateWeakRoots(Isolate* isolate,
454 HandleVisitor* visitor, 502 HandleVisitor* visitor,
455 bool visit_prologue_weak_persistent_handles) { 503 bool visit_prologue_weak_persistent_handles) {
456 ApiState* state = isolate->api_state(); 504 ApiState* state = isolate->api_state();
457 ASSERT(state != NULL); 505 ASSERT(state != NULL);
458 isolate->VisitWeakPersistentHandles(visitor, 506 isolate->VisitWeakPersistentHandles(visitor,
459 visit_prologue_weak_persistent_handles); 507 visit_prologue_weak_persistent_handles);
460 } 508 }
461 509
462 510
511 template<class MarkingVisitorType>
463 void GCMarker::IterateWeakReferences(Isolate* isolate, 512 void GCMarker::IterateWeakReferences(Isolate* isolate,
464 MarkingVisitor* visitor) { 513 MarkingVisitorType* visitor) {
465 ApiState* state = isolate->api_state(); 514 ApiState* state = isolate->api_state();
466 ASSERT(state != NULL); 515 ASSERT(state != NULL);
467 while (true) { 516 while (true) {
468 WeakReferenceSet* queue = state->delayed_weak_reference_sets(); 517 WeakReferenceSet* queue = state->delayed_weak_reference_sets();
469 if (queue == NULL) { 518 if (queue == NULL) {
470 // The delay queue is empty therefore no clean-up is required. 519 // The delay queue is empty therefore no clean-up is required.
471 return; 520 return;
472 } 521 }
473 state->set_delayed_weak_reference_sets(NULL); 522 state->set_delayed_weak_reference_sets(NULL);
474 while (queue != NULL) { 523 while (queue != NULL) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 class MarkTask : public ThreadPool::Task { 618 class MarkTask : public ThreadPool::Task {
570 public: 619 public:
571 MarkTask(GCMarker* marker, 620 MarkTask(GCMarker* marker,
572 Isolate* isolate, 621 Isolate* isolate,
573 Heap* heap, 622 Heap* heap,
574 PageSpace* page_space, 623 PageSpace* page_space,
575 MarkingStack* marking_stack, 624 MarkingStack* marking_stack,
576 DelaySet* delay_set, 625 DelaySet* delay_set,
577 ThreadBarrier* barrier, 626 ThreadBarrier* barrier,
578 bool collect_code, 627 bool collect_code,
579 bool visit_prologue_weak_persistent_handles) 628 bool visit_prologue_weak_persistent_handles,
629 intptr_t task_index,
630 intptr_t num_tasks,
631 uintptr_t* num_busy)
580 : marker_(marker), 632 : marker_(marker),
581 isolate_(isolate), 633 isolate_(isolate),
582 heap_(heap), 634 heap_(heap),
583 page_space_(page_space), 635 page_space_(page_space),
584 marking_stack_(marking_stack), 636 marking_stack_(marking_stack),
585 delay_set_(delay_set), 637 delay_set_(delay_set),
586 barrier_(barrier), 638 barrier_(barrier),
587 collect_code_(collect_code), 639 collect_code_(collect_code),
588 visit_prologue_weak_persistent_handles_( 640 visit_prologue_weak_persistent_handles_(
589 visit_prologue_weak_persistent_handles) { 641 visit_prologue_weak_persistent_handles),
642 task_index_(task_index),
643 num_tasks_(num_tasks),
644 num_busy_(num_busy) {
590 } 645 }
591 646
592 virtual void Run() { 647 virtual void Run() {
593 Thread::EnterIsolateAsHelper(isolate_, true); 648 Thread::EnterIsolateAsHelper(isolate_, true);
594 { 649 {
595 StackZone stack_zone(Thread::Current()); 650 StackZone stack_zone(Thread::Current());
596 Zone* zone = stack_zone.GetZone(); 651 Zone* zone = stack_zone.GetZone();
597 SkippedCodeFunctions* skipped_code_functions = 652 SkippedCodeFunctions* skipped_code_functions =
598 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL; 653 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL;
599 MarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_, 654 SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_,
600 delay_set_, skipped_code_functions); 655 delay_set_, skipped_code_functions);
601 // Phase 1: Populate and drain marking stack in task. 656 // Phase 1: Iterate over roots in tasks.
602 // TODO(koda): Split root iteration work among multiple tasks.
603 marker_->IterateRoots(isolate_, &visitor, 657 marker_->IterateRoots(isolate_, &visitor,
604 visit_prologue_weak_persistent_handles_); 658 visit_prologue_weak_persistent_handles_,
605 visitor.DrainMarkingStack(); 659 task_index_, num_tasks_);
660 // Phase 2: Drain marking stack from tasks.
Ivan Posva 2015/10/01 17:02:54 Shouldn't phase 2 start after a barrier?
koda 2015/10/01 20:30:11 Obsolete after combining the phases.
661 ASSERT(AtomicOperations::LoadRelaxed(num_busy_) ==
662 static_cast<uword>(num_tasks_));
Ivan Posva 2015/10/01 17:02:54 This looks like you want to add a LoadRelaxed(intr
koda 2015/10/01 20:30:11 Obsolete after combining the phases.
606 barrier_->Sync(); 663 barrier_->Sync();
Ivan Posva 2015/10/01 17:02:54 Is this barrier really necessary? The tasks that d
koda 2015/10/01 20:30:10 It was necessary to support the ASSERT in DrainMar
607 // Phase 2: Weak processing and follow-up marking on main thread. 664 do {
665 visitor.DrainMarkingStack();
666 // I can't find more work right now. If no other task is busy,
667 // then there will never be more work (NB: 1 is *before* decrement).
668 if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break;
669 // Busy wait for some work to appear.
670 while (marking_stack_->IsEmpty() &&
Ivan Posva 2015/10/01 17:02:55 How do you plan to fix the busy looping?
koda 2015/10/01 20:30:11 We can replace the mutex inside marking_stack_ wit
671 AtomicOperations::LoadRelaxed(num_busy_) > 0) {
672 }
673 // If no tasks are busy, there will never be more work.
674 if (AtomicOperations::LoadRelaxed(num_busy_) == 0) break;
675 // I saw some work; get busy and compete for it.
Ivan Posva 2015/10/01 17:02:55 Style comment: It is hard to read these blocks of
koda 2015/10/01 20:30:11 Done.
676 AtomicOperations::FetchAndIncrement(num_busy_);
677 } while (true);
678 ASSERT(AtomicOperations::LoadRelaxed(num_busy_) == 0);
608 barrier_->Sync(); 679 barrier_->Sync();
609 // Phase 3: Finalize results from all markers (detach code, etc.). 680 // Phase 3: Weak processing and follow-up marking on main thread.
681 barrier_->Sync();
682 // Phase 4: Finalize results from all markers (detach code, etc.).
683 if (FLAG_log_marker_tasks) {
684 THR_Print("Task %" Pd " marked %" Pd " bytes.\n",
685 task_index_, visitor.marked_bytes());
686 }
610 marker_->FinalizeResultsFrom(&visitor); 687 marker_->FinalizeResultsFrom(&visitor);
611 } 688 }
612 Thread::ExitIsolateAsHelper(true); 689 Thread::ExitIsolateAsHelper(true);
613 // This task is done. Notify the original thread. 690 // This task is done. Notify the original thread.
614 barrier_->Exit(); 691 barrier_->Exit();
615 } 692 }
616 693
617 private: 694 private:
618 GCMarker* marker_; 695 GCMarker* marker_;
619 Isolate* isolate_; 696 Isolate* isolate_;
620 Heap* heap_; 697 Heap* heap_;
621 PageSpace* page_space_; 698 PageSpace* page_space_;
622 MarkingStack* marking_stack_; 699 MarkingStack* marking_stack_;
623 DelaySet* delay_set_; 700 DelaySet* delay_set_;
624 ThreadBarrier* barrier_; 701 ThreadBarrier* barrier_;
625 bool collect_code_; 702 bool collect_code_;
626 bool visit_prologue_weak_persistent_handles_; 703 bool visit_prologue_weak_persistent_handles_;
704 const intptr_t task_index_;
705 const intptr_t num_tasks_;
706 uintptr_t* num_busy_;
627 707
628 DISALLOW_COPY_AND_ASSIGN(MarkTask); 708 DISALLOW_COPY_AND_ASSIGN(MarkTask);
629 }; 709 };
630 710
631 711
632 void GCMarker::FinalizeResultsFrom(MarkingVisitor* visitor) { 712 template<class MarkingVisitorType>
713 void GCMarker::FinalizeResultsFrom(MarkingVisitorType* visitor) {
633 { 714 {
634 MutexLocker ml(&stats_mutex_); 715 MutexLocker ml(&stats_mutex_);
635 marked_bytes_ += visitor->marked_bytes(); 716 marked_bytes_ += visitor->marked_bytes();
636 // Class heap stats are not themselves thread-safe yet, so we update the 717 // Class heap stats are not themselves thread-safe yet, so we update the
637 // stats while holding stats_mutex_. 718 // stats while holding stats_mutex_.
638 ClassTable* table = heap_->isolate()->class_table(); 719 ClassTable* table = heap_->isolate()->class_table();
639 for (intptr_t i = 0; i < table->NumCids(); ++i) { 720 for (intptr_t i = 0; i < table->NumCids(); ++i) {
640 const intptr_t count = visitor->live_count(i); 721 const intptr_t count = visitor->live_count(i);
641 if (count > 0) { 722 if (count > 0) {
642 const intptr_t size = visitor->live_size(i); 723 const intptr_t size = visitor->live_size(i);
(...skipping 17 matching lines...) Expand all
660 Zone* zone = stack_zone.GetZone(); 741 Zone* zone = stack_zone.GetZone();
661 MarkingStack marking_stack; 742 MarkingStack marking_stack;
662 DelaySet delay_set; 743 DelaySet delay_set;
663 const bool visit_prologue_weak_persistent_handles = !invoke_api_callbacks; 744 const bool visit_prologue_weak_persistent_handles = !invoke_api_callbacks;
664 marked_bytes_ = 0; 745 marked_bytes_ = 0;
665 const int num_tasks = FLAG_marker_tasks; 746 const int num_tasks = FLAG_marker_tasks;
666 if (num_tasks == 0) { 747 if (num_tasks == 0) {
667 // Mark everything on main thread. 748 // Mark everything on main thread.
668 SkippedCodeFunctions* skipped_code_functions = 749 SkippedCodeFunctions* skipped_code_functions =
669 collect_code ? new(zone) SkippedCodeFunctions() : NULL; 750 collect_code ? new(zone) SkippedCodeFunctions() : NULL;
670 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, 751 UnsyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
671 &delay_set, skipped_code_functions); 752 &delay_set, skipped_code_functions);
672 IterateRoots(isolate, &mark, visit_prologue_weak_persistent_handles); 753 IterateRoots(isolate, &mark, visit_prologue_weak_persistent_handles,
754 0, 1);
673 mark.DrainMarkingStack(); 755 mark.DrainMarkingStack();
674 IterateWeakReferences(isolate, &mark); 756 IterateWeakReferences(isolate, &mark);
675 MarkingWeakVisitor mark_weak; 757 MarkingWeakVisitor mark_weak;
676 IterateWeakRoots(isolate, &mark_weak, 758 IterateWeakRoots(isolate, &mark_weak,
677 !visit_prologue_weak_persistent_handles); 759 !visit_prologue_weak_persistent_handles);
678 // All marking done; detach code, etc. 760 // All marking done; detach code, etc.
679 FinalizeResultsFrom(&mark); 761 FinalizeResultsFrom(&mark);
680 } else { 762 } else {
681 if (num_tasks > 1) { 763 ThreadBarrier barrier(num_tasks + 1);
682 // TODO(koda): Support multiple: 764 // Used to coordinate draining among tasks; all start out as 'busy'.
683 // 1. non-concurrent tasks, after splitting root iteration work, then 765 uintptr_t num_busy = num_tasks;
684 // 2. concurrent tasks, after synchronizing headers. 766 // Phase 1: Iterate over roots in tasks.
685 FATAL("Multiple marking tasks not yet supported"); 767 for (intptr_t i = 0; i < num_tasks; ++i) {
768 MarkTask* mark_task =
769 new MarkTask(this, isolate, heap_, page_space, &marking_stack,
770 &delay_set, &barrier, collect_code,
771 visit_prologue_weak_persistent_handles,
772 i, num_tasks, &num_busy);
773 ThreadPool* pool = Dart::thread_pool();
774 pool->Run(mark_task);
686 } 775 }
687 ThreadBarrier barrier(num_tasks + 1); // +1 for the main thread.
688 // Phase 1: Populate and drain marking stack in task.
689 MarkTask* mark_task =
690 new MarkTask(this, isolate, heap_, page_space, &marking_stack,
691 &delay_set, &barrier, collect_code,
692 visit_prologue_weak_persistent_handles);
693 ThreadPool* pool = Dart::thread_pool();
694 pool->Run(mark_task);
695 barrier.Sync(); 776 barrier.Sync();
696 // Phase 2: Weak processing and follow-up marking on main thread. 777 // Phase 2: Drain marking stack from tasks.
778 barrier.Sync();
779 // Phase 3: Weak processing and follow-up marking on main thread.
697 SkippedCodeFunctions* skipped_code_functions = 780 SkippedCodeFunctions* skipped_code_functions =
698 collect_code ? new(zone) SkippedCodeFunctions() : NULL; 781 collect_code ? new(zone) SkippedCodeFunctions() : NULL;
699 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, 782 SyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
700 &delay_set, skipped_code_functions); 783 &delay_set, skipped_code_functions);
701 IterateWeakReferences(isolate, &mark); 784 IterateWeakReferences(isolate, &mark);
702 MarkingWeakVisitor mark_weak; 785 MarkingWeakVisitor mark_weak;
703 IterateWeakRoots(isolate, &mark_weak, 786 IterateWeakRoots(isolate, &mark_weak,
704 !visit_prologue_weak_persistent_handles); 787 !visit_prologue_weak_persistent_handles);
705 barrier.Sync(); 788 barrier.Sync();
706 // Phase 3: Finalize results from all markers (detach code, etc.). 789 // Phase 4: Finalize results from all markers (detach code, etc.).
790 if (FLAG_log_marker_tasks) {
791 THR_Print("Main thread marked %" Pd " bytes.\n",
792 mark.marked_bytes());
793 }
707 FinalizeResultsFrom(&mark); 794 FinalizeResultsFrom(&mark);
708 barrier.Exit(); 795 barrier.Exit();
709 } 796 }
710 delay_set.ClearReferences(); 797 delay_set.ClearReferences();
711 ProcessWeakTables(page_space); 798 ProcessWeakTables(page_space);
712 ProcessObjectIdTable(isolate); 799 ProcessObjectIdTable(isolate);
713 } 800 }
714 Epilogue(isolate, invoke_api_callbacks); 801 Epilogue(isolate, invoke_api_callbacks);
715 } 802 }
716 803
717 } // namespace dart 804 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/gc_marker.h ('k') | runtime/vm/heap_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698