| 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> | |
| 8 #include <utility> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "vm/allocation.h" | 7 #include "vm/allocation.h" |
| 12 #include "vm/dart_api_state.h" | 8 #include "vm/dart_api_state.h" |
| 13 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
| 14 #include "vm/log.h" | 10 #include "vm/log.h" |
| 15 #include "vm/pages.h" | 11 #include "vm/pages.h" |
| 16 #include "vm/raw_object.h" | 12 #include "vm/raw_object.h" |
| 17 #include "vm/stack_frame.h" | 13 #include "vm/stack_frame.h" |
| 18 #include "vm/store_buffer.h" | 14 #include "vm/store_buffer.h" |
| 19 #include "vm/thread_barrier.h" | 15 #include "vm/thread_barrier.h" |
| 20 #include "vm/thread_pool.h" | 16 #include "vm/thread_pool.h" |
| 21 #include "vm/thread_registry.h" | 17 #include "vm/thread_registry.h" |
| 22 #include "vm/timeline.h" | 18 #include "vm/timeline.h" |
| 23 #include "vm/visitor.h" | 19 #include "vm/visitor.h" |
| 24 #include "vm/object_id_ring.h" | 20 #include "vm/object_id_ring.h" |
| 25 | 21 |
| 26 namespace dart { | 22 namespace dart { |
| 27 | 23 |
| 28 DEFINE_FLAG(int, marker_tasks, 2, | 24 DEFINE_FLAG(int, marker_tasks, 2, |
| 29 "The number of tasks to spawn during old gen GC marking (0 means " | 25 "The number of tasks to spawn during old gen GC marking (0 means " |
| 30 "perform all marking on main thread)."); | 26 "perform all marking on main thread)."); |
| 31 DEFINE_FLAG(bool, log_marker_tasks, false, | 27 DEFINE_FLAG(bool, log_marker_tasks, false, |
| 32 "Log debugging information for old gen GC marking tasks."); | 28 "Log debugging information for old gen GC marking tasks."); |
| 33 | 29 |
| 34 class DelaySet { | |
| 35 private: | |
| 36 typedef std::multimap<RawObject*, RawWeakProperty*> Map; | |
| 37 typedef std::pair<RawObject*, RawWeakProperty*> MapEntry; | |
| 38 | |
| 39 public: | |
| 40 DelaySet() : mutex_(new Mutex()) {} | |
| 41 ~DelaySet() { delete mutex_; } | |
| 42 | |
| 43 // After atomically setting the watched bit on a white key (see | |
| 44 // EnsureWatchedIfWhitewhich; this means the mark bit cannot be set | |
| 45 // without observing the watched bit), this method atomically | |
| 46 // inserts raw_weak if its key is *still* white, so that any future | |
| 47 // call to VisitValuesForKey is guaranteed to include its | |
| 48 // value. Returns true on success, and false if the key is no longer white. | |
| 49 bool InsertIfWhite(RawWeakProperty* raw_weak) { | |
| 50 MutexLocker ml(mutex_); | |
| 51 RawObject* raw_key = raw_weak->ptr()->key_; | |
| 52 if (raw_key->IsMarked()) return false; | |
| 53 // The key was white *after* acquiring the lock. Thus any future call to | |
| 54 // VisitValuesForKey is guaranteed to include the entry inserted below. | |
| 55 delay_set_.insert(std::make_pair(raw_key, raw_weak)); | |
| 56 return true; | |
| 57 } | |
| 58 | |
| 59 void ClearReferences() { | |
| 60 MutexLocker ml(mutex_); | |
| 61 for (Map::iterator it = delay_set_.begin(); it != delay_set_.end(); ++it) { | |
| 62 ASSERT(!it->first->IsMarked()); | |
| 63 WeakProperty::Clear(it->second); | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 // Visit all values with a key equal to raw_obj, which must already be marked. | |
| 68 void VisitValuesForKey(RawObject* raw_obj, ObjectPointerVisitor* visitor) { | |
| 69 ASSERT(raw_obj->IsMarked()); | |
| 70 // Extract the range into a temporary vector to iterate over it | |
| 71 // while delay_set_ may be modified. | |
| 72 std::vector<MapEntry> temp_copy; | |
| 73 { | |
| 74 MutexLocker ml(mutex_); | |
| 75 std::pair<Map::iterator, Map::iterator> ret = | |
| 76 delay_set_.equal_range(raw_obj); | |
| 77 temp_copy.insert(temp_copy.end(), ret.first, ret.second); | |
| 78 delay_set_.erase(ret.first, ret.second); | |
| 79 } | |
| 80 for (std::vector<MapEntry>::iterator it = temp_copy.begin(); | |
| 81 it != temp_copy.end(); ++it) { | |
| 82 it->second->VisitPointers(visitor); | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 private: | |
| 87 Map delay_set_; | |
| 88 Mutex* mutex_; | |
| 89 }; | |
| 90 | |
| 91 | |
| 92 class SkippedCodeFunctions : public ZoneAllocated { | 30 class SkippedCodeFunctions : public ZoneAllocated { |
| 93 public: | 31 public: |
| 94 SkippedCodeFunctions() {} | 32 SkippedCodeFunctions() {} |
| 95 | 33 |
| 96 void Add(RawFunction* func) { | 34 void Add(RawFunction* func) { |
| 97 skipped_code_functions_.Add(func); | 35 skipped_code_functions_.Add(func); |
| 98 } | 36 } |
| 99 | 37 |
| 100 void DetachCode() { | 38 void DetachCode() { |
| 101 intptr_t unoptimized_code_count = 0; | 39 intptr_t unoptimized_code_count = 0; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 }; | 143 }; |
| 206 | 144 |
| 207 | 145 |
| 208 template<bool sync> | 146 template<bool sync> |
| 209 class MarkingVisitorBase : public ObjectPointerVisitor { | 147 class MarkingVisitorBase : public ObjectPointerVisitor { |
| 210 public: | 148 public: |
| 211 MarkingVisitorBase(Isolate* isolate, | 149 MarkingVisitorBase(Isolate* isolate, |
| 212 Heap* heap, | 150 Heap* heap, |
| 213 PageSpace* page_space, | 151 PageSpace* page_space, |
| 214 MarkingStack* marking_stack, | 152 MarkingStack* marking_stack, |
| 215 DelaySet* delay_set, | |
| 216 SkippedCodeFunctions* skipped_code_functions) | 153 SkippedCodeFunctions* skipped_code_functions) |
| 217 : ObjectPointerVisitor(isolate), | 154 : ObjectPointerVisitor(isolate), |
| 218 thread_(Thread::Current()), | 155 thread_(Thread::Current()), |
| 219 heap_(heap), | 156 heap_(heap), |
| 220 vm_heap_(Dart::vm_isolate()->heap()), | 157 vm_heap_(Dart::vm_isolate()->heap()), |
| 221 class_stats_count_(isolate->class_table()->NumCids()), | 158 class_stats_count_(isolate->class_table()->NumCids()), |
| 222 class_stats_size_(isolate->class_table()->NumCids()), | 159 class_stats_size_(isolate->class_table()->NumCids()), |
| 223 page_space_(page_space), | 160 page_space_(page_space), |
| 224 work_list_(marking_stack), | 161 work_list_(marking_stack), |
| 225 delay_set_(delay_set), | 162 delayed_weak_properties_(NULL), |
| 226 visiting_old_object_(NULL), | 163 visiting_old_object_(NULL), |
| 227 skipped_code_functions_(skipped_code_functions), | 164 skipped_code_functions_(skipped_code_functions), |
| 228 marked_bytes_(0) { | 165 marked_bytes_(0) { |
| 229 ASSERT(heap_ != vm_heap_); | 166 ASSERT(heap_ != vm_heap_); |
| 230 ASSERT(thread_->isolate() == isolate); | 167 ASSERT(thread_->isolate() == isolate); |
| 231 class_stats_count_.SetLength(isolate->class_table()->NumCids()); | 168 class_stats_count_.SetLength(isolate->class_table()->NumCids()); |
| 232 class_stats_size_.SetLength(isolate->class_table()->NumCids()); | 169 class_stats_size_.SetLength(isolate->class_table()->NumCids()); |
| 233 for (intptr_t i = 0; i < class_stats_count_.length(); ++i) { | 170 for (intptr_t i = 0; i < class_stats_count_.length(); ++i) { |
| 234 class_stats_count_[i] = 0; | 171 class_stats_count_[i] = 0; |
| 235 class_stats_size_[i] = 0; | 172 class_stats_size_[i] = 0; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 247 } | 184 } |
| 248 | 185 |
| 249 // Returns true if some non-zero amount of work was performed. | 186 // Returns true if some non-zero amount of work was performed. |
| 250 bool DrainMarkingStack() { | 187 bool DrainMarkingStack() { |
| 251 RawObject* raw_obj = work_list_.Pop(); | 188 RawObject* raw_obj = work_list_.Pop(); |
| 252 if (raw_obj == NULL) { | 189 if (raw_obj == NULL) { |
| 253 ASSERT(visiting_old_object_ == NULL); | 190 ASSERT(visiting_old_object_ == NULL); |
| 254 return false; | 191 return false; |
| 255 } | 192 } |
| 256 do { | 193 do { |
| 257 VisitingOldObject(raw_obj); | 194 do { |
| 258 const intptr_t class_id = raw_obj->GetClassId(); | 195 // First drain the marking stacks. |
| 259 if (class_id != kWeakPropertyCid) { | 196 VisitingOldObject(raw_obj); |
| 260 marked_bytes_ += raw_obj->VisitPointers(this); | 197 const intptr_t class_id = raw_obj->GetClassId(); |
| 261 } else { | 198 if (class_id != kWeakPropertyCid) { |
| 262 RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj); | 199 marked_bytes_ += raw_obj->VisitPointers(this); |
| 263 marked_bytes_ += raw_weak->Size(); | 200 } else { |
| 264 ProcessWeakProperty(raw_weak); | 201 RawWeakProperty* raw_weak = |
| 202 reinterpret_cast<RawWeakProperty*>(raw_obj); |
| 203 marked_bytes_ += ProcessWeakProperty(raw_weak); |
| 204 } |
| 205 raw_obj = work_list_.Pop(); |
| 206 } while (raw_obj != NULL); |
| 207 |
| 208 // Marking stack is empty. |
| 209 // Process all the pending weak properties in this visitor. |
| 210 RawWeakProperty* cur_weak = delayed_weak_properties_; |
| 211 delayed_weak_properties_ = NULL; |
| 212 while (cur_weak != NULL) { |
| 213 uword next_weak = cur_weak->ptr()->next_; |
| 214 RawObject* raw_key = cur_weak->ptr()->key_; |
| 215 // Reset the next pointer in the weak property. |
| 216 cur_weak->ptr()->next_ = 0; |
| 217 if (raw_key->IsMarked()) { |
| 218 // The key is marked so we make sure to properly visit all pointers |
| 219 // originating from this weak property. |
| 220 VisitingOldObject(cur_weak); |
| 221 cur_weak->VisitPointers(this); |
| 222 } else { |
| 223 // Requeue this weak property to be handled later. |
| 224 EnqueueWeakProperty(cur_weak); |
| 225 } |
| 226 // Advance to next weak property in the queue. |
| 227 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); |
| 265 } | 228 } |
| 229 |
| 230 // Check whether any further work was pushed either by other markers or |
| 231 // by the handling of weak properties. |
| 266 raw_obj = work_list_.Pop(); | 232 raw_obj = work_list_.Pop(); |
| 267 } while (raw_obj != NULL); | 233 } while (raw_obj != NULL); |
| 268 VisitingOldObject(NULL); | 234 VisitingOldObject(NULL); |
| 269 return true; | 235 return true; |
| 270 } | 236 } |
| 271 | 237 |
| 272 void VisitPointers(RawObject** first, RawObject** last) { | 238 void VisitPointers(RawObject** first, RawObject** last) { |
| 273 for (RawObject** current = first; current <= last; current++) { | 239 for (RawObject** current = first; current <= last; current++) { |
| 274 MarkObject(*current, current); | 240 MarkObject(*current, current); |
| 275 } | 241 } |
| 276 } | 242 } |
| 277 | 243 |
| 278 bool visit_function_code() const { | 244 bool visit_function_code() const { |
| 279 return skipped_code_functions_ == NULL; | 245 return skipped_code_functions_ == NULL; |
| 280 } | 246 } |
| 281 | 247 |
| 282 virtual void add_skipped_code_function(RawFunction* func) { | 248 virtual void add_skipped_code_function(RawFunction* func) { |
| 283 ASSERT(!visit_function_code()); | 249 ASSERT(!visit_function_code()); |
| 284 skipped_code_functions_->Add(func); | 250 skipped_code_functions_->Add(func); |
| 285 } | 251 } |
| 286 | 252 |
| 287 // If unmarked, sets the watch bit and returns true. | 253 void EnqueueWeakProperty(RawWeakProperty* raw_weak) { |
| 288 // If marked, does nothing and returns false. | 254 ASSERT(raw_weak->IsHeapObject()); |
| 289 static bool EnsureWatchedIfWhite(RawObject* obj) { | 255 ASSERT(raw_weak->IsOldObject()); |
| 290 if (!sync) { | 256 ASSERT(raw_weak->IsWeakProperty()); |
| 291 if (obj->IsMarked()) return false; | 257 ASSERT(raw_weak->IsMarked()); |
| 292 if (!obj->IsWatched()) obj->SetWatchedBitUnsynchronized(); | 258 ASSERT(raw_weak->ptr()->next_ == 0); |
| 293 return true; | 259 raw_weak->ptr()->next_ = reinterpret_cast<uword>(delayed_weak_properties_); |
| 294 } | 260 delayed_weak_properties_ = raw_weak; |
| 295 uword tags = obj->ptr()->tags_; | |
| 296 uword old_tags; | |
| 297 do { | |
| 298 old_tags = tags; | |
| 299 if (RawObject::MarkBit::decode(tags)) return false; | |
| 300 if (RawObject::WatchedBit::decode(tags)) return true; | |
| 301 uword new_tags = RawObject::WatchedBit::update(true, old_tags); | |
| 302 tags = AtomicOperations::CompareAndSwapWord( | |
| 303 &obj->ptr()->tags_, old_tags, new_tags); | |
| 304 } while (tags != old_tags); | |
| 305 return true; | |
| 306 } | 261 } |
| 307 | 262 |
| 308 void ProcessWeakProperty(RawWeakProperty* raw_weak) { | 263 intptr_t ProcessWeakProperty(RawWeakProperty* raw_weak) { |
| 309 // The fate of the weak property is determined by its key. | 264 // The fate of the weak property is determined by its key. |
| 310 RawObject* raw_key = raw_weak->ptr()->key_; | 265 RawObject* raw_key = raw_weak->ptr()->key_; |
| 311 if (raw_key->IsHeapObject() && | 266 if (raw_key->IsHeapObject() && |
| 312 raw_key->IsOldObject() && | 267 raw_key->IsOldObject() && |
| 313 EnsureWatchedIfWhite(raw_key) && | 268 !raw_key->IsMarked()) { |
| 314 delay_set_->InsertIfWhite(raw_weak)) { | 269 // Key was white. Enqueue the weak property. |
| 315 // Key was white. Delayed the weak property. | 270 EnqueueWeakProperty(raw_weak); |
| 316 } else { | 271 return raw_weak->Size(); |
| 317 // Key is gray or black. Make the weak property black. | |
| 318 raw_weak->VisitPointers(this); | |
| 319 } | 272 } |
| 273 // Key is gray or black. Make the weak property black. |
| 274 return raw_weak->VisitPointers(this); |
| 320 } | 275 } |
| 321 | 276 |
| 322 // Called when all marking is complete. | 277 // Called when all marking is complete. |
| 323 void Finalize() { | 278 void Finalize() { |
| 324 work_list_.Finalize(); | 279 work_list_.Finalize(); |
| 280 // Detach code from functions. |
| 325 if (skipped_code_functions_ != NULL) { | 281 if (skipped_code_functions_ != NULL) { |
| 326 skipped_code_functions_->DetachCode(); | 282 skipped_code_functions_->DetachCode(); |
| 327 } | 283 } |
| 284 // Clear pending weak properties. |
| 285 RawWeakProperty* cur_weak = delayed_weak_properties_; |
| 286 delayed_weak_properties_ = NULL; |
| 287 intptr_t weak_properties_cleared = 0; |
| 288 while (cur_weak != NULL) { |
| 289 uword next_weak = cur_weak->ptr()->next_; |
| 290 cur_weak->ptr()->next_ = 0; |
| 291 WeakProperty::Clear(cur_weak); |
| 292 weak_properties_cleared++; |
| 293 // Advance to next weak property in the queue. |
| 294 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); |
| 295 } |
| 328 } | 296 } |
| 329 | 297 |
| 330 void VisitingOldObject(RawObject* obj) { | 298 void VisitingOldObject(RawObject* obj) { |
| 331 ASSERT((obj == NULL) || obj->IsOldObject()); | 299 ASSERT((obj == NULL) || obj->IsOldObject()); |
| 332 visiting_old_object_ = obj; | 300 visiting_old_object_ = obj; |
| 333 } | 301 } |
| 334 | 302 |
| 335 private: | 303 private: |
| 336 void PushMarked(RawObject* raw_obj) { | 304 void PushMarked(RawObject* raw_obj) { |
| 337 ASSERT(raw_obj->IsHeapObject()); | 305 ASSERT(raw_obj->IsHeapObject()); |
| 338 ASSERT((FLAG_verify_before_gc || FLAG_verify_before_gc) ? | 306 ASSERT((FLAG_verify_before_gc || FLAG_verify_before_gc) ? |
| 339 page_space_->Contains(RawObject::ToAddr(raw_obj)) : | 307 page_space_->Contains(RawObject::ToAddr(raw_obj)) : |
| 340 true); | 308 true); |
| 341 | 309 |
| 342 // Push the marked object on the marking stack. | 310 // Push the marked object on the marking stack. |
| 343 ASSERT(raw_obj->IsMarked()); | 311 ASSERT(raw_obj->IsMarked()); |
| 344 const bool is_watched = raw_obj->IsWatched(); | |
| 345 // We acquired the mark bit => no other task is modifying the header. | 312 // We acquired the mark bit => no other task is modifying the header. |
| 346 // TODO(koda): For concurrent mutator, this needs synchronization. Consider | 313 // TODO(koda): For concurrent mutator, this needs synchronization. Consider |
| 347 // clearing these bits already in the CAS for the mark bit. | 314 // clearing these bits already in the CAS for the mark bit. |
| 348 raw_obj->ClearRememberedBitUnsynchronized(); | 315 raw_obj->ClearRememberedBitUnsynchronized(); |
| 349 raw_obj->ClearWatchedBitUnsynchronized(); | |
| 350 if (is_watched) { | |
| 351 delay_set_->VisitValuesForKey(raw_obj, this); | |
| 352 } | |
| 353 work_list_.Push(raw_obj); | 316 work_list_.Push(raw_obj); |
| 354 } | 317 } |
| 355 | 318 |
| 356 static bool TryAcquireMarkBit(RawObject* raw_obj) { | 319 static bool TryAcquireMarkBit(RawObject* raw_obj) { |
| 357 if (!sync) { | 320 if (!sync) { |
| 358 if (raw_obj->IsMarked()) return false; | 321 if (raw_obj->IsMarked()) return false; |
| 359 raw_obj->SetMarkBitUnsynchronized(); | 322 raw_obj->SetMarkBitUnsynchronized(); |
| 360 return true; | 323 return true; |
| 361 } | 324 } |
| 362 return raw_obj->TryAcquireMarkBit(); | 325 return raw_obj->TryAcquireMarkBit(); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 class_stats_size_[class_id] += size; | 392 class_stats_size_[class_id] += size; |
| 430 } | 393 } |
| 431 | 394 |
| 432 Thread* thread_; | 395 Thread* thread_; |
| 433 Heap* heap_; | 396 Heap* heap_; |
| 434 Heap* vm_heap_; | 397 Heap* vm_heap_; |
| 435 GrowableArray<intptr_t> class_stats_count_; | 398 GrowableArray<intptr_t> class_stats_count_; |
| 436 GrowableArray<intptr_t> class_stats_size_; | 399 GrowableArray<intptr_t> class_stats_size_; |
| 437 PageSpace* page_space_; | 400 PageSpace* page_space_; |
| 438 MarkerWorkList work_list_; | 401 MarkerWorkList work_list_; |
| 439 DelaySet* delay_set_; | 402 RawWeakProperty* delayed_weak_properties_; |
| 440 RawObject* visiting_old_object_; | 403 RawObject* visiting_old_object_; |
| 441 SkippedCodeFunctions* skipped_code_functions_; | 404 SkippedCodeFunctions* skipped_code_functions_; |
| 442 uintptr_t marked_bytes_; | 405 uintptr_t marked_bytes_; |
| 443 | 406 |
| 444 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitorBase); | 407 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitorBase); |
| 445 }; | 408 }; |
| 446 | 409 |
| 447 | 410 |
| 448 typedef MarkingVisitorBase<false> UnsyncMarkingVisitor; | 411 typedef MarkingVisitorBase<false> UnsyncMarkingVisitor; |
| 449 typedef MarkingVisitorBase<true> SyncMarkingVisitor; | 412 typedef MarkingVisitorBase<true> SyncMarkingVisitor; |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 } | 536 } |
| 574 | 537 |
| 575 | 538 |
| 576 class MarkTask : public ThreadPool::Task { | 539 class MarkTask : public ThreadPool::Task { |
| 577 public: | 540 public: |
| 578 MarkTask(GCMarker* marker, | 541 MarkTask(GCMarker* marker, |
| 579 Isolate* isolate, | 542 Isolate* isolate, |
| 580 Heap* heap, | 543 Heap* heap, |
| 581 PageSpace* page_space, | 544 PageSpace* page_space, |
| 582 MarkingStack* marking_stack, | 545 MarkingStack* marking_stack, |
| 583 DelaySet* delay_set, | |
| 584 ThreadBarrier* barrier, | 546 ThreadBarrier* barrier, |
| 585 bool collect_code, | 547 bool collect_code, |
| 586 intptr_t task_index, | 548 intptr_t task_index, |
| 587 intptr_t num_tasks, | 549 intptr_t num_tasks, |
| 588 uintptr_t* num_busy) | 550 uintptr_t* num_busy) |
| 589 : marker_(marker), | 551 : marker_(marker), |
| 590 isolate_(isolate), | 552 isolate_(isolate), |
| 591 heap_(heap), | 553 heap_(heap), |
| 592 page_space_(page_space), | 554 page_space_(page_space), |
| 593 marking_stack_(marking_stack), | 555 marking_stack_(marking_stack), |
| 594 delay_set_(delay_set), | |
| 595 barrier_(barrier), | 556 barrier_(barrier), |
| 596 collect_code_(collect_code), | 557 collect_code_(collect_code), |
| 597 task_index_(task_index), | 558 task_index_(task_index), |
| 598 num_tasks_(num_tasks), | 559 num_tasks_(num_tasks), |
| 599 num_busy_(num_busy) { | 560 num_busy_(num_busy) { |
| 600 } | 561 } |
| 601 | 562 |
| 602 virtual void Run() { | 563 virtual void Run() { |
| 603 bool result = | 564 bool result = |
| 604 Thread::EnterIsolateAsHelper(isolate_, Thread::kMarkerTask, true); | 565 Thread::EnterIsolateAsHelper(isolate_, Thread::kMarkerTask, true); |
| 605 ASSERT(result); | 566 ASSERT(result); |
| 606 { | 567 { |
| 607 Thread* thread = Thread::Current(); | 568 Thread* thread = Thread::Current(); |
| 608 TIMELINE_FUNCTION_GC_DURATION(thread, "MarkTask"); | 569 TIMELINE_FUNCTION_GC_DURATION(thread, "MarkTask"); |
| 609 StackZone stack_zone(thread); | 570 StackZone stack_zone(thread); |
| 610 Zone* zone = stack_zone.GetZone(); | 571 Zone* zone = stack_zone.GetZone(); |
| 611 SkippedCodeFunctions* skipped_code_functions = | 572 SkippedCodeFunctions* skipped_code_functions = |
| 612 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL; | 573 collect_code_ ? new(zone) SkippedCodeFunctions() : NULL; |
| 613 SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_, | 574 SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_, |
| 614 delay_set_, skipped_code_functions); | 575 skipped_code_functions); |
| 615 // Phase 1: Iterate over roots and drain marking stack in tasks. | 576 // Phase 1: Iterate over roots and drain marking stack in tasks. |
| 616 marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_); | 577 marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_); |
| 617 do { | 578 do { |
| 618 visitor.DrainMarkingStack(); | 579 visitor.DrainMarkingStack(); |
| 619 | 580 |
| 620 // I can't find more work right now. If no other task is busy, | 581 // I can't find more work right now. If no other task is busy, |
| 621 // then there will never be more work (NB: 1 is *before* decrement). | 582 // then there will never be more work (NB: 1 is *before* decrement). |
| 622 if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break; | 583 if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break; |
| 623 | 584 |
| 624 // Wait for some work to appear. | 585 // Wait for some work to appear. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 652 // This task is done. Notify the original thread. | 613 // This task is done. Notify the original thread. |
| 653 barrier_->Exit(); | 614 barrier_->Exit(); |
| 654 } | 615 } |
| 655 | 616 |
| 656 private: | 617 private: |
| 657 GCMarker* marker_; | 618 GCMarker* marker_; |
| 658 Isolate* isolate_; | 619 Isolate* isolate_; |
| 659 Heap* heap_; | 620 Heap* heap_; |
| 660 PageSpace* page_space_; | 621 PageSpace* page_space_; |
| 661 MarkingStack* marking_stack_; | 622 MarkingStack* marking_stack_; |
| 662 DelaySet* delay_set_; | |
| 663 ThreadBarrier* barrier_; | 623 ThreadBarrier* barrier_; |
| 664 bool collect_code_; | 624 bool collect_code_; |
| 665 const intptr_t task_index_; | 625 const intptr_t task_index_; |
| 666 const intptr_t num_tasks_; | 626 const intptr_t num_tasks_; |
| 667 uintptr_t* num_busy_; | 627 uintptr_t* num_busy_; |
| 668 | 628 |
| 669 DISALLOW_COPY_AND_ASSIGN(MarkTask); | 629 DISALLOW_COPY_AND_ASSIGN(MarkTask); |
| 670 }; | 630 }; |
| 671 | 631 |
| 672 | 632 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 694 PageSpace* page_space, | 654 PageSpace* page_space, |
| 695 bool invoke_api_callbacks, | 655 bool invoke_api_callbacks, |
| 696 bool collect_code) { | 656 bool collect_code) { |
| 697 Prologue(isolate, invoke_api_callbacks); | 657 Prologue(isolate, invoke_api_callbacks); |
| 698 // The API prologue/epilogue may create/destroy zones, so we must not | 658 // The API prologue/epilogue may create/destroy zones, so we must not |
| 699 // depend on zone allocations surviving beyond the epilogue callback. | 659 // depend on zone allocations surviving beyond the epilogue callback. |
| 700 { | 660 { |
| 701 StackZone stack_zone(Thread::Current()); | 661 StackZone stack_zone(Thread::Current()); |
| 702 Zone* zone = stack_zone.GetZone(); | 662 Zone* zone = stack_zone.GetZone(); |
| 703 MarkingStack marking_stack; | 663 MarkingStack marking_stack; |
| 704 DelaySet delay_set; | |
| 705 marked_bytes_ = 0; | 664 marked_bytes_ = 0; |
| 706 const int num_tasks = FLAG_marker_tasks; | 665 const int num_tasks = FLAG_marker_tasks; |
| 707 if (num_tasks == 0) { | 666 if (num_tasks == 0) { |
| 708 // Mark everything on main thread. | 667 // Mark everything on main thread. |
| 709 SkippedCodeFunctions* skipped_code_functions = | 668 SkippedCodeFunctions* skipped_code_functions = |
| 710 collect_code ? new(zone) SkippedCodeFunctions() : NULL; | 669 collect_code ? new(zone) SkippedCodeFunctions() : NULL; |
| 711 UnsyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack, | 670 UnsyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack, |
| 712 &delay_set, skipped_code_functions); | 671 skipped_code_functions); |
| 713 IterateRoots(isolate, &mark, 0, 1); | 672 IterateRoots(isolate, &mark, 0, 1); |
| 714 mark.DrainMarkingStack(); | 673 mark.DrainMarkingStack(); |
| 715 MarkingWeakVisitor mark_weak; | 674 MarkingWeakVisitor mark_weak; |
| 716 IterateWeakRoots(isolate, &mark_weak); | 675 IterateWeakRoots(isolate, &mark_weak); |
| 717 // All marking done; detach code, etc. | 676 // All marking done; detach code, etc. |
| 718 FinalizeResultsFrom(&mark); | 677 FinalizeResultsFrom(&mark); |
| 719 } else { | 678 } else { |
| 720 ThreadBarrier barrier(num_tasks + 1, | 679 ThreadBarrier barrier(num_tasks + 1, |
| 721 heap_->barrier(), | 680 heap_->barrier(), |
| 722 heap_->barrier_done()); | 681 heap_->barrier_done()); |
| 723 // Used to coordinate draining among tasks; all start out as 'busy'. | 682 // Used to coordinate draining among tasks; all start out as 'busy'. |
| 724 uintptr_t num_busy = num_tasks; | 683 uintptr_t num_busy = num_tasks; |
| 725 // Phase 1: Iterate over roots and drain marking stack in tasks. | 684 // Phase 1: Iterate over roots and drain marking stack in tasks. |
| 726 for (intptr_t i = 0; i < num_tasks; ++i) { | 685 for (intptr_t i = 0; i < num_tasks; ++i) { |
| 727 MarkTask* mark_task = | 686 MarkTask* mark_task = |
| 728 new MarkTask(this, isolate, heap_, page_space, &marking_stack, | 687 new MarkTask(this, isolate, heap_, page_space, &marking_stack, |
| 729 &delay_set, &barrier, collect_code, | 688 &barrier, collect_code, |
| 730 i, num_tasks, &num_busy); | 689 i, num_tasks, &num_busy); |
| 731 ThreadPool* pool = Dart::thread_pool(); | 690 ThreadPool* pool = Dart::thread_pool(); |
| 732 pool->Run(mark_task); | 691 pool->Run(mark_task); |
| 733 } | 692 } |
| 734 barrier.Sync(); | 693 barrier.Sync(); |
| 735 | 694 |
| 736 // Phase 2: Weak processing and follow-up marking on main thread. | 695 // Phase 2: Weak processing on main thread. |
| 737 SkippedCodeFunctions* skipped_code_functions = | |
| 738 collect_code ? new(zone) SkippedCodeFunctions() : NULL; | |
| 739 SyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack, | |
| 740 &delay_set, skipped_code_functions); | |
| 741 MarkingWeakVisitor mark_weak; | 696 MarkingWeakVisitor mark_weak; |
| 742 IterateWeakRoots(isolate, &mark_weak); | 697 IterateWeakRoots(isolate, &mark_weak); |
| 743 barrier.Sync(); | 698 barrier.Sync(); |
| 744 | 699 |
| 745 // Phase 3: Finalize results from all markers (detach code, etc.). | 700 // Phase 3: Finalize results from all markers (detach code, etc.). |
| 746 if (FLAG_log_marker_tasks) { | |
| 747 THR_Print("Main thread marked %" Pd " bytes.\n", | |
| 748 mark.marked_bytes()); | |
| 749 } | |
| 750 FinalizeResultsFrom(&mark); | |
| 751 barrier.Exit(); | 701 barrier.Exit(); |
| 752 } | 702 } |
| 753 delay_set.ClearReferences(); | |
| 754 ProcessWeakTables(page_space); | 703 ProcessWeakTables(page_space); |
| 755 ProcessObjectIdTable(isolate); | 704 ProcessObjectIdTable(isolate); |
| 756 } | 705 } |
| 757 Epilogue(isolate, invoke_api_callbacks); | 706 Epilogue(isolate, invoke_api_callbacks); |
| 758 } | 707 } |
| 759 | 708 |
| 760 } // namespace dart | 709 } // namespace dart |
| OLD | NEW |