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

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

Issue 1271833002: Chunk-wise marking stack processing. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Encapsulate visitor's interface to marking stack in WorkList inner class. Created 5 years, 4 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
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/thread_pool.h" 19 #include "vm/thread_pool.h"
19 #include "vm/visitor.h" 20 #include "vm/visitor.h"
20 #include "vm/object_id_ring.h" 21 #include "vm/object_id_ring.h"
21 22
22 namespace dart { 23 namespace dart {
23 24
24 // A simple chunked marking stack. 25 typedef StoreBufferBlock PointerBlock; // TODO(koda): Rename to PointerBlock.
25 class MarkingStack : public ValueObject { 26 typedef StoreBuffer MarkingStack; // TODO(koda): Create shared base class.
26 public:
27 MarkingStack()
28 : head_(new MarkingStackChunk()),
29 empty_chunks_(NULL),
30 marking_stack_(NULL),
31 top_(0) {
32 marking_stack_ = head_->MarkingStackChunkMemory();
33 }
34
35 ~MarkingStack() {
36 // TODO(iposva): Consider caching a couple emtpy marking stack chunks.
37 ASSERT(IsEmpty());
38 delete head_;
39 MarkingStackChunk* next;
40 while (empty_chunks_ != NULL) {
41 next = empty_chunks_->next();
42 delete empty_chunks_;
43 empty_chunks_ = next;
44 }
45 }
46
47 bool IsEmpty() const {
48 return IsMarkingStackChunkEmpty() && (head_->next() == NULL);
49 }
50
51 void Push(RawObject* value) {
52 ASSERT(!IsMarkingStackChunkFull());
53 marking_stack_[top_] = value;
54 top_++;
55 if (IsMarkingStackChunkFull()) {
56 MarkingStackChunk* new_chunk;
57 if (empty_chunks_ == NULL) {
58 new_chunk = new MarkingStackChunk();
59 } else {
60 new_chunk = empty_chunks_;
61 empty_chunks_ = new_chunk->next();
62 }
63 new_chunk->set_next(head_);
64 head_ = new_chunk;
65 marking_stack_ = head_->MarkingStackChunkMemory();
66 top_ = 0;
67 }
68 }
69
70 RawObject* Pop() {
71 ASSERT(head_ != NULL);
72 ASSERT(!IsEmpty());
73 if (IsMarkingStackChunkEmpty()) {
74 MarkingStackChunk* empty_chunk = head_;
75 head_ = head_->next();
76 empty_chunk->set_next(empty_chunks_);
77 empty_chunks_ = empty_chunk;
78 marking_stack_ = head_->MarkingStackChunkMemory();
79 top_ = MarkingStackChunk::kMarkingStackChunkSize;
80 }
81 top_--;
82 return marking_stack_[top_];
83 }
84
85 private:
86 class MarkingStackChunk {
87 public:
88 MarkingStackChunk() : next_(NULL) {}
89 ~MarkingStackChunk() {}
90
91 RawObject** MarkingStackChunkMemory() {
92 return &memory_[0];
93 }
94
95 MarkingStackChunk* next() const { return next_; }
96 void set_next(MarkingStackChunk* value) { next_ = value; }
97
98 static const uint32_t kMarkingStackChunkSize = 1024;
99
100 private:
101 RawObject* memory_[kMarkingStackChunkSize];
102 MarkingStackChunk* next_;
103
104 DISALLOW_COPY_AND_ASSIGN(MarkingStackChunk);
105 };
106
107 bool IsMarkingStackChunkFull() const {
108 return top_ == MarkingStackChunk::kMarkingStackChunkSize;
109 }
110
111 bool IsMarkingStackChunkEmpty() const {
112 return top_ == 0;
113 }
114
115 MarkingStackChunk* head_;
116 MarkingStackChunk* empty_chunks_;
117 RawObject** marking_stack_;
118 uint32_t top_;
119
120 DISALLOW_COPY_AND_ASSIGN(MarkingStack);
121 };
122
123 27
124 class DelaySet { 28 class DelaySet {
125 private: 29 private:
126 typedef std::multimap<RawObject*, RawWeakProperty*> Map; 30 typedef std::multimap<RawObject*, RawWeakProperty*> Map;
127 typedef std::pair<RawObject*, RawWeakProperty*> MapEntry; 31 typedef std::pair<RawObject*, RawWeakProperty*> MapEntry;
128 32
129 public: 33 public:
130 DelaySet() : mutex_(new Mutex()) {} 34 DelaySet() : mutex_(new Mutex()) {}
131 ~DelaySet() { delete mutex_; } 35 ~DelaySet() { delete mutex_; }
132 36
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 PageSpace* page_space, 81 PageSpace* page_space,
178 MarkingStack* marking_stack, 82 MarkingStack* marking_stack,
179 DelaySet* delay_set, 83 DelaySet* delay_set,
180 bool visit_function_code) 84 bool visit_function_code)
181 : ObjectPointerVisitor(isolate), 85 : ObjectPointerVisitor(isolate),
182 thread_(Thread::Current()), 86 thread_(Thread::Current()),
183 heap_(heap), 87 heap_(heap),
184 vm_heap_(Dart::vm_isolate()->heap()), 88 vm_heap_(Dart::vm_isolate()->heap()),
185 class_table_(isolate->class_table()), 89 class_table_(isolate->class_table()),
186 page_space_(page_space), 90 page_space_(page_space),
187 marking_stack_(marking_stack), 91 work_list_(marking_stack),
188 delay_set_(delay_set), 92 delay_set_(delay_set),
189 visiting_old_object_(NULL), 93 visiting_old_object_(NULL),
190 visit_function_code_(visit_function_code) { 94 visit_function_code_(visit_function_code),
95 marked_bytes_(0) {
191 ASSERT(heap_ != vm_heap_); 96 ASSERT(heap_ != vm_heap_);
192 ASSERT(thread_->isolate() == isolate); 97 ASSERT(thread_->isolate() == isolate);
193 } 98 }
194 99
195 ~MarkingVisitor() { 100 uintptr_t marked_bytes() const { return marked_bytes_; }
196 // 'Finalize' should be explicitly called before destruction. 101
197 ASSERT(marking_stack_ == NULL); 102 // Returns true if some non-zero amount of work was performed.
103 bool DrainMarkingStack() {
104 RawObject* raw_obj = work_list_.Pop();
105 if (raw_obj == NULL) {
106 ASSERT(visiting_old_object_ == NULL);
107 return false;
108 }
109 do {
110 VisitingOldObject(raw_obj);
111 const intptr_t class_id = raw_obj->GetClassId();
112 // Currently, classes are considered roots (see issue 18284), so at this
113 // point, they should all be marked.
114 ASSERT(isolate()->class_table()->At(class_id)->IsMarked());
115 if (class_id != kWeakPropertyCid) {
116 marked_bytes_ += raw_obj->VisitPointers(this);
117 } else {
118 RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj);
119 marked_bytes_ += raw_weak->Size();
120 ProcessWeakProperty(raw_weak);
121 }
122 raw_obj = work_list_.Pop();
123 } while (raw_obj != NULL);
124 VisitingOldObject(NULL);
125 return true;
198 } 126 }
199 127
200 MarkingStack* marking_stack() const { return marking_stack_; }
201
202 void VisitPointers(RawObject** first, RawObject** last) { 128 void VisitPointers(RawObject** first, RawObject** last) {
203 for (RawObject** current = first; current <= last; current++) { 129 for (RawObject** current = first; current <= last; current++) {
204 MarkObject(*current, current); 130 MarkObject(*current, current);
205 } 131 }
206 } 132 }
207 133
208 bool visit_function_code() const { return visit_function_code_; } 134 bool visit_function_code() const { return visit_function_code_; }
209 135
210 virtual MallocGrowableArray<RawFunction*>* skipped_code_functions() { 136 virtual MallocGrowableArray<RawFunction*>* skipped_code_functions() {
211 return &skipped_code_functions_; 137 return &skipped_code_functions_;
(...skipping 29 matching lines...) Expand all
241 // Key is gray or black. Make the weak property black. 167 // Key is gray or black. Make the weak property black.
242 raw_weak->VisitPointers(this); 168 raw_weak->VisitPointers(this);
243 } 169 }
244 } 170 }
245 171
246 // Called when all marking is complete. 172 // Called when all marking is complete.
247 void Finalize() { 173 void Finalize() {
248 if (!visit_function_code_) { 174 if (!visit_function_code_) {
249 DetachCode(); 175 DetachCode();
250 } 176 }
251 // Fail fast on attempts to mark after finalizing. 177 work_list_.Finalize();
252 marking_stack_ = NULL;
253 } 178 }
254 179
255 void VisitingOldObject(RawObject* obj) { 180 void VisitingOldObject(RawObject* obj) {
256 ASSERT((obj == NULL) || obj->IsOldObject()); 181 ASSERT((obj == NULL) || obj->IsOldObject());
257 visiting_old_object_ = obj; 182 visiting_old_object_ = obj;
258 } 183 }
259 184
260 private: 185 private:
186 class WorkList : public ValueObject {
187 public:
188 explicit WorkList(MarkingStack* marking_stack)
189 : marking_stack_(marking_stack) {
190 work_ = marking_stack_->PopEmptyBlock();
191 }
192
193 ~WorkList() {
194 ASSERT(work_ == NULL);
195 ASSERT(marking_stack_ == NULL);
196 }
197
198 // Returns NULL if no more work was found.
199 RawObject* Pop() {
200 ASSERT(work_ != NULL);
201 if (!work_->IsEmpty()) {
202 return work_->Pop();
Ivan Posva 2015/08/06 07:02:09 How about structuring it like below, which to me r
koda 2015/08/07 12:59:07 Done.
203 }
204 // TODO(koda): Track over/underflow events and use in heuristics to
205 // distribute work and prevent degenerate flip-flopping.
206 PointerBlock* new_work = marking_stack_->PopNonEmptyBlock();
207 if (new_work == NULL) {
208 return NULL;
209 }
210 marking_stack_->PushBlock(work_);
211 work_ = new_work;
212 return work_->Pop();
213 }
214
215 void Push(RawObject* raw_obj) {
216 if (work_->IsFull()) {
217 // TODO(koda): Track over/underflow events and use in heuristics to
218 // distribute work and prevent degenerate flip-flopping.
219 marking_stack_->PushBlock(work_, false);
220 work_ = marking_stack_->PopEmptyBlock();
221 }
222 work_->Push(raw_obj);
223 }
224
225 void Finalize() {
226 ASSERT(work_->IsEmpty());
227 marking_stack_->PushBlock(work_, false);
228 work_ = NULL;
229 // Fail fast on attempts to mark after finalizing.
230 marking_stack_ = NULL;
231 }
232
233 private:
234 PointerBlock* work_;
235 MarkingStack* marking_stack_;
236 };
237
261 void MarkAndPush(RawObject* raw_obj) { 238 void MarkAndPush(RawObject* raw_obj) {
262 ASSERT(raw_obj->IsHeapObject()); 239 ASSERT(raw_obj->IsHeapObject());
263 ASSERT((FLAG_verify_before_gc || FLAG_verify_before_gc) ? 240 ASSERT((FLAG_verify_before_gc || FLAG_verify_before_gc) ?
264 page_space_->Contains(RawObject::ToAddr(raw_obj)) : 241 page_space_->Contains(RawObject::ToAddr(raw_obj)) :
265 true); 242 true);
266 243
267 // Mark the object and push it on the marking stack. 244 // Mark the object and push it on the marking stack.
268 ASSERT(!raw_obj->IsMarked()); 245 ASSERT(!raw_obj->IsMarked());
269 const bool is_watched = raw_obj->IsWatched(); 246 const bool is_watched = raw_obj->IsWatched();
270 raw_obj->SetMarkBitUnsynchronized(); 247 raw_obj->SetMarkBitUnsynchronized();
271 raw_obj->ClearRememberedBitUnsynchronized(); 248 raw_obj->ClearRememberedBitUnsynchronized();
272 raw_obj->ClearWatchedBitUnsynchronized(); 249 raw_obj->ClearWatchedBitUnsynchronized();
273 if (is_watched) { 250 if (is_watched) {
274 delay_set_->VisitValuesForKey(raw_obj, this); 251 delay_set_->VisitValuesForKey(raw_obj, this);
275 } 252 }
276 marking_stack_->Push(raw_obj); 253 work_list_.Push(raw_obj);
277 } 254 }
278 255
279 void MarkObject(RawObject* raw_obj, RawObject** p) { 256 void MarkObject(RawObject* raw_obj, RawObject** p) {
280 // Fast exit if the raw object is a Smi. 257 // Fast exit if the raw object is a Smi.
281 if (!raw_obj->IsHeapObject()) { 258 if (!raw_obj->IsHeapObject()) {
282 return; 259 return;
283 } 260 }
284 261
285 // Fast exit if the raw object is marked. 262 // Fast exit if the raw object is marked.
286 if (raw_obj->IsMarked()) { 263 if (raw_obj->IsMarked()) {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 } 329 }
353 // Clean up. 330 // Clean up.
354 skipped_code_functions_.Clear(); 331 skipped_code_functions_.Clear();
355 } 332 }
356 333
357 Thread* thread_; 334 Thread* thread_;
358 Heap* heap_; 335 Heap* heap_;
359 Heap* vm_heap_; 336 Heap* vm_heap_;
360 ClassTable* class_table_; 337 ClassTable* class_table_;
361 PageSpace* page_space_; 338 PageSpace* page_space_;
362 MarkingStack* marking_stack_; 339 WorkList work_list_;
363 DelaySet* delay_set_; 340 DelaySet* delay_set_;
364 RawObject* visiting_old_object_; 341 RawObject* visiting_old_object_;
365 const bool visit_function_code_; 342 const bool visit_function_code_;
366 MallocGrowableArray<RawFunction*> skipped_code_functions_; 343 MallocGrowableArray<RawFunction*> skipped_code_functions_;
344 uintptr_t marked_bytes_;
367 345
368 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitor); 346 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitor);
369 }; 347 };
370 348
371 349
372 static bool IsUnreachable(const RawObject* raw_obj) { 350 static bool IsUnreachable(const RawObject* raw_obj) {
373 if (!raw_obj->IsHeapObject()) { 351 if (!raw_obj->IsHeapObject()) {
374 return false; 352 return false;
375 } 353 }
376 if (raw_obj == Object::null()) { 354 if (raw_obj == Object::null()) {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 break; 454 break;
477 } 455 }
478 } 456 }
479 // If all key objects are unreachable put the reference on a 457 // If all key objects are unreachable put the reference on a
480 // delay queue. This reference will be revisited if another 458 // delay queue. This reference will be revisited if another
481 // reference is marked. 459 // reference is marked.
482 if (is_unreachable) { 460 if (is_unreachable) {
483 state->DelayWeakReferenceSet(reference_set); 461 state->DelayWeakReferenceSet(reference_set);
484 } 462 }
485 } 463 }
486 if (!visitor->marking_stack()->IsEmpty()) { 464 if (!visitor->DrainMarkingStack()) {
487 DrainMarkingStack(isolate, visitor);
488 } else {
489 // Break out of the loop if there has been no forward process. 465 // Break out of the loop if there has been no forward process.
490 // All key objects in the weak reference sets are unreachable 466 // All key objects in the weak reference sets are unreachable
491 // so we reset the weak reference sets queue. 467 // so we reset the weak reference sets queue.
492 state->set_delayed_weak_reference_sets(NULL); 468 state->set_delayed_weak_reference_sets(NULL);
493 break; 469 break;
494 } 470 }
495 } 471 }
496 ASSERT(state->delayed_weak_reference_sets() == NULL); 472 ASSERT(state->delayed_weak_reference_sets() == NULL);
497 // All weak reference sets are zone allocated and unmarked references which 473 // All weak reference sets are zone allocated and unmarked references which
498 // were on the delay queue will be freed when the zone is released in the 474 // were on the delay queue will be freed when the zone is released in the
499 // epilog callback. 475 // epilog callback.
500 } 476 }
501 477
502 478
503 void GCMarker::DrainMarkingStack(Isolate* isolate,
504 MarkingVisitor* visitor) {
505 while (!visitor->marking_stack()->IsEmpty()) {
506 RawObject* raw_obj = visitor->marking_stack()->Pop();
507 visitor->VisitingOldObject(raw_obj);
508 const intptr_t class_id = raw_obj->GetClassId();
509 // Currently, classes are considered roots (see issue 18284), so at this
510 // point, they should all be marked.
511 ASSERT(isolate->class_table()->At(class_id)->IsMarked());
512 if (class_id != kWeakPropertyCid) {
513 marked_bytes_ += raw_obj->VisitPointers(visitor);
514 } else {
515 RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj);
516 marked_bytes_ += raw_weak->Size();
517 visitor->ProcessWeakProperty(raw_weak);
518 }
519 }
520 visitor->VisitingOldObject(NULL);
521 }
522
523
524 void GCMarker::ProcessWeakTables(PageSpace* page_space) { 479 void GCMarker::ProcessWeakTables(PageSpace* page_space) {
525 for (int sel = 0; 480 for (int sel = 0;
526 sel < Heap::kNumWeakSelectors; 481 sel < Heap::kNumWeakSelectors;
527 sel++) { 482 sel++) {
528 WeakTable* table = heap_->GetWeakTable( 483 WeakTable* table = heap_->GetWeakTable(
529 Heap::kOld, static_cast<Heap::WeakSelector>(sel)); 484 Heap::kOld, static_cast<Heap::WeakSelector>(sel));
530 intptr_t size = table->size(); 485 intptr_t size = table->size();
531 for (intptr_t i = 0; i < size; i++) { 486 for (intptr_t i = 0; i < size; i++) {
532 if (table->IsValidEntryAt(i)) { 487 if (table->IsValidEntryAt(i)) {
533 RawObject* raw_obj = table->ObjectAt(i); 488 RawObject* raw_obj = table->ObjectAt(i);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 Prologue(isolate, invoke_api_callbacks); 531 Prologue(isolate, invoke_api_callbacks);
577 // The API prologue/epilogue may create/destroy zones, so we must not 532 // The API prologue/epilogue may create/destroy zones, so we must not
578 // depend on zone allocations surviving beyond the epilogue callback. 533 // depend on zone allocations surviving beyond the epilogue callback.
579 { 534 {
580 StackZone zone(isolate); 535 StackZone zone(isolate);
581 MarkingStack marking_stack; 536 MarkingStack marking_stack;
582 DelaySet delay_set; 537 DelaySet delay_set;
583 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, 538 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
584 &delay_set, visit_function_code); 539 &delay_set, visit_function_code);
585 IterateRoots(isolate, &mark, !invoke_api_callbacks); 540 IterateRoots(isolate, &mark, !invoke_api_callbacks);
586 DrainMarkingStack(isolate, &mark); 541 mark.DrainMarkingStack();
587 IterateWeakReferences(isolate, &mark); 542 IterateWeakReferences(isolate, &mark);
588 MarkingWeakVisitor mark_weak; 543 MarkingWeakVisitor mark_weak;
589 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks); 544 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks);
545 // TODO(koda): Add hand-over callback and centralize skipped code functions.
546 marked_bytes_ = mark.marked_bytes();
590 mark.Finalize(); 547 mark.Finalize();
591 delay_set.ClearReferences(); 548 delay_set.ClearReferences();
592 ProcessWeakTables(page_space); 549 ProcessWeakTables(page_space);
593 ProcessObjectIdTable(isolate); 550 ProcessObjectIdTable(isolate);
594 } 551 }
595 Epilogue(isolate, invoke_api_callbacks); 552 Epilogue(isolate, invoke_api_callbacks);
596 } 553 }
597 554
598 } // namespace dart 555 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/gc_marker.h ('k') | runtime/vm/store_buffer.h » ('j') | runtime/vm/store_buffer.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698