| 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/scavenger.h" | 5 #include "vm/scavenger.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 } | 43 } |
| 44 | 44 |
| 45 | 45 |
| 46 static inline void ForwardTo(uword orignal, uword target) { | 46 static inline void ForwardTo(uword orignal, uword target) { |
| 47 // Make sure forwarding can be encoded. | 47 // Make sure forwarding can be encoded. |
| 48 ASSERT((target & kForwardingMask) == 0); | 48 ASSERT((target & kForwardingMask) == 0); |
| 49 *reinterpret_cast<uword*>(orignal) = target | kForwarded; | 49 *reinterpret_cast<uword*>(orignal) = target | kForwarded; |
| 50 } | 50 } |
| 51 | 51 |
| 52 | 52 |
| 53 class BoolScope : public ValueObject { |
| 54 public: |
| 55 BoolScope(bool* addr, bool value) : _addr(addr), _value(*addr) { |
| 56 *_addr = value; |
| 57 } |
| 58 ~BoolScope() { |
| 59 *_addr = _value; |
| 60 } |
| 61 |
| 62 private: |
| 63 bool* _addr; |
| 64 bool _value; |
| 65 }; |
| 66 |
| 67 |
| 53 class ScavengerVisitor : public ObjectPointerVisitor { | 68 class ScavengerVisitor : public ObjectPointerVisitor { |
| 54 public: | 69 public: |
| 55 explicit ScavengerVisitor(Isolate* isolate, Scavenger* scavenger) | 70 explicit ScavengerVisitor(Isolate* isolate, Scavenger* scavenger) |
| 56 : ObjectPointerVisitor(isolate), | 71 : ObjectPointerVisitor(isolate), |
| 57 scavenger_(scavenger), | 72 scavenger_(scavenger), |
| 58 heap_(scavenger->heap_), | 73 heap_(scavenger->heap_), |
| 59 vm_heap_(Dart::vm_isolate()->heap()), | 74 vm_heap_(Dart::vm_isolate()->heap()), |
| 60 visiting_old_pointers_(false) {} | 75 delayed_weak_stack_(), |
| 76 visiting_old_pointers_(false), |
| 77 in_scavenge_pointer_(false) {} |
| 61 | 78 |
| 62 void VisitPointers(RawObject** first, RawObject** last) { | 79 void VisitPointers(RawObject** first, RawObject** last) { |
| 63 for (RawObject** current = first; current <= last; current++) { | 80 for (RawObject** current = first; current <= last; current++) { |
| 64 ScavengePointer(current); | 81 ScavengePointer(current); |
| 65 } | 82 } |
| 66 } | 83 } |
| 67 | 84 |
| 68 void VisitingOldPointers(bool value) { visiting_old_pointers_ = value; } | 85 GrowableArray<RawObject*>* DelayedWeakStack() { |
| 86 return &delayed_weak_stack_; |
| 87 } |
| 88 |
| 89 bool* VisitingOldPointersAddr() { return &visiting_old_pointers_; } |
| 69 | 90 |
| 70 void DelayWeakProperty(RawWeakProperty* raw_weak) { | 91 void DelayWeakProperty(RawWeakProperty* raw_weak) { |
| 71 RawObject* raw_key = raw_weak->ptr()->key_; | 92 RawObject* raw_key = raw_weak->ptr()->key_; |
| 72 DelaySet::iterator it = delay_set_.find(raw_key); | 93 DelaySet::iterator it = delay_set_.find(raw_key); |
| 73 if (it != delay_set_.end()) { | 94 if (it != delay_set_.end()) { |
| 74 ASSERT(raw_key->IsWatched()); | 95 ASSERT(raw_key->IsWatched()); |
| 75 } else { | 96 } else { |
| 76 ASSERT(!raw_key->IsWatched()); | 97 ASSERT(!raw_key->IsWatched()); |
| 77 raw_key->SetWatchedBit(); | 98 raw_key->SetWatchedBit(); |
| 78 } | 99 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 92 ASSERT(obj->IsHeapObject()); | 113 ASSERT(obj->IsHeapObject()); |
| 93 ASSERT(!scavenger_->Contains(ptr)); | 114 ASSERT(!scavenger_->Contains(ptr)); |
| 94 ASSERT(!heap_->CodeContains(ptr)); | 115 ASSERT(!heap_->CodeContains(ptr)); |
| 95 ASSERT(heap_->Contains(ptr)); | 116 ASSERT(heap_->Contains(ptr)); |
| 96 // If the newly written object is not a new object, drop it immediately. | 117 // If the newly written object is not a new object, drop it immediately. |
| 97 if (!obj->IsNewObject()) return; | 118 if (!obj->IsNewObject()) return; |
| 98 isolate()->store_buffer()->AddPointer(ptr); | 119 isolate()->store_buffer()->AddPointer(ptr); |
| 99 } | 120 } |
| 100 | 121 |
| 101 void ScavengePointer(RawObject** p) { | 122 void ScavengePointer(RawObject** p) { |
| 123 // ScavengePointer cannot be called recursively. |
| 124 ASSERT(!in_scavenge_pointer_); |
| 125 BoolScope bs(&in_scavenge_pointer_, true); |
| 126 |
| 102 RawObject* raw_obj = *p; | 127 RawObject* raw_obj = *p; |
| 103 | 128 |
| 104 // Fast exit if the raw object is a Smi or an old object. | 129 // Fast exit if the raw object is a Smi or an old object. |
| 105 if (!raw_obj->IsHeapObject() || raw_obj->IsOldObject()) { | 130 if (!raw_obj->IsHeapObject() || raw_obj->IsOldObject()) { |
| 106 return; | 131 return; |
| 107 } | 132 } |
| 108 | 133 |
| 109 uword raw_addr = RawObject::ToAddr(raw_obj); | 134 uword raw_addr = RawObject::ToAddr(raw_obj); |
| 110 // Objects should be contained in the heap. | 135 // Objects should be contained in the heap. |
| 111 // TODO(iposva): Add an appropriate assert here or in the return block | 136 // TODO(iposva): Add an appropriate assert here or in the return block |
| 112 // below. | 137 // below. |
| 113 // The scavenger is only interested in objects located in the from space. | 138 // The scavenger is only interested in objects located in the from space. |
| 114 if (!scavenger_->from_->Contains(raw_addr)) { | 139 if (!scavenger_->from_->Contains(raw_addr)) { |
| 115 return; | 140 return; |
| 116 } | 141 } |
| 117 | 142 |
| 118 // Read the header word of the object and determine if the object has | 143 // Read the header word of the object and determine if the object has |
| 119 // already been copied. | 144 // already been copied. |
| 120 uword header = *reinterpret_cast<uword*>(raw_addr); | 145 uword header = *reinterpret_cast<uword*>(raw_addr); |
| 121 uword new_addr = 0; | 146 uword new_addr = 0; |
| 122 if (IsForwarding(header)) { | 147 if (IsForwarding(header)) { |
| 123 // Get the new location of the object. | 148 // Get the new location of the object. |
| 124 new_addr = ForwardedAddr(header); | 149 new_addr = ForwardedAddr(header); |
| 125 } else if (raw_obj->IsWatched()) { | 150 } else { |
| 126 // Forward the object by scavenging its watchers. | 151 if (raw_obj->IsWatched()) { |
| 127 raw_obj->ClearWatchedBit(); | 152 raw_obj->ClearWatchedBit(); |
| 128 std::pair<DelaySet::iterator, DelaySet::iterator> ret; | 153 std::pair<DelaySet::iterator, DelaySet::iterator> ret; |
| 129 // Visit all elements with a key equal to raw_obj. | 154 // Visit all elements with a key equal to this raw_obj. |
| 130 ret = delay_set_.equal_range(raw_obj); | 155 ret = delay_set_.equal_range(raw_obj); |
| 131 for (DelaySet::iterator it = ret.first; it != ret.second; ++it) { | 156 for (DelaySet::iterator it = ret.first; it != ret.second; ++it) { |
| 132 // Scavenge the delayed WeakProperty. These objects have been | 157 // Remember the delayed WeakProperty. These objects have been |
| 133 // forwarded but have not been scavenged because their key | 158 // forwarded, but have not been scavenged because their key was not |
| 134 // object was not known to be reachable. Now that the key | 159 // known to be reachable. Now that the key object is known to be |
| 135 // object is known to be reachable we can scavenge the key and | 160 // reachable, we need to visit its key and value pointers. |
| 136 // value pointers. | 161 delayed_weak_stack_.Add(it->second); |
| 137 it->second->VisitPointers(this); | 162 } |
| 163 delay_set_.erase(ret.first, ret.second); |
| 138 } | 164 } |
| 139 delay_set_.erase(ret.first, ret.second); | |
| 140 // Reread the header word to get the new location of the object. | |
| 141 header = *reinterpret_cast<uword*>(raw_addr); | |
| 142 ASSERT(IsForwarding(header)); | |
| 143 new_addr = ForwardedAddr(header); | |
| 144 } else { | |
| 145 intptr_t size = raw_obj->Size(); | 165 intptr_t size = raw_obj->Size(); |
| 146 // Check whether object should be promoted. | 166 // Check whether object should be promoted. |
| 147 if (scavenger_->survivor_end_ <= raw_addr) { | 167 if (scavenger_->survivor_end_ <= raw_addr) { |
| 148 // Not a survivor of a previous scavenge. Just copy the object into the | 168 // Not a survivor of a previous scavenge. Just copy the object into the |
| 149 // to space. | 169 // to space. |
| 150 new_addr = scavenger_->TryAllocate(size); | 170 new_addr = scavenger_->TryAllocate(size); |
| 151 } else { | 171 } else { |
| 152 // TODO(iposva): Experiment with less aggressive promotion. For example | 172 // TODO(iposva): Experiment with less aggressive promotion. For example |
| 153 // a coin toss determines if an object is promoted or whether it should | 173 // a coin toss determines if an object is promoted or whether it should |
| 154 // survive in this generation. | 174 // survive in this generation. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 183 if (visiting_old_pointers_) { | 203 if (visiting_old_pointers_) { |
| 184 UpdateStoreBuffer(p, new_obj); | 204 UpdateStoreBuffer(p, new_obj); |
| 185 } | 205 } |
| 186 } | 206 } |
| 187 | 207 |
| 188 Scavenger* scavenger_; | 208 Scavenger* scavenger_; |
| 189 Heap* heap_; | 209 Heap* heap_; |
| 190 Heap* vm_heap_; | 210 Heap* vm_heap_; |
| 191 typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet; | 211 typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet; |
| 192 DelaySet delay_set_; | 212 DelaySet delay_set_; |
| 213 GrowableArray<RawObject*> delayed_weak_stack_; |
| 193 | 214 |
| 194 bool visiting_old_pointers_; | 215 bool visiting_old_pointers_; |
| 216 bool in_scavenge_pointer_; |
| 195 | 217 |
| 196 DISALLOW_COPY_AND_ASSIGN(ScavengerVisitor); | 218 DISALLOW_COPY_AND_ASSIGN(ScavengerVisitor); |
| 197 }; | 219 }; |
| 198 | 220 |
| 199 | 221 |
| 200 class ScavengerWeakVisitor : public HandleVisitor { | 222 class ScavengerWeakVisitor : public HandleVisitor { |
| 201 public: | 223 public: |
| 202 explicit ScavengerWeakVisitor(Scavenger* scavenger) : scavenger_(scavenger) { | 224 explicit ScavengerWeakVisitor(Scavenger* scavenger) : scavenger_(scavenger) { |
| 203 } | 225 } |
| 204 | 226 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 #endif // defined(DEBUG) | 340 #endif // defined(DEBUG) |
| 319 if (invoke_api_callbacks) { | 341 if (invoke_api_callbacks) { |
| 320 isolate->gc_epilogue_callbacks().Invoke(); | 342 isolate->gc_epilogue_callbacks().Invoke(); |
| 321 } | 343 } |
| 322 } | 344 } |
| 323 | 345 |
| 324 | 346 |
| 325 void Scavenger::IterateStoreBuffers(Isolate* isolate, | 347 void Scavenger::IterateStoreBuffers(Isolate* isolate, |
| 326 ScavengerVisitor* visitor) { | 348 ScavengerVisitor* visitor) { |
| 327 // Iterating through the store buffers. | 349 // Iterating through the store buffers. |
| 328 visitor->VisitingOldPointers(true); | 350 BoolScope bs(visitor->VisitingOldPointersAddr(), true); |
| 329 // Grab the deduplication sets out of the store buffer. | 351 // Grab the deduplication sets out of the store buffer. |
| 330 StoreBuffer::DedupSet* pending = isolate->store_buffer()->DedupSets(); | 352 StoreBuffer::DedupSet* pending = isolate->store_buffer()->DedupSets(); |
| 331 intptr_t entries = 0; | 353 intptr_t entries = 0; |
| 332 intptr_t duplicates = 0; | 354 intptr_t duplicates = 0; |
| 333 while (pending != NULL) { | 355 while (pending != NULL) { |
| 334 StoreBuffer::DedupSet* next = pending->next(); | 356 StoreBuffer::DedupSet* next = pending->next(); |
| 335 HashSet* set = pending->set(); | 357 HashSet* set = pending->set(); |
| 336 intptr_t count = set->Count(); | 358 intptr_t count = set->Count(); |
| 337 intptr_t size = set->Size(); | 359 intptr_t size = set->Size(); |
| 338 intptr_t handled = 0; | 360 intptr_t handled = 0; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 } else { | 396 } else { |
| 375 duplicates++; | 397 duplicates++; |
| 376 } | 398 } |
| 377 } | 399 } |
| 378 } | 400 } |
| 379 block->Reset(); | 401 block->Reset(); |
| 380 if (FLAG_verbose_gc) { | 402 if (FLAG_verbose_gc) { |
| 381 OS::PrintErr("StoreBufferBlock: %"Pd", %"Pd" (entries, dups)\n", | 403 OS::PrintErr("StoreBufferBlock: %"Pd", %"Pd" (entries, dups)\n", |
| 382 entries, duplicates); | 404 entries, duplicates); |
| 383 } | 405 } |
| 384 // Done iterating through the store buffers. | |
| 385 visitor->VisitingOldPointers(false); | |
| 386 } | 406 } |
| 387 | 407 |
| 388 | 408 |
| 389 void Scavenger::IterateRoots(Isolate* isolate, | 409 void Scavenger::IterateRoots(Isolate* isolate, |
| 390 ScavengerVisitor* visitor, | 410 ScavengerVisitor* visitor, |
| 391 bool visit_prologue_weak_persistent_handles) { | 411 bool visit_prologue_weak_persistent_handles) { |
| 392 IterateStoreBuffers(isolate, visitor); | 412 IterateStoreBuffers(isolate, visitor); |
| 393 isolate->VisitObjectPointers(visitor, | 413 isolate->VisitObjectPointers(visitor, |
| 394 visit_prologue_weak_persistent_handles, | 414 visit_prologue_weak_persistent_handles, |
| 395 StackFrameIterator::kDontValidateFrames); | 415 StackFrameIterator::kDontValidateFrames); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 | 492 |
| 473 void Scavenger::IterateWeakRoots(Isolate* isolate, | 493 void Scavenger::IterateWeakRoots(Isolate* isolate, |
| 474 HandleVisitor* visitor, | 494 HandleVisitor* visitor, |
| 475 bool visit_prologue_weak_persistent_handles) { | 495 bool visit_prologue_weak_persistent_handles) { |
| 476 isolate->VisitWeakPersistentHandles(visitor, | 496 isolate->VisitWeakPersistentHandles(visitor, |
| 477 visit_prologue_weak_persistent_handles); | 497 visit_prologue_weak_persistent_handles); |
| 478 } | 498 } |
| 479 | 499 |
| 480 | 500 |
| 481 void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) { | 501 void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) { |
| 502 GrowableArray<RawObject*>* delayed_weak_stack = visitor->DelayedWeakStack(); |
| 503 |
| 482 // Iterate until all work has been drained. | 504 // Iterate until all work has been drained. |
| 483 while ((resolved_top_ < top_) || PromotedStackHasMore()) { | 505 while ((resolved_top_ < top_) || |
| 506 PromotedStackHasMore() || |
| 507 !delayed_weak_stack->is_empty()) { |
| 484 while (resolved_top_ < top_) { | 508 while (resolved_top_ < top_) { |
| 485 RawObject* raw_obj = RawObject::FromAddr(resolved_top_); | 509 RawObject* raw_obj = RawObject::FromAddr(resolved_top_); |
| 486 intptr_t class_id = raw_obj->GetClassId(); | 510 intptr_t class_id = raw_obj->GetClassId(); |
| 487 if (class_id != kWeakPropertyCid) { | 511 if (class_id != kWeakPropertyCid) { |
| 488 resolved_top_ += raw_obj->VisitPointers(visitor); | 512 resolved_top_ += raw_obj->VisitPointers(visitor); |
| 489 } else { | 513 } else { |
| 490 RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj); | 514 RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj); |
| 491 resolved_top_ += ProcessWeakProperty(raw_weak, visitor); | 515 resolved_top_ += ProcessWeakProperty(raw_weak, visitor); |
| 492 } | 516 } |
| 493 } | 517 } |
| 494 visitor->VisitingOldPointers(true); | 518 { |
| 495 while (PromotedStackHasMore()) { | 519 BoolScope bs(visitor->VisitingOldPointersAddr(), true); |
| 496 RawObject* raw_object = RawObject::FromAddr(PopFromPromotedStack()); | 520 while (PromotedStackHasMore()) { |
| 497 // Resolve or copy all objects referred to by the current object. This | 521 RawObject* raw_object = RawObject::FromAddr(PopFromPromotedStack()); |
| 498 // can potentially push more objects on this stack as well as add more | 522 // Resolve or copy all objects referred to by the current object. This |
| 499 // objects to be resolved in the to space. | 523 // can potentially push more objects on this stack as well as add more |
| 500 raw_object->VisitPointers(visitor); | 524 // objects to be resolved in the to space. |
| 525 raw_object->VisitPointers(visitor); |
| 526 } |
| 501 } | 527 } |
| 502 visitor->VisitingOldPointers(false); | 528 while (!delayed_weak_stack->is_empty()) { |
| 529 // Pop the delayed weak object from the stack and visit its pointers. |
| 530 RawObject* weak_property = delayed_weak_stack->Last(); |
| 531 delayed_weak_stack->RemoveLast(); |
| 532 weak_property->VisitPointers(visitor); |
| 533 } |
| 503 } | 534 } |
| 504 } | 535 } |
| 505 | 536 |
| 506 | 537 |
| 507 uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak, | 538 uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak, |
| 508 ScavengerVisitor* visitor) { | 539 ScavengerVisitor* visitor) { |
| 509 // The fate of the weak property is determined by its key. | 540 // The fate of the weak property is determined by its key. |
| 510 RawObject* raw_key = raw_weak->ptr()->key_; | 541 RawObject* raw_key = raw_weak->ptr()->key_; |
| 511 if (raw_key->IsHeapObject() && raw_key->IsNewObject()) { | 542 if (raw_key->IsHeapObject() && raw_key->IsNewObject()) { |
| 512 uword raw_addr = RawObject::ToAddr(raw_key); | 543 uword raw_addr = RawObject::ToAddr(raw_key); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 PeerTable::iterator it = peer_table_.find(raw_obj); | 666 PeerTable::iterator it = peer_table_.find(raw_obj); |
| 636 return (it == peer_table_.end()) ? NULL : it->second; | 667 return (it == peer_table_.end()) ? NULL : it->second; |
| 637 } | 668 } |
| 638 | 669 |
| 639 | 670 |
| 640 int64_t Scavenger::PeerCount() const { | 671 int64_t Scavenger::PeerCount() const { |
| 641 return static_cast<int64_t>(peer_table_.size()); | 672 return static_cast<int64_t>(peer_table_.size()); |
| 642 } | 673 } |
| 643 | 674 |
| 644 } // namespace dart | 675 } // namespace dart |
| OLD | NEW |