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 "vm/allocation.h" | 7 #include "vm/allocation.h" |
| 8 #include "vm/dart_api_state.h" | 8 #include "vm/dart_api_state.h" |
| 9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
| 10 #include "vm/log.h" | 10 #include "vm/log.h" |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 184 uword next_weak = cur_weak->ptr()->next_; | 184 uword next_weak = cur_weak->ptr()->next_; |
| 185 RawObject* raw_key = cur_weak->ptr()->key_; | 185 RawObject* raw_key = cur_weak->ptr()->key_; |
| 186 // Reset the next pointer in the weak property. | 186 // Reset the next pointer in the weak property. |
| 187 cur_weak->ptr()->next_ = 0; | 187 cur_weak->ptr()->next_ = 0; |
| 188 if (raw_key->IsMarked()) { | 188 if (raw_key->IsMarked()) { |
| 189 RawObject* raw_val = cur_weak->ptr()->value_; | 189 RawObject* raw_val = cur_weak->ptr()->value_; |
| 190 marked = marked || (raw_val->IsHeapObject() && !raw_val->IsMarked()); | 190 marked = marked || (raw_val->IsHeapObject() && !raw_val->IsMarked()); |
| 191 | 191 |
| 192 // The key is marked so we make sure to properly visit all pointers | 192 // The key is marked so we make sure to properly visit all pointers |
| 193 // originating from this weak property. | 193 // originating from this weak property. |
| 194 VisitingOldObject(cur_weak); | 194 if (cur_weak->IsOldObject()) { |
| 195 VisitingOldObject(cur_weak); | |
| 196 } else { | |
| 197 VisitingOldObject(NULL); | |
| 198 } | |
| 195 cur_weak->VisitPointersNonvirtual(this); | 199 cur_weak->VisitPointersNonvirtual(this); |
| 196 } else { | 200 } else { |
| 197 // Requeue this weak property to be handled later. | 201 // Requeue this weak property to be handled later. |
| 198 EnqueueWeakProperty(cur_weak); | 202 EnqueueWeakProperty(cur_weak); |
| 199 } | 203 } |
| 200 // Advance to next weak property in the queue. | 204 // Advance to next weak property in the queue. |
| 201 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); | 205 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); |
| 202 } | 206 } |
| 203 VisitingOldObject(NULL); | 207 VisitingOldObject(NULL); |
| 204 return marked; | 208 return marked; |
| 205 } | 209 } |
| 206 | 210 |
| 207 void DrainMarkingStack() { | 211 void DrainMarkingStack() { |
| 208 RawObject* raw_obj = work_list_.Pop(); | 212 RawObject* raw_obj = work_list_.Pop(); |
| 209 if ((raw_obj == NULL) && ProcessPendingWeakProperties()) { | 213 if ((raw_obj == NULL) && ProcessPendingWeakProperties()) { |
| 210 raw_obj = work_list_.Pop(); | 214 raw_obj = work_list_.Pop(); |
| 211 } | 215 } |
| 212 | 216 |
| 213 if (raw_obj == NULL) { | 217 if (raw_obj == NULL) { |
| 214 ASSERT(visiting_old_object_ == NULL); | 218 ASSERT(visiting_old_object_ == NULL); |
| 215 return; | 219 return; |
| 216 } | 220 } |
| 217 do { | 221 do { |
| 218 do { | 222 do { |
| 219 // First drain the marking stacks. | 223 // First drain the marking stacks. |
| 220 VisitingOldObject(raw_obj); | 224 if (raw_obj->IsOldObject()) { |
| 225 VisitingOldObject(raw_obj); | |
| 226 } else { | |
| 227 VisitingOldObject(NULL); | |
| 228 } | |
| 229 | |
| 221 const intptr_t class_id = raw_obj->GetClassId(); | 230 const intptr_t class_id = raw_obj->GetClassId(); |
| 222 if (class_id != kWeakPropertyCid) { | 231 if (class_id != kWeakPropertyCid) { |
| 223 marked_bytes_ += raw_obj->VisitPointersNonvirtual(this); | 232 marked_bytes_ += raw_obj->VisitPointersNonvirtual(this); |
| 224 } else { | 233 } else { |
| 225 RawWeakProperty* raw_weak = | 234 RawWeakProperty* raw_weak = |
| 226 reinterpret_cast<RawWeakProperty*>(raw_obj); | 235 reinterpret_cast<RawWeakProperty*>(raw_obj); |
| 227 marked_bytes_ += ProcessWeakProperty(raw_weak); | 236 marked_bytes_ += ProcessWeakProperty(raw_weak); |
| 228 } | 237 } |
| 229 raw_obj = work_list_.Pop(); | 238 raw_obj = work_list_.Pop(); |
| 230 } while (raw_obj != NULL); | 239 } while (raw_obj != NULL); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 247 | 256 |
| 248 bool visit_function_code() const { return skipped_code_functions_ == NULL; } | 257 bool visit_function_code() const { return skipped_code_functions_ == NULL; } |
| 249 | 258 |
| 250 virtual void add_skipped_code_function(RawFunction* func) { | 259 virtual void add_skipped_code_function(RawFunction* func) { |
| 251 ASSERT(!visit_function_code()); | 260 ASSERT(!visit_function_code()); |
| 252 skipped_code_functions_->Add(func); | 261 skipped_code_functions_->Add(func); |
| 253 } | 262 } |
| 254 | 263 |
| 255 void EnqueueWeakProperty(RawWeakProperty* raw_weak) { | 264 void EnqueueWeakProperty(RawWeakProperty* raw_weak) { |
| 256 ASSERT(raw_weak->IsHeapObject()); | 265 ASSERT(raw_weak->IsHeapObject()); |
| 257 ASSERT(raw_weak->IsOldObject()); | 266 ASSERT(raw_weak->IsOldObject()); |
|
rmacnak
2017/06/08 21:23:48
Update (visiting new-space weak properties now).
| |
| 258 ASSERT(raw_weak->IsWeakProperty()); | 267 ASSERT(raw_weak->IsWeakProperty()); |
| 259 ASSERT(raw_weak->IsMarked()); | 268 ASSERT(raw_weak->IsMarked()); |
| 260 ASSERT(raw_weak->ptr()->next_ == 0); | 269 ASSERT(raw_weak->ptr()->next_ == 0); |
| 261 raw_weak->ptr()->next_ = reinterpret_cast<uword>(delayed_weak_properties_); | 270 raw_weak->ptr()->next_ = reinterpret_cast<uword>(delayed_weak_properties_); |
| 262 delayed_weak_properties_ = raw_weak; | 271 delayed_weak_properties_ = raw_weak; |
| 263 } | 272 } |
| 264 | 273 |
| 265 intptr_t ProcessWeakProperty(RawWeakProperty* raw_weak) { | 274 intptr_t ProcessWeakProperty(RawWeakProperty* raw_weak) { |
| 266 // The fate of the weak property is determined by its key. | 275 // The fate of the weak property is determined by its key. |
| 267 RawObject* raw_key = raw_weak->ptr()->key_; | 276 RawObject* raw_key = raw_weak->ptr()->key_; |
| 268 if (raw_key->IsHeapObject() && raw_key->IsOldObject() && | 277 if (raw_key->IsHeapObject() && raw_key->IsOldObject() && |
|
rmacnak
2017/06/08 21:23:48
Update (not all new-space objects are survivors)
| |
| 269 !raw_key->IsMarked()) { | 278 !raw_key->IsMarked()) { |
| 270 // Key was white. Enqueue the weak property. | 279 // Key was white. Enqueue the weak property. |
| 271 EnqueueWeakProperty(raw_weak); | 280 EnqueueWeakProperty(raw_weak); |
| 272 return raw_weak->Size(); | 281 return raw_weak->Size(); |
| 273 } | 282 } |
| 274 // Key is gray or black. Make the weak property black. | 283 // Key is gray or black. Make the weak property black. |
| 275 return raw_weak->VisitPointersNonvirtual(this); | 284 return raw_weak->VisitPointersNonvirtual(this); |
| 276 } | 285 } |
| 277 | 286 |
| 278 // Called when all marking is complete. | 287 // Called when all marking is complete. |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 299 | 308 |
| 300 void VisitingOldObject(RawObject* obj) { | 309 void VisitingOldObject(RawObject* obj) { |
| 301 ASSERT((obj == NULL) || obj->IsOldObject()); | 310 ASSERT((obj == NULL) || obj->IsOldObject()); |
| 302 visiting_old_object_ = obj; | 311 visiting_old_object_ = obj; |
| 303 } | 312 } |
| 304 | 313 |
| 305 private: | 314 private: |
| 306 void PushMarked(RawObject* raw_obj) { | 315 void PushMarked(RawObject* raw_obj) { |
| 307 ASSERT(raw_obj->IsHeapObject()); | 316 ASSERT(raw_obj->IsHeapObject()); |
| 308 ASSERT((FLAG_verify_gc_contains) | 317 ASSERT((FLAG_verify_gc_contains) |
| 309 ? page_space_->Contains(RawObject::ToAddr(raw_obj)) | 318 ? ((page_space_->Contains(RawObject::ToAddr(raw_obj))) || |
| 319 (heap_->new_space()->Contains(RawObject::ToAddr(raw_obj)))) | |
| 310 : true); | 320 : true); |
| 311 | 321 |
| 312 // Push the marked object on the marking stack. | 322 // Push the marked object on the marking stack. |
| 313 ASSERT(raw_obj->IsMarked()); | 323 ASSERT(raw_obj->IsMarked()); |
| 314 // We acquired the mark bit => no other task is modifying the header. | 324 // We acquired the mark bit => no other task is modifying the header. |
| 315 // TODO(koda): For concurrent mutator, this needs synchronization. Consider | 325 // TODO(koda): For concurrent mutator, this needs synchronization. Consider |
| 316 // clearing these bits already in the CAS for the mark bit. | 326 // clearing these bits already in the CAS for the mark bit. |
| 317 raw_obj->ClearRememberedBitUnsynchronized(); | 327 raw_obj->ClearRememberedBitUnsynchronized(); |
| 318 work_list_.Push(raw_obj); | 328 work_list_.Push(raw_obj); |
| 319 } | 329 } |
| 320 | 330 |
| 321 static bool TryAcquireMarkBit(RawObject* raw_obj) { | 331 static bool TryAcquireMarkBit(RawObject* raw_obj) { |
| 322 if (!sync) { | 332 if (!sync) { |
| 323 if (raw_obj->IsMarked()) return false; | 333 if (raw_obj->IsMarked()) return false; |
| 324 raw_obj->SetMarkBitUnsynchronized(); | 334 raw_obj->SetMarkBitUnsynchronized(); |
| 325 return true; | 335 return true; |
| 326 } | 336 } |
| 327 return raw_obj->TryAcquireMarkBit(); | 337 return raw_obj->TryAcquireMarkBit(); |
| 328 } | 338 } |
| 329 | 339 |
| 330 void MarkObject(RawObject* raw_obj, RawObject** p) { | 340 void MarkObject(RawObject* raw_obj, RawObject** p) { |
| 331 // Fast exit if the raw object is a Smi. | 341 // Fast exit if the raw object is a Smi. |
| 332 if (!raw_obj->IsHeapObject()) { | 342 if (!raw_obj->IsHeapObject()) { |
| 333 return; | 343 return; |
| 334 } | 344 } |
| 335 | 345 |
| 336 // Fast exit if the raw object is marked. | 346 // Fast exit if the raw object is marked. |
| 337 if (raw_obj->IsMarked()) { | 347 if (raw_obj->IsMarked()) { |
| 348 if (raw_obj->IsNewObject()) { | |
| 349 ProcessNewSpaceObject(raw_obj, p); | |
| 350 } | |
| 338 return; | 351 return; |
| 339 } | 352 } |
| 340 | 353 |
| 341 // TODO(koda): Investigate performance impact of alternative branching: | 354 // TODO(koda): Investigate performance impact of alternative branching: |
| 342 // if (smi or new) <-- can be done as single compare + conditional jump | 355 // if (smi or new) <-- can be done as single compare + conditional jump |
| 343 // if (smi) return; | 356 // if (smi) return; |
| 344 // else ... | 357 // else ... |
| 345 // if (marked) return; | 358 // if (marked) return; |
| 346 // ... | 359 // ... |
| 347 if (raw_obj->IsNewObject()) { | 360 if (raw_obj->IsNewObject()) { |
| 348 ProcessNewSpaceObject(raw_obj, p); | 361 ProcessNewSpaceObject(raw_obj, p); |
| 349 return; | |
| 350 } | 362 } |
| 351 | 363 |
| 352 if (!TryAcquireMarkBit(raw_obj)) { | 364 if (!TryAcquireMarkBit(raw_obj)) { |
| 353 // Already marked. | 365 // Already marked. |
| 354 return; | 366 return; |
| 355 } | 367 } |
| 356 if (RawObject::IsVariableSizeClassId(raw_obj->GetClassId())) { | 368 if (RawObject::IsVariableSizeClassId(raw_obj->GetClassId())) { |
| 357 UpdateLiveOld(raw_obj->GetClassId(), raw_obj->Size()); | 369 UpdateLiveOld(raw_obj->GetClassId(), raw_obj->Size()); |
| 358 } else { | 370 } else { |
| 359 UpdateLiveOld(raw_obj->GetClassId(), 0); | 371 UpdateLiveOld(raw_obj->GetClassId(), 0); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 414 typedef MarkingVisitorBase<true> SyncMarkingVisitor; | 426 typedef MarkingVisitorBase<true> SyncMarkingVisitor; |
| 415 | 427 |
| 416 | 428 |
| 417 static bool IsUnreachable(const RawObject* raw_obj) { | 429 static bool IsUnreachable(const RawObject* raw_obj) { |
| 418 if (!raw_obj->IsHeapObject()) { | 430 if (!raw_obj->IsHeapObject()) { |
| 419 return false; | 431 return false; |
| 420 } | 432 } |
| 421 if (raw_obj == Object::null()) { | 433 if (raw_obj == Object::null()) { |
| 422 return true; | 434 return true; |
| 423 } | 435 } |
| 424 if (!raw_obj->IsOldObject()) { | 436 if (!raw_obj->IsOldObject()) { |
|
rmacnak
2017/06/08 21:23:48
Update (not all new-space objects are survivors)
| |
| 425 return false; | 437 return false; |
| 426 } | 438 } |
| 427 return !raw_obj->IsMarked(); | 439 return !raw_obj->IsMarked(); |
| 428 } | 440 } |
| 429 | 441 |
| 430 | 442 |
| 431 class MarkingWeakVisitor : public HandleVisitor { | 443 class MarkingWeakVisitor : public HandleVisitor { |
| 432 public: | 444 public: |
| 433 explicit MarkingWeakVisitor(Thread* thread) : HandleVisitor(thread) {} | 445 explicit MarkingWeakVisitor(Thread* thread) : HandleVisitor(thread) {} |
| 434 | 446 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 465 | 477 |
| 466 void GCMarker::IterateRoots(Isolate* isolate, | 478 void GCMarker::IterateRoots(Isolate* isolate, |
| 467 ObjectPointerVisitor* visitor, | 479 ObjectPointerVisitor* visitor, |
| 468 intptr_t slice_index, | 480 intptr_t slice_index, |
| 469 intptr_t num_slices) { | 481 intptr_t num_slices) { |
| 470 ASSERT(0 <= slice_index && slice_index < num_slices); | 482 ASSERT(0 <= slice_index && slice_index < num_slices); |
| 471 if ((slice_index == 0) || (num_slices <= 1)) { | 483 if ((slice_index == 0) || (num_slices <= 1)) { |
| 472 isolate->VisitObjectPointers(visitor, | 484 isolate->VisitObjectPointers(visitor, |
| 473 StackFrameIterator::kDontValidateFrames); | 485 StackFrameIterator::kDontValidateFrames); |
| 474 } | 486 } |
| 475 if ((slice_index == 1) || (num_slices <= 1)) { | |
| 476 heap_->new_space()->VisitObjectPointers(visitor); | |
| 477 } | |
| 478 | 487 |
| 479 // For now, we just distinguish two parts of the root set, so any remaining | 488 // For now, we just distinguish two parts of the root set, so any remaining |
| 480 // slices are empty. | 489 // slices are empty. |
| 481 } | 490 } |
| 482 | 491 |
| 483 | 492 |
| 484 void GCMarker::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) { | 493 void GCMarker::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) { |
| 485 ApiState* state = isolate->api_state(); | 494 ApiState* state = isolate->api_state(); |
| 486 ASSERT(state != NULL); | 495 ASSERT(state != NULL); |
| 487 isolate->VisitWeakPersistentHandles(visitor); | 496 isolate->VisitWeakPersistentHandles(visitor); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 509 class ObjectIdRingClearPointerVisitor : public ObjectPointerVisitor { | 518 class ObjectIdRingClearPointerVisitor : public ObjectPointerVisitor { |
| 510 public: | 519 public: |
| 511 explicit ObjectIdRingClearPointerVisitor(Isolate* isolate) | 520 explicit ObjectIdRingClearPointerVisitor(Isolate* isolate) |
| 512 : ObjectPointerVisitor(isolate) {} | 521 : ObjectPointerVisitor(isolate) {} |
| 513 | 522 |
| 514 | 523 |
| 515 void VisitPointers(RawObject** first, RawObject** last) { | 524 void VisitPointers(RawObject** first, RawObject** last) { |
| 516 for (RawObject** current = first; current <= last; current++) { | 525 for (RawObject** current = first; current <= last; current++) { |
| 517 RawObject* raw_obj = *current; | 526 RawObject* raw_obj = *current; |
| 518 ASSERT(raw_obj->IsHeapObject()); | 527 ASSERT(raw_obj->IsHeapObject()); |
| 519 if (raw_obj->IsOldObject() && !raw_obj->IsMarked()) { | 528 if (raw_obj->IsOldObject() && !raw_obj->IsMarked()) { |
|
rmacnak
2017/06/08 21:23:48
Update (not all new-space objects are survivors)
| |
| 520 // Object has become garbage. Replace it will null. | 529 // Object has become garbage. Replace it will null. |
| 521 *current = Object::null(); | 530 *current = Object::null(); |
| 522 } | 531 } |
| 523 } | 532 } |
| 524 } | 533 } |
| 525 }; | 534 }; |
| 526 | 535 |
| 527 | 536 |
| 528 void GCMarker::ProcessObjectIdTable(Isolate* isolate) { | 537 void GCMarker::ProcessObjectIdTable(Isolate* isolate) { |
| 529 #ifndef PRODUCT | 538 #ifndef PRODUCT |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 758 // Phase 3: Finalize results from all markers (detach code, etc.). | 767 // Phase 3: Finalize results from all markers (detach code, etc.). |
| 759 barrier.Exit(); | 768 barrier.Exit(); |
| 760 } | 769 } |
| 761 ProcessWeakTables(page_space); | 770 ProcessWeakTables(page_space); |
| 762 ProcessObjectIdTable(isolate); | 771 ProcessObjectIdTable(isolate); |
| 763 } | 772 } |
| 764 Epilogue(isolate, invoke_api_callbacks); | 773 Epilogue(isolate, invoke_api_callbacks); |
| 765 } | 774 } |
| 766 | 775 |
| 767 } // namespace dart | 776 } // namespace dart |
| OLD | NEW |