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

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: Add missing argument. 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
« no previous file with comments | « runtime/vm/gc_marker.h ('k') | runtime/vm/store_buffer.h » ('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/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 // TODO(koda): Track over/underflow events and use in heuristics to
203 // distribute work and prevent degenerate flip-flopping.
204 PointerBlock* new_work = marking_stack_->PopNonEmptyBlock();
205 if (new_work == NULL) {
206 return NULL;
207 }
208 marking_stack_->PushBlock(work_, false);
209 work_ = new_work;
210 }
211 return work_->Pop();
212 }
213
214 void Push(RawObject* raw_obj) {
215 if (work_->IsFull()) {
216 // TODO(koda): Track over/underflow events and use in heuristics to
217 // distribute work and prevent degenerate flip-flopping.
218 marking_stack_->PushBlock(work_, false);
219 work_ = marking_stack_->PopEmptyBlock();
220 }
221 work_->Push(raw_obj);
222 }
223
224 void Finalize() {
225 ASSERT(work_->IsEmpty());
226 marking_stack_->PushBlock(work_, false);
227 work_ = NULL;
228 // Fail fast on attempts to mark after finalizing.
229 marking_stack_ = NULL;
230 }
231
232 private:
233 PointerBlock* work_;
234 MarkingStack* marking_stack_;
235 };
236
261 void MarkAndPush(RawObject* raw_obj) { 237 void MarkAndPush(RawObject* raw_obj) {
262 ASSERT(raw_obj->IsHeapObject()); 238 ASSERT(raw_obj->IsHeapObject());
263 ASSERT((FLAG_verify_before_gc || FLAG_verify_before_gc) ? 239 ASSERT((FLAG_verify_before_gc || FLAG_verify_before_gc) ?
264 page_space_->Contains(RawObject::ToAddr(raw_obj)) : 240 page_space_->Contains(RawObject::ToAddr(raw_obj)) :
265 true); 241 true);
266 242
267 // Mark the object and push it on the marking stack. 243 // Mark the object and push it on the marking stack.
268 ASSERT(!raw_obj->IsMarked()); 244 ASSERT(!raw_obj->IsMarked());
269 const bool is_watched = raw_obj->IsWatched(); 245 const bool is_watched = raw_obj->IsWatched();
270 raw_obj->SetMarkBitUnsynchronized(); 246 raw_obj->SetMarkBitUnsynchronized();
271 raw_obj->ClearRememberedBitUnsynchronized(); 247 raw_obj->ClearRememberedBitUnsynchronized();
272 raw_obj->ClearWatchedBitUnsynchronized(); 248 raw_obj->ClearWatchedBitUnsynchronized();
273 if (is_watched) { 249 if (is_watched) {
274 delay_set_->VisitValuesForKey(raw_obj, this); 250 delay_set_->VisitValuesForKey(raw_obj, this);
275 } 251 }
276 marking_stack_->Push(raw_obj); 252 work_list_.Push(raw_obj);
277 } 253 }
278 254
279 void MarkObject(RawObject* raw_obj, RawObject** p) { 255 void MarkObject(RawObject* raw_obj, RawObject** p) {
280 // Fast exit if the raw object is a Smi. 256 // Fast exit if the raw object is a Smi.
281 if (!raw_obj->IsHeapObject()) { 257 if (!raw_obj->IsHeapObject()) {
282 return; 258 return;
283 } 259 }
284 260
285 // Fast exit if the raw object is marked. 261 // Fast exit if the raw object is marked.
286 if (raw_obj->IsMarked()) { 262 if (raw_obj->IsMarked()) {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 } 328 }
353 // Clean up. 329 // Clean up.
354 skipped_code_functions_.Clear(); 330 skipped_code_functions_.Clear();
355 } 331 }
356 332
357 Thread* thread_; 333 Thread* thread_;
358 Heap* heap_; 334 Heap* heap_;
359 Heap* vm_heap_; 335 Heap* vm_heap_;
360 ClassTable* class_table_; 336 ClassTable* class_table_;
361 PageSpace* page_space_; 337 PageSpace* page_space_;
362 MarkingStack* marking_stack_; 338 WorkList work_list_;
363 DelaySet* delay_set_; 339 DelaySet* delay_set_;
364 RawObject* visiting_old_object_; 340 RawObject* visiting_old_object_;
365 const bool visit_function_code_; 341 const bool visit_function_code_;
366 MallocGrowableArray<RawFunction*> skipped_code_functions_; 342 MallocGrowableArray<RawFunction*> skipped_code_functions_;
343 uintptr_t marked_bytes_;
367 344
368 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitor); 345 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitor);
369 }; 346 };
370 347
371 348
372 static bool IsUnreachable(const RawObject* raw_obj) { 349 static bool IsUnreachable(const RawObject* raw_obj) {
373 if (!raw_obj->IsHeapObject()) { 350 if (!raw_obj->IsHeapObject()) {
374 return false; 351 return false;
375 } 352 }
376 if (raw_obj == Object::null()) { 353 if (raw_obj == Object::null()) {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 break; 453 break;
477 } 454 }
478 } 455 }
479 // If all key objects are unreachable put the reference on a 456 // If all key objects are unreachable put the reference on a
480 // delay queue. This reference will be revisited if another 457 // delay queue. This reference will be revisited if another
481 // reference is marked. 458 // reference is marked.
482 if (is_unreachable) { 459 if (is_unreachable) {
483 state->DelayWeakReferenceSet(reference_set); 460 state->DelayWeakReferenceSet(reference_set);
484 } 461 }
485 } 462 }
486 if (!visitor->marking_stack()->IsEmpty()) { 463 if (!visitor->DrainMarkingStack()) {
487 DrainMarkingStack(isolate, visitor);
488 } else {
489 // Break out of the loop if there has been no forward process. 464 // Break out of the loop if there has been no forward process.
490 // All key objects in the weak reference sets are unreachable 465 // All key objects in the weak reference sets are unreachable
491 // so we reset the weak reference sets queue. 466 // so we reset the weak reference sets queue.
492 state->set_delayed_weak_reference_sets(NULL); 467 state->set_delayed_weak_reference_sets(NULL);
493 break; 468 break;
494 } 469 }
495 } 470 }
496 ASSERT(state->delayed_weak_reference_sets() == NULL); 471 ASSERT(state->delayed_weak_reference_sets() == NULL);
497 // All weak reference sets are zone allocated and unmarked references which 472 // 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 473 // were on the delay queue will be freed when the zone is released in the
499 // epilog callback. 474 // epilog callback.
500 } 475 }
501 476
502 477
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) { 478 void GCMarker::ProcessWeakTables(PageSpace* page_space) {
525 for (int sel = 0; 479 for (int sel = 0;
526 sel < Heap::kNumWeakSelectors; 480 sel < Heap::kNumWeakSelectors;
527 sel++) { 481 sel++) {
528 WeakTable* table = heap_->GetWeakTable( 482 WeakTable* table = heap_->GetWeakTable(
529 Heap::kOld, static_cast<Heap::WeakSelector>(sel)); 483 Heap::kOld, static_cast<Heap::WeakSelector>(sel));
530 intptr_t size = table->size(); 484 intptr_t size = table->size();
531 for (intptr_t i = 0; i < size; i++) { 485 for (intptr_t i = 0; i < size; i++) {
532 if (table->IsValidEntryAt(i)) { 486 if (table->IsValidEntryAt(i)) {
533 RawObject* raw_obj = table->ObjectAt(i); 487 RawObject* raw_obj = table->ObjectAt(i);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 Prologue(isolate, invoke_api_callbacks); 530 Prologue(isolate, invoke_api_callbacks);
577 // The API prologue/epilogue may create/destroy zones, so we must not 531 // The API prologue/epilogue may create/destroy zones, so we must not
578 // depend on zone allocations surviving beyond the epilogue callback. 532 // depend on zone allocations surviving beyond the epilogue callback.
579 { 533 {
580 StackZone zone(isolate); 534 StackZone zone(isolate);
581 MarkingStack marking_stack; 535 MarkingStack marking_stack;
582 DelaySet delay_set; 536 DelaySet delay_set;
583 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, 537 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
584 &delay_set, visit_function_code); 538 &delay_set, visit_function_code);
585 IterateRoots(isolate, &mark, !invoke_api_callbacks); 539 IterateRoots(isolate, &mark, !invoke_api_callbacks);
586 DrainMarkingStack(isolate, &mark); 540 mark.DrainMarkingStack();
587 IterateWeakReferences(isolate, &mark); 541 IterateWeakReferences(isolate, &mark);
588 MarkingWeakVisitor mark_weak; 542 MarkingWeakVisitor mark_weak;
589 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks); 543 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks);
544 // TODO(koda): Add hand-over callback and centralize skipped code functions.
545 marked_bytes_ = mark.marked_bytes();
590 mark.Finalize(); 546 mark.Finalize();
591 delay_set.ClearReferences(); 547 delay_set.ClearReferences();
592 ProcessWeakTables(page_space); 548 ProcessWeakTables(page_space);
593 ProcessObjectIdTable(isolate); 549 ProcessObjectIdTable(isolate);
594 } 550 }
595 Epilogue(isolate, invoke_api_callbacks); 551 Epilogue(isolate, invoke_api_callbacks);
596 } 552 }
597 553
598 } // namespace dart 554 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/gc_marker.h ('k') | runtime/vm/store_buffer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698