| Index: runtime/vm/scavenger.cc
|
| diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
|
| index bcbb79fed277ad6b27f8bd696e31a73892e22447..7921e36e4f1f022120252edd1132039442d67161 100644
|
| --- a/runtime/vm/scavenger.cc
|
| +++ b/runtime/vm/scavenger.cc
|
| @@ -4,10 +4,6 @@
|
|
|
| #include "vm/scavenger.h"
|
|
|
| -#include <algorithm>
|
| -#include <map>
|
| -#include <utility>
|
| -
|
| #include "vm/dart.h"
|
| #include "vm/dart_api_state.h"
|
| #include "vm/isolate.h"
|
| @@ -63,21 +59,6 @@ static inline void ForwardTo(uword original, uword target) {
|
| }
|
|
|
|
|
| -class BoolScope : public ValueObject {
|
| - public:
|
| - BoolScope(bool* addr, bool value) : _addr(addr), _value(*addr) {
|
| - *_addr = value;
|
| - }
|
| - ~BoolScope() {
|
| - *_addr = _value;
|
| - }
|
| -
|
| - private:
|
| - bool* _addr;
|
| - bool _value;
|
| -};
|
| -
|
| -
|
| class ScavengerVisitor : public ObjectPointerVisitor {
|
| public:
|
| explicit ScavengerVisitor(Isolate* isolate,
|
| @@ -90,45 +71,23 @@ class ScavengerVisitor : public ObjectPointerVisitor {
|
| heap_(scavenger->heap_),
|
| vm_heap_(Dart::vm_isolate()->heap()),
|
| page_space_(scavenger->heap_->old_space()),
|
| - delayed_weak_stack_(),
|
| bytes_promoted_(0),
|
| - visiting_old_object_(NULL),
|
| - in_scavenge_pointer_(false) { }
|
| + visiting_old_object_(NULL) { }
|
|
|
| void VisitPointers(RawObject** first, RawObject** last) {
|
| + ASSERT((visiting_old_object_ != NULL) ||
|
| + scavenger_->Contains(reinterpret_cast<uword>(first)) ||
|
| + !heap_->Contains(reinterpret_cast<uword>(first)));
|
| for (RawObject** current = first; current <= last; current++) {
|
| ScavengePointer(current);
|
| }
|
| }
|
|
|
| - GrowableArray<RawObject*>* DelayedWeakStack() {
|
| - return &delayed_weak_stack_;
|
| - }
|
| -
|
| void VisitingOldObject(RawObject* obj) {
|
| ASSERT((obj == NULL) || obj->IsOldObject());
|
| visiting_old_object_ = obj;
|
| }
|
|
|
| - void DelayWeakProperty(RawWeakProperty* raw_weak) {
|
| - RawObject* raw_key = raw_weak->ptr()->key_;
|
| - DelaySet::iterator it = delay_set_.find(raw_key);
|
| - if (it != delay_set_.end()) {
|
| - ASSERT(raw_key->IsWatched());
|
| - } else {
|
| - ASSERT(!raw_key->IsWatched());
|
| - raw_key->SetWatchedBitUnsynchronized();
|
| - }
|
| - delay_set_.insert(std::make_pair(raw_key, raw_weak));
|
| - }
|
| -
|
| - void Finalize() {
|
| - DelaySet::iterator it = delay_set_.begin();
|
| - for (; it != delay_set_.end(); ++it) {
|
| - WeakProperty::Clear(it->second);
|
| - }
|
| - }
|
| -
|
| intptr_t bytes_promoted() const { return bytes_promoted_; }
|
|
|
| private:
|
| @@ -148,11 +107,6 @@ class ScavengerVisitor : public ObjectPointerVisitor {
|
|
|
| void ScavengePointer(RawObject** p) {
|
| // ScavengePointer cannot be called recursively.
|
| -#ifdef DEBUG
|
| - ASSERT(!in_scavenge_pointer_);
|
| - BoolScope bs(&in_scavenge_pointer_, true);
|
| -#endif
|
| -
|
| RawObject* raw_obj = *p;
|
|
|
| if (raw_obj->IsSmiOrOldObject()) {
|
| @@ -170,20 +124,6 @@ class ScavengerVisitor : public ObjectPointerVisitor {
|
| // Get the new location of the object.
|
| new_addr = ForwardedAddr(header);
|
| } else {
|
| - if (raw_obj->IsWatched()) {
|
| - raw_obj->ClearWatchedBitUnsynchronized();
|
| - std::pair<DelaySet::iterator, DelaySet::iterator> ret;
|
| - // Visit all elements with a key equal to this raw_obj.
|
| - ret = delay_set_.equal_range(raw_obj);
|
| - for (DelaySet::iterator it = ret.first; it != ret.second; ++it) {
|
| - // Remember the delayed WeakProperty. These objects have been
|
| - // forwarded, but have not been scavenged because their key was not
|
| - // known to be reachable. Now that the key object is known to be
|
| - // reachable, we need to visit its key and value pointers.
|
| - delayed_weak_stack_.Add(it->second);
|
| - }
|
| - delay_set_.erase(ret.first, ret.second);
|
| - }
|
| intptr_t size = raw_obj->Size();
|
| intptr_t cid = raw_obj->GetClassId();
|
| ClassTable* class_table = isolate()->class_table();
|
| @@ -241,14 +181,11 @@ class ScavengerVisitor : public ObjectPointerVisitor {
|
| Heap* heap_;
|
| Heap* vm_heap_;
|
| PageSpace* page_space_;
|
| - typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet;
|
| - DelaySet delay_set_;
|
| - GrowableArray<RawObject*> delayed_weak_stack_;
|
| - // TODO(cshapiro): use this value to compute survival statistics for
|
| - // new space growth policy.
|
| + RawWeakProperty* delayed_weak_properties_;
|
| intptr_t bytes_promoted_;
|
| RawObject* visiting_old_object_;
|
| - bool in_scavenge_pointer_;
|
| +
|
| + friend class Scavenger;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(ScavengerVisitor);
|
| };
|
| @@ -397,6 +334,7 @@ Scavenger::Scavenger(Heap* heap,
|
| max_semi_capacity_in_words_(max_semi_capacity_in_words),
|
| object_alignment_(object_alignment),
|
| scavenging_(false),
|
| + delayed_weak_properties_(NULL),
|
| gc_time_micros_(0),
|
| collections_(0),
|
| external_size_(0) {
|
| @@ -601,12 +539,9 @@ void Scavenger::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) {
|
|
|
|
|
| void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) {
|
| - GrowableArray<RawObject*>* delayed_weak_stack = visitor->DelayedWeakStack();
|
| -
|
| // Iterate until all work has been drained.
|
| while ((resolved_top_ < top_) ||
|
| - PromotedStackHasMore() ||
|
| - !delayed_weak_stack->is_empty()) {
|
| + PromotedStackHasMore()) {
|
| while (resolved_top_ < top_) {
|
| RawObject* raw_obj = RawObject::FromAddr(resolved_top_);
|
| intptr_t class_id = raw_obj->GetClassId();
|
| @@ -618,6 +553,8 @@ void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) {
|
| }
|
| }
|
| {
|
| + // Visit all the promoted objects and update/scavenge their internal
|
| + // pointers. Potentially this adds more objects to the to space.
|
| while (PromotedStackHasMore()) {
|
| RawObject* raw_object = RawObject::FromAddr(PopFromPromotedStack());
|
| // Resolve or copy all objects referred to by the current object. This
|
| @@ -629,10 +566,36 @@ void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) {
|
| }
|
| visitor->VisitingOldObject(NULL);
|
| }
|
| - while (!delayed_weak_stack->is_empty()) {
|
| - // Pop the delayed weak object from the stack and visit its pointers.
|
| - RawObject* weak_property = delayed_weak_stack->RemoveLast();
|
| - weak_property->VisitPointers(visitor);
|
| + {
|
| + // Finished this round of scavenging. Process the pending weak properties
|
| + // for which the keys have become reachable. Potentially this adds more
|
| + // objects to the to space.
|
| + RawWeakProperty* cur_weak = delayed_weak_properties_;
|
| + delayed_weak_properties_ = NULL;
|
| + while (cur_weak != NULL) {
|
| + uword next_weak = cur_weak->ptr()->next_;
|
| + // Promoted weak properties are not enqueued. So we can guarantee that
|
| + // we do not need to think about store barriers here.
|
| + ASSERT(cur_weak->IsNewObject());
|
| + RawObject* raw_key = cur_weak->ptr()->key_;
|
| + ASSERT(raw_key->IsHeapObject());
|
| + // Key still points into from space even if the object has been
|
| + // promoted to old space by now. The key will be updated accordingly
|
| + // below when VisitPointers is run.
|
| + ASSERT(raw_key->IsNewObject());
|
| + uword raw_addr = RawObject::ToAddr(raw_key);
|
| + ASSERT(visitor->from_->Contains(raw_addr));
|
| + uword header = *reinterpret_cast<uword*>(raw_addr);
|
| + // Reset the next pointer in the weak property.
|
| + cur_weak->ptr()->next_ = 0;
|
| + if (IsForwarding(header)) {
|
| + cur_weak->VisitPointers(visitor);
|
| + } else {
|
| + EnqueueWeakProperty(cur_weak);
|
| + }
|
| + // Advance to next weak property in the queue.
|
| + cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak);
|
| + }
|
| }
|
| }
|
| }
|
| @@ -665,6 +628,21 @@ void Scavenger::UpdateMaxHeapUsage() {
|
| }
|
|
|
|
|
| +void Scavenger::EnqueueWeakProperty(RawWeakProperty* raw_weak) {
|
| + ASSERT(raw_weak->IsHeapObject());
|
| + ASSERT(raw_weak->IsNewObject());
|
| + ASSERT(raw_weak->IsWeakProperty());
|
| + DEBUG_ONLY(
|
| + uword raw_addr = RawObject::ToAddr(raw_weak);
|
| + uword header = *reinterpret_cast<uword*>(raw_addr);
|
| + ASSERT(!IsForwarding(header));
|
| + )
|
| + ASSERT(raw_weak->ptr()->next_ == 0);
|
| + raw_weak->ptr()->next_ = reinterpret_cast<uword>(delayed_weak_properties_);
|
| + delayed_weak_properties_ = raw_weak;
|
| +}
|
| +
|
| +
|
| uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak,
|
| ScavengerVisitor* visitor) {
|
| // The fate of the weak property is determined by its key.
|
| @@ -673,8 +651,8 @@ uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak,
|
| uword raw_addr = RawObject::ToAddr(raw_key);
|
| uword header = *reinterpret_cast<uword*>(raw_addr);
|
| if (!IsForwarding(header)) {
|
| - // Key is white. Delay the weak property.
|
| - visitor->DelayWeakProperty(raw_weak);
|
| + // Key is white. Enqueue the weak property.
|
| + EnqueueWeakProperty(raw_weak);
|
| return raw_weak->Size();
|
| }
|
| }
|
| @@ -683,7 +661,8 @@ uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak,
|
| }
|
|
|
|
|
| -void Scavenger::ProcessWeakTables() {
|
| +void Scavenger::ProcessWeakReferences() {
|
| + // Rehash the weak tables now that we know which objects survive this cycle.
|
| for (int sel = 0;
|
| sel < Heap::kNumWeakSelectors;
|
| sel++) {
|
| @@ -713,6 +692,32 @@ void Scavenger::ProcessWeakTables() {
|
| // table above.
|
| delete table;
|
| }
|
| +
|
| + // The queued weak properties at this point do not refer to reachable keys,
|
| + // so we clear their key and value fields.
|
| + {
|
| + RawWeakProperty* cur_weak = delayed_weak_properties_;
|
| + delayed_weak_properties_ = NULL;
|
| + while (cur_weak != NULL) {
|
| + uword next_weak = cur_weak->ptr()->next_;
|
| + // Reset the next pointer in the weak property.
|
| + cur_weak->ptr()->next_ = 0;
|
| +
|
| + DEBUG_ONLY(
|
| + RawObject* raw_key = cur_weak->ptr()->key_;
|
| + uword raw_addr = RawObject::ToAddr(raw_key);
|
| + uword header = *reinterpret_cast<uword*>(raw_addr);
|
| + ASSERT(!IsForwarding(header));
|
| + ASSERT(raw_key->IsHeapObject());
|
| + ASSERT(raw_key->IsNewObject()); // Key still points into from space.
|
| + )
|
| +
|
| + WeakProperty::Clear(cur_weak);
|
| +
|
| + // Advance to next weak property in the queue.
|
| + cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak);
|
| + }
|
| + }
|
| }
|
|
|
|
|
| @@ -801,8 +806,7 @@ void Scavenger::Scavenge(bool invoke_api_callbacks) {
|
| int64_t middle = OS::GetCurrentTimeMicros();
|
| ScavengerWeakVisitor weak_visitor(this);
|
| IterateWeakRoots(isolate, &weak_visitor);
|
| - visitor.Finalize();
|
| - ProcessWeakTables();
|
| + ProcessWeakReferences();
|
| page_space->ReleaseDataLock();
|
|
|
| // Scavenge finished. Run accounting.
|
|
|