Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |