Home | History | Annotate | Download | only in src
      1 // Copyright 2009 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/global-handles.h"
      6 
      7 #include "src/api.h"
      8 #include "src/v8.h"
      9 #include "src/vm-state-inl.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 
     15 ObjectGroup::~ObjectGroup() {
     16   if (info != NULL) info->Dispose();
     17   delete[] objects;
     18 }
     19 
     20 
     21 ImplicitRefGroup::~ImplicitRefGroup() {
     22   delete[] children;
     23 }
     24 
     25 
     26 class GlobalHandles::Node {
     27  public:
     28   // State transition diagram:
     29   // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
     30   enum State {
     31     FREE = 0,
     32     NORMAL,      // Normal global handle.
     33     WEAK,        // Flagged as weak but not yet finalized.
     34     PENDING,     // Has been recognized as only reachable by weak handles.
     35     NEAR_DEATH,  // Callback has informed the handle is near death.
     36     NUMBER_OF_NODE_STATES
     37   };
     38 
     39   // Maps handle location (slot) to the containing node.
     40   static Node* FromLocation(Object** location) {
     41     DCHECK(offsetof(Node, object_) == 0);
     42     return reinterpret_cast<Node*>(location);
     43   }
     44 
     45   Node() {
     46     DCHECK(offsetof(Node, class_id_) == Internals::kNodeClassIdOffset);
     47     DCHECK(offsetof(Node, flags_) == Internals::kNodeFlagsOffset);
     48     STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
     49                   Internals::kNodeStateMask);
     50     STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
     51     STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
     52     STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
     53     STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
     54                   Internals::kNodeIsIndependentShift);
     55     STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
     56                   Internals::kNodeIsPartiallyDependentShift);
     57     STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
     58                   Internals::kNodeIsActiveShift);
     59   }
     60 
     61 #ifdef ENABLE_HANDLE_ZAPPING
     62   ~Node() {
     63     // TODO(1428): if it's a weak handle we should have invoked its callback.
     64     // Zap the values for eager trapping.
     65     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
     66     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
     67     index_ = 0;
     68     set_independent(false);
     69     if (FLAG_scavenge_reclaim_unmodified_objects) {
     70       set_active(false);
     71     } else {
     72       set_partially_dependent(false);
     73     }
     74     set_in_new_space_list(false);
     75     parameter_or_next_free_.next_free = NULL;
     76     weak_callback_ = NULL;
     77   }
     78 #endif
     79 
     80   void Initialize(int index, Node** first_free) {
     81     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
     82     index_ = static_cast<uint8_t>(index);
     83     DCHECK(static_cast<int>(index_) == index);
     84     set_state(FREE);
     85     set_weakness_type(NORMAL_WEAK);
     86     set_in_new_space_list(false);
     87     parameter_or_next_free_.next_free = *first_free;
     88     *first_free = this;
     89   }
     90 
     91   void Acquire(Object* object) {
     92     DCHECK(state() == FREE);
     93     object_ = object;
     94     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
     95     set_independent(false);
     96     if (FLAG_scavenge_reclaim_unmodified_objects) {
     97       set_active(false);
     98     } else {
     99       set_partially_dependent(false);
    100     }
    101     set_state(NORMAL);
    102     parameter_or_next_free_.parameter = NULL;
    103     weak_callback_ = NULL;
    104     IncreaseBlockUses();
    105   }
    106 
    107   void Zap() {
    108     DCHECK(IsInUse());
    109     // Zap the values for eager trapping.
    110     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
    111   }
    112 
    113   void Release() {
    114     DCHECK(IsInUse());
    115     set_state(FREE);
    116     // Zap the values for eager trapping.
    117     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
    118     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
    119     set_independent(false);
    120     if (FLAG_scavenge_reclaim_unmodified_objects) {
    121       set_active(false);
    122     } else {
    123       set_partially_dependent(false);
    124     }
    125     weak_callback_ = NULL;
    126     DecreaseBlockUses();
    127   }
    128 
    129   // Object slot accessors.
    130   Object* object() const { return object_; }
    131   Object** location() { return &object_; }
    132   Handle<Object> handle() { return Handle<Object>(location()); }
    133 
    134   // Wrapper class ID accessors.
    135   bool has_wrapper_class_id() const {
    136     return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
    137   }
    138 
    139   uint16_t wrapper_class_id() const { return class_id_; }
    140 
    141   // State and flag accessors.
    142 
    143   State state() const {
    144     return NodeState::decode(flags_);
    145   }
    146   void set_state(State state) {
    147     flags_ = NodeState::update(flags_, state);
    148   }
    149 
    150   bool is_independent() {
    151     return IsIndependent::decode(flags_);
    152   }
    153   void set_independent(bool v) {
    154     flags_ = IsIndependent::update(flags_, v);
    155   }
    156 
    157   bool is_partially_dependent() {
    158     CHECK(!FLAG_scavenge_reclaim_unmodified_objects);
    159     return IsPartiallyDependent::decode(flags_);
    160   }
    161   void set_partially_dependent(bool v) {
    162     CHECK(!FLAG_scavenge_reclaim_unmodified_objects);
    163     flags_ = IsPartiallyDependent::update(flags_, v);
    164   }
    165 
    166   bool is_active() {
    167     CHECK(FLAG_scavenge_reclaim_unmodified_objects);
    168     return IsActive::decode(flags_);
    169   }
    170   void set_active(bool v) {
    171     CHECK(FLAG_scavenge_reclaim_unmodified_objects);
    172     flags_ = IsActive::update(flags_, v);
    173   }
    174 
    175   bool is_in_new_space_list() {
    176     return IsInNewSpaceList::decode(flags_);
    177   }
    178   void set_in_new_space_list(bool v) {
    179     flags_ = IsInNewSpaceList::update(flags_, v);
    180   }
    181 
    182   WeaknessType weakness_type() const {
    183     return NodeWeaknessType::decode(flags_);
    184   }
    185   void set_weakness_type(WeaknessType weakness_type) {
    186     flags_ = NodeWeaknessType::update(flags_, weakness_type);
    187   }
    188 
    189   bool IsNearDeath() const {
    190     // Check for PENDING to ensure correct answer when processing callbacks.
    191     return state() == PENDING || state() == NEAR_DEATH;
    192   }
    193 
    194   bool IsWeak() const { return state() == WEAK; }
    195 
    196   bool IsInUse() const { return state() != FREE; }
    197 
    198   bool IsRetainer() const {
    199     return state() != FREE &&
    200            !(state() == NEAR_DEATH && weakness_type() != NORMAL_WEAK);
    201   }
    202 
    203   bool IsStrongRetainer() const { return state() == NORMAL; }
    204 
    205   bool IsWeakRetainer() const {
    206     return state() == WEAK || state() == PENDING ||
    207            (state() == NEAR_DEATH && weakness_type() == NORMAL_WEAK);
    208   }
    209 
    210   void MarkPending() {
    211     DCHECK(state() == WEAK);
    212     set_state(PENDING);
    213   }
    214 
    215   // Independent flag accessors.
    216   void MarkIndependent() {
    217     DCHECK(IsInUse());
    218     set_independent(true);
    219   }
    220 
    221   void MarkPartiallyDependent() {
    222     DCHECK(IsInUse());
    223     if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
    224       set_partially_dependent(true);
    225     }
    226   }
    227   void clear_partially_dependent() { set_partially_dependent(false); }
    228 
    229   // Callback accessor.
    230   // TODO(svenpanne) Re-enable or nuke later.
    231   // WeakReferenceCallback callback() { return callback_; }
    232 
    233   // Callback parameter accessors.
    234   void set_parameter(void* parameter) {
    235     DCHECK(IsInUse());
    236     parameter_or_next_free_.parameter = parameter;
    237   }
    238   void* parameter() const {
    239     DCHECK(IsInUse());
    240     return parameter_or_next_free_.parameter;
    241   }
    242 
    243   // Accessors for next free node in the free list.
    244   Node* next_free() {
    245     DCHECK(state() == FREE);
    246     return parameter_or_next_free_.next_free;
    247   }
    248   void set_next_free(Node* value) {
    249     DCHECK(state() == FREE);
    250     parameter_or_next_free_.next_free = value;
    251   }
    252 
    253   void MakeWeak(void* parameter, WeakCallback weak_callback) {
    254     DCHECK(weak_callback != nullptr);
    255     DCHECK(IsInUse());
    256     CHECK_NE(object_, reinterpret_cast<Object*>(kGlobalHandleZapValue));
    257     set_state(WEAK);
    258     set_weakness_type(NORMAL_WEAK);
    259     set_parameter(parameter);
    260     weak_callback_ = weak_callback;
    261   }
    262 
    263   void MakeWeak(void* parameter,
    264                 WeakCallbackInfo<void>::Callback phantom_callback,
    265                 v8::WeakCallbackType type) {
    266     DCHECK(phantom_callback != nullptr);
    267     DCHECK(IsInUse());
    268     CHECK_NE(object_, reinterpret_cast<Object*>(kGlobalHandleZapValue));
    269     set_state(WEAK);
    270     switch (type) {
    271       case v8::WeakCallbackType::kParameter:
    272         set_weakness_type(PHANTOM_WEAK);
    273         break;
    274       case v8::WeakCallbackType::kInternalFields:
    275       set_weakness_type(PHANTOM_WEAK_2_INTERNAL_FIELDS);
    276       break;
    277     }
    278     set_parameter(parameter);
    279     weak_callback_ = reinterpret_cast<WeakCallback>(phantom_callback);
    280   }
    281 
    282   void* ClearWeakness() {
    283     DCHECK(IsInUse());
    284     void* p = parameter();
    285     set_state(NORMAL);
    286     set_parameter(NULL);
    287     return p;
    288   }
    289 
    290   void CollectPhantomCallbackData(
    291       Isolate* isolate,
    292       List<PendingPhantomCallback>* pending_phantom_callbacks) {
    293     DCHECK(weakness_type() == PHANTOM_WEAK ||
    294            weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
    295     DCHECK(state() == PENDING);
    296 
    297     void* internal_fields[v8::kInternalFieldsInWeakCallback] = {nullptr,
    298                                                                 nullptr};
    299     if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
    300       auto jsobject = JSObject::cast(object());
    301       int field_count = jsobject->GetInternalFieldCount();
    302       for (int i = 0; i < v8::kInternalFieldsInWeakCallback; ++i) {
    303         if (field_count == i) break;
    304         auto field = jsobject->GetInternalField(i);
    305         if (field->IsSmi()) internal_fields[i] = field;
    306       }
    307     }
    308 
    309     // Zap with something dangerous.
    310     *location() = reinterpret_cast<Object*>(0x6057ca11);
    311 
    312     typedef v8::WeakCallbackInfo<void> Data;
    313     auto callback = reinterpret_cast<Data::Callback>(weak_callback_);
    314     pending_phantom_callbacks->Add(
    315         PendingPhantomCallback(this, callback, parameter(), internal_fields));
    316     DCHECK(IsInUse());
    317     set_state(NEAR_DEATH);
    318   }
    319 
    320   bool PostGarbageCollectionProcessing(Isolate* isolate) {
    321     // Handles only weak handles (not phantom) that are dying.
    322     if (state() != Node::PENDING) return false;
    323     if (weak_callback_ == NULL) {
    324       Release();
    325       return false;
    326     }
    327     set_state(NEAR_DEATH);
    328 
    329     // Check that we are not passing a finalized external string to
    330     // the callback.
    331     DCHECK(!object_->IsExternalOneByteString() ||
    332            ExternalOneByteString::cast(object_)->resource() != NULL);
    333     DCHECK(!object_->IsExternalTwoByteString() ||
    334            ExternalTwoByteString::cast(object_)->resource() != NULL);
    335     if (weakness_type() != NORMAL_WEAK) return false;
    336 
    337     // Leaving V8.
    338     VMState<EXTERNAL> vmstate(isolate);
    339     HandleScope handle_scope(isolate);
    340     Object** object = location();
    341     Handle<Object> handle(*object, isolate);
    342     v8::WeakCallbackData<v8::Value, void> data(
    343         reinterpret_cast<v8::Isolate*>(isolate), parameter(),
    344         v8::Utils::ToLocal(handle));
    345     set_parameter(NULL);
    346     weak_callback_(data);
    347 
    348     // Absence of explicit cleanup or revival of weak handle
    349     // in most of the cases would lead to memory leak.
    350     CHECK(state() != NEAR_DEATH);
    351     return true;
    352   }
    353 
    354   inline GlobalHandles* GetGlobalHandles();
    355 
    356  private:
    357   inline NodeBlock* FindBlock();
    358   inline void IncreaseBlockUses();
    359   inline void DecreaseBlockUses();
    360 
    361   // Storage for object pointer.
    362   // Placed first to avoid offset computation.
    363   Object* object_;
    364 
    365   // Next word stores class_id, index, state, and independent.
    366   // Note: the most aligned fields should go first.
    367 
    368   // Wrapper class ID.
    369   uint16_t class_id_;
    370 
    371   // Index in the containing handle block.
    372   uint8_t index_;
    373 
    374   // This stores three flags (independent, partially_dependent and
    375   // in_new_space_list) and a State.
    376   class NodeState : public BitField<State, 0, 3> {};
    377   class IsIndependent : public BitField<bool, 3, 1> {};
    378   // The following two fields are mutually exclusive
    379   class IsActive : public BitField<bool, 4, 1> {};
    380   class IsPartiallyDependent : public BitField<bool, 4, 1> {};
    381   class IsInNewSpaceList : public BitField<bool, 5, 1> {};
    382   class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
    383 
    384   uint8_t flags_;
    385 
    386   // Handle specific callback - might be a weak reference in disguise.
    387   WeakCallback weak_callback_;
    388 
    389   // Provided data for callback.  In FREE state, this is used for
    390   // the free list link.
    391   union {
    392     void* parameter;
    393     Node* next_free;
    394   } parameter_or_next_free_;
    395 
    396   DISALLOW_COPY_AND_ASSIGN(Node);
    397 };
    398 
    399 
    400 class GlobalHandles::NodeBlock {
    401  public:
    402   static const int kSize = 256;
    403 
    404   explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
    405       : next_(next),
    406         used_nodes_(0),
    407         next_used_(NULL),
    408         prev_used_(NULL),
    409         global_handles_(global_handles) {}
    410 
    411   void PutNodesOnFreeList(Node** first_free) {
    412     for (int i = kSize - 1; i >= 0; --i) {
    413       nodes_[i].Initialize(i, first_free);
    414     }
    415   }
    416 
    417   Node* node_at(int index) {
    418     DCHECK(0 <= index && index < kSize);
    419     return &nodes_[index];
    420   }
    421 
    422   void IncreaseUses() {
    423     DCHECK(used_nodes_ < kSize);
    424     if (used_nodes_++ == 0) {
    425       NodeBlock* old_first = global_handles_->first_used_block_;
    426       global_handles_->first_used_block_ = this;
    427       next_used_ = old_first;
    428       prev_used_ = NULL;
    429       if (old_first == NULL) return;
    430       old_first->prev_used_ = this;
    431     }
    432   }
    433 
    434   void DecreaseUses() {
    435     DCHECK(used_nodes_ > 0);
    436     if (--used_nodes_ == 0) {
    437       if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
    438       if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
    439       if (this == global_handles_->first_used_block_) {
    440         global_handles_->first_used_block_ = next_used_;
    441       }
    442     }
    443   }
    444 
    445   GlobalHandles* global_handles() { return global_handles_; }
    446 
    447   // Next block in the list of all blocks.
    448   NodeBlock* next() const { return next_; }
    449 
    450   // Next/previous block in the list of blocks with used nodes.
    451   NodeBlock* next_used() const { return next_used_; }
    452   NodeBlock* prev_used() const { return prev_used_; }
    453 
    454  private:
    455   Node nodes_[kSize];
    456   NodeBlock* const next_;
    457   int used_nodes_;
    458   NodeBlock* next_used_;
    459   NodeBlock* prev_used_;
    460   GlobalHandles* global_handles_;
    461 };
    462 
    463 
    464 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
    465   return FindBlock()->global_handles();
    466 }
    467 
    468 
    469 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
    470   intptr_t ptr = reinterpret_cast<intptr_t>(this);
    471   ptr = ptr - index_ * sizeof(Node);
    472   NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
    473   DCHECK(block->node_at(index_) == this);
    474   return block;
    475 }
    476 
    477 
    478 void GlobalHandles::Node::IncreaseBlockUses() {
    479   NodeBlock* node_block = FindBlock();
    480   node_block->IncreaseUses();
    481   GlobalHandles* global_handles = node_block->global_handles();
    482   global_handles->isolate()->counters()->global_handles()->Increment();
    483   global_handles->number_of_global_handles_++;
    484 }
    485 
    486 
    487 void GlobalHandles::Node::DecreaseBlockUses() {
    488   NodeBlock* node_block = FindBlock();
    489   GlobalHandles* global_handles = node_block->global_handles();
    490   parameter_or_next_free_.next_free = global_handles->first_free_;
    491   global_handles->first_free_ = this;
    492   node_block->DecreaseUses();
    493   global_handles->isolate()->counters()->global_handles()->Decrement();
    494   global_handles->number_of_global_handles_--;
    495 }
    496 
    497 
    498 class GlobalHandles::NodeIterator {
    499  public:
    500   explicit NodeIterator(GlobalHandles* global_handles)
    501       : block_(global_handles->first_used_block_),
    502         index_(0) {}
    503 
    504   bool done() const { return block_ == NULL; }
    505 
    506   Node* node() const {
    507     DCHECK(!done());
    508     return block_->node_at(index_);
    509   }
    510 
    511   void Advance() {
    512     DCHECK(!done());
    513     if (++index_ < NodeBlock::kSize) return;
    514     index_ = 0;
    515     block_ = block_->next_used();
    516   }
    517 
    518  private:
    519   NodeBlock* block_;
    520   int index_;
    521 
    522   DISALLOW_COPY_AND_ASSIGN(NodeIterator);
    523 };
    524 
    525 class GlobalHandles::PendingPhantomCallbacksSecondPassTask
    526     : public v8::internal::CancelableTask {
    527  public:
    528   // Takes ownership of the contents of pending_phantom_callbacks, leaving it in
    529   // the same state it would be after a call to Clear().
    530   PendingPhantomCallbacksSecondPassTask(
    531       List<PendingPhantomCallback>* pending_phantom_callbacks, Isolate* isolate)
    532       : CancelableTask(isolate) {
    533     pending_phantom_callbacks_.Swap(pending_phantom_callbacks);
    534   }
    535 
    536   void RunInternal() override {
    537     isolate()->heap()->CallGCPrologueCallbacks(
    538         GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    539     InvokeSecondPassPhantomCallbacks(&pending_phantom_callbacks_, isolate());
    540     isolate()->heap()->CallGCEpilogueCallbacks(
    541         GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    542   }
    543 
    544  private:
    545   List<PendingPhantomCallback> pending_phantom_callbacks_;
    546 
    547   DISALLOW_COPY_AND_ASSIGN(PendingPhantomCallbacksSecondPassTask);
    548 };
    549 
    550 
    551 GlobalHandles::GlobalHandles(Isolate* isolate)
    552     : isolate_(isolate),
    553       number_of_global_handles_(0),
    554       first_block_(NULL),
    555       first_used_block_(NULL),
    556       first_free_(NULL),
    557       post_gc_processing_count_(0),
    558       object_group_connections_(kObjectGroupConnectionsCapacity) {}
    559 
    560 
    561 GlobalHandles::~GlobalHandles() {
    562   NodeBlock* block = first_block_;
    563   while (block != NULL) {
    564     NodeBlock* tmp = block->next();
    565     delete block;
    566     block = tmp;
    567   }
    568   first_block_ = NULL;
    569 }
    570 
    571 
    572 Handle<Object> GlobalHandles::Create(Object* value) {
    573   if (first_free_ == NULL) {
    574     first_block_ = new NodeBlock(this, first_block_);
    575     first_block_->PutNodesOnFreeList(&first_free_);
    576   }
    577   DCHECK(first_free_ != NULL);
    578   // Take the first node in the free list.
    579   Node* result = first_free_;
    580   first_free_ = result->next_free();
    581   result->Acquire(value);
    582   if (isolate_->heap()->InNewSpace(value) &&
    583       !result->is_in_new_space_list()) {
    584     new_space_nodes_.Add(result);
    585     result->set_in_new_space_list(true);
    586   }
    587   return result->handle();
    588 }
    589 
    590 
    591 Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
    592   DCHECK(location != NULL);
    593   return Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
    594 }
    595 
    596 
    597 void GlobalHandles::Destroy(Object** location) {
    598   if (location != NULL) Node::FromLocation(location)->Release();
    599 }
    600 
    601 
    602 void GlobalHandles::MakeWeak(Object** location, void* parameter,
    603                              WeakCallback weak_callback) {
    604   Node::FromLocation(location)->MakeWeak(parameter, weak_callback);
    605 }
    606 
    607 
    608 typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
    609 
    610 
    611 void GlobalHandles::MakeWeak(Object** location, void* parameter,
    612                              GenericCallback phantom_callback,
    613                              v8::WeakCallbackType type) {
    614   Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
    615 }
    616 
    617 
    618 void* GlobalHandles::ClearWeakness(Object** location) {
    619   return Node::FromLocation(location)->ClearWeakness();
    620 }
    621 
    622 
    623 void GlobalHandles::MarkIndependent(Object** location) {
    624   Node::FromLocation(location)->MarkIndependent();
    625 }
    626 
    627 
    628 void GlobalHandles::MarkPartiallyDependent(Object** location) {
    629   Node::FromLocation(location)->MarkPartiallyDependent();
    630 }
    631 
    632 
    633 bool GlobalHandles::IsIndependent(Object** location) {
    634   return Node::FromLocation(location)->is_independent();
    635 }
    636 
    637 
    638 bool GlobalHandles::IsNearDeath(Object** location) {
    639   return Node::FromLocation(location)->IsNearDeath();
    640 }
    641 
    642 
    643 bool GlobalHandles::IsWeak(Object** location) {
    644   return Node::FromLocation(location)->IsWeak();
    645 }
    646 
    647 
    648 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
    649   for (NodeIterator it(this); !it.done(); it.Advance()) {
    650     Node* node = it.node();
    651     if (node->IsWeakRetainer()) {
    652       // Pending weak phantom handles die immediately. Everything else survives.
    653       if (node->state() == Node::PENDING &&
    654           node->weakness_type() != NORMAL_WEAK) {
    655           node->CollectPhantomCallbackData(isolate(),
    656                                            &pending_phantom_callbacks_);
    657       } else {
    658         v->VisitPointer(node->location());
    659       }
    660     }
    661   }
    662 }
    663 
    664 
    665 void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
    666   for (NodeIterator it(this); !it.done(); it.Advance()) {
    667     if (it.node()->IsWeak() && f(it.node()->location())) {
    668       it.node()->MarkPending();
    669     }
    670   }
    671 }
    672 
    673 
    674 void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
    675   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    676     Node* node = new_space_nodes_[i];
    677     if (FLAG_scavenge_reclaim_unmodified_objects) {
    678       if (node->IsStrongRetainer() ||
    679           (node->IsWeakRetainer() && !node->is_independent() &&
    680            node->is_active())) {
    681         v->VisitPointer(node->location());
    682       }
    683     } else {
    684       if (node->IsStrongRetainer() ||
    685           (node->IsWeakRetainer() && !node->is_independent() &&
    686            !node->is_partially_dependent())) {
    687         v->VisitPointer(node->location());
    688       }
    689     }
    690   }
    691 }
    692 
    693 
    694 void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles(
    695     WeakSlotCallbackWithHeap f) {
    696   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    697     Node* node = new_space_nodes_[i];
    698     DCHECK(node->is_in_new_space_list());
    699     if ((node->is_independent() || node->is_partially_dependent()) &&
    700         node->IsWeak() && f(isolate_->heap(), node->location())) {
    701       node->MarkPending();
    702     }
    703   }
    704 }
    705 
    706 
    707 void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
    708   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    709     Node* node = new_space_nodes_[i];
    710     DCHECK(node->is_in_new_space_list());
    711     if ((node->is_independent() || node->is_partially_dependent()) &&
    712         node->IsWeakRetainer()) {
    713       // Pending weak phantom handles die immediately. Everything else survives.
    714       if (node->state() == Node::PENDING &&
    715           node->weakness_type() != NORMAL_WEAK) {
    716         node->CollectPhantomCallbackData(isolate(),
    717                                          &pending_phantom_callbacks_);
    718       } else {
    719         v->VisitPointer(node->location());
    720       }
    721     }
    722   }
    723 }
    724 
    725 
    726 void GlobalHandles::IdentifyWeakUnmodifiedObjects(
    727     WeakSlotCallback is_unmodified) {
    728   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    729     Node* node = new_space_nodes_[i];
    730     if (node->IsWeak() && !is_unmodified(node->location())) {
    731       node->set_active(true);
    732     }
    733   }
    734 }
    735 
    736 
    737 void GlobalHandles::MarkNewSpaceWeakUnmodifiedObjectsPending(
    738     WeakSlotCallbackWithHeap is_unscavenged) {
    739   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    740     Node* node = new_space_nodes_[i];
    741     DCHECK(node->is_in_new_space_list());
    742     if ((node->is_independent() || !node->is_active()) && node->IsWeak() &&
    743         is_unscavenged(isolate_->heap(), node->location())) {
    744       node->MarkPending();
    745     }
    746   }
    747 }
    748 
    749 
    750 void GlobalHandles::IterateNewSpaceWeakUnmodifiedRoots(ObjectVisitor* v) {
    751   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    752     Node* node = new_space_nodes_[i];
    753     DCHECK(node->is_in_new_space_list());
    754     if ((node->is_independent() || !node->is_active()) &&
    755         node->IsWeakRetainer()) {
    756       // Pending weak phantom handles die immediately. Everything else survives.
    757       if (node->state() == Node::PENDING &&
    758           node->weakness_type() != NORMAL_WEAK) {
    759         node->CollectPhantomCallbackData(isolate(),
    760                                          &pending_phantom_callbacks_);
    761       } else {
    762         v->VisitPointer(node->location());
    763       }
    764     }
    765   }
    766 }
    767 
    768 
    769 bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
    770                                         WeakSlotCallbackWithHeap can_skip) {
    771   ComputeObjectGroupsAndImplicitReferences();
    772   int last = 0;
    773   bool any_group_was_visited = false;
    774   for (int i = 0; i < object_groups_.length(); i++) {
    775     ObjectGroup* entry = object_groups_.at(i);
    776     DCHECK(entry != NULL);
    777 
    778     Object*** objects = entry->objects;
    779     bool group_should_be_visited = false;
    780     for (size_t j = 0; j < entry->length; j++) {
    781       Object* object = *objects[j];
    782       if (object->IsHeapObject()) {
    783         if (!can_skip(isolate_->heap(), &object)) {
    784           group_should_be_visited = true;
    785           break;
    786         }
    787       }
    788     }
    789 
    790     if (!group_should_be_visited) {
    791       object_groups_[last++] = entry;
    792       continue;
    793     }
    794 
    795     // An object in the group requires visiting, so iterate over all
    796     // objects in the group.
    797     for (size_t j = 0; j < entry->length; ++j) {
    798       Object* object = *objects[j];
    799       if (object->IsHeapObject()) {
    800         v->VisitPointer(&object);
    801         any_group_was_visited = true;
    802       }
    803     }
    804 
    805     // Once the entire group has been iterated over, set the object
    806     // group to NULL so it won't be processed again.
    807     delete entry;
    808     object_groups_.at(i) = NULL;
    809   }
    810   object_groups_.Rewind(last);
    811   return any_group_was_visited;
    812 }
    813 
    814 
    815 void GlobalHandles::InvokeSecondPassPhantomCallbacks(
    816     List<PendingPhantomCallback>* callbacks, Isolate* isolate) {
    817   while (callbacks->length() != 0) {
    818     auto callback = callbacks->RemoveLast();
    819     DCHECK(callback.node() == nullptr);
    820     // No second pass callback required.
    821     if (callback.callback() == nullptr) continue;
    822     // Fire second pass callback
    823     callback.Invoke(isolate);
    824   }
    825 }
    826 
    827 
    828 int GlobalHandles::PostScavengeProcessing(
    829     const int initial_post_gc_processing_count) {
    830   int freed_nodes = 0;
    831   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    832     Node* node = new_space_nodes_[i];
    833     DCHECK(node->is_in_new_space_list());
    834     if (!node->IsRetainer()) {
    835       // Free nodes do not have weak callbacks. Do not use them to compute
    836       // the freed_nodes.
    837       continue;
    838     }
    839     // Skip dependent or unmodified handles. Their weak callbacks might expect
    840     // to be
    841     // called between two global garbage collection callbacks which
    842     // are not called for minor collections.
    843     if (FLAG_scavenge_reclaim_unmodified_objects) {
    844       if (!node->is_independent() && (node->is_active())) {
    845         node->set_active(false);
    846         continue;
    847       }
    848       node->set_active(false);
    849     } else {
    850       if (!node->is_independent() && !node->is_partially_dependent()) {
    851         continue;
    852       }
    853       node->clear_partially_dependent();
    854     }
    855 
    856     if (node->PostGarbageCollectionProcessing(isolate_)) {
    857       if (initial_post_gc_processing_count != post_gc_processing_count_) {
    858         // Weak callback triggered another GC and another round of
    859         // PostGarbageCollection processing.  The current node might
    860         // have been deleted in that round, so we need to bail out (or
    861         // restart the processing).
    862         return freed_nodes;
    863       }
    864     }
    865     if (!node->IsRetainer()) {
    866       freed_nodes++;
    867     }
    868   }
    869   return freed_nodes;
    870 }
    871 
    872 
    873 int GlobalHandles::PostMarkSweepProcessing(
    874     const int initial_post_gc_processing_count) {
    875   int freed_nodes = 0;
    876   for (NodeIterator it(this); !it.done(); it.Advance()) {
    877     if (!it.node()->IsRetainer()) {
    878       // Free nodes do not have weak callbacks. Do not use them to compute
    879       // the freed_nodes.
    880       continue;
    881     }
    882     if (FLAG_scavenge_reclaim_unmodified_objects) {
    883       it.node()->set_active(false);
    884     } else {
    885       it.node()->clear_partially_dependent();
    886     }
    887     if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
    888       if (initial_post_gc_processing_count != post_gc_processing_count_) {
    889         // See the comment above.
    890         return freed_nodes;
    891       }
    892     }
    893     if (!it.node()->IsRetainer()) {
    894       freed_nodes++;
    895     }
    896   }
    897   return freed_nodes;
    898 }
    899 
    900 
    901 void GlobalHandles::UpdateListOfNewSpaceNodes() {
    902   int last = 0;
    903   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    904     Node* node = new_space_nodes_[i];
    905     DCHECK(node->is_in_new_space_list());
    906     if (node->IsRetainer()) {
    907       if (isolate_->heap()->InNewSpace(node->object())) {
    908         new_space_nodes_[last++] = node;
    909         isolate_->heap()->IncrementNodesCopiedInNewSpace();
    910       } else {
    911         node->set_in_new_space_list(false);
    912         isolate_->heap()->IncrementNodesPromoted();
    913       }
    914     } else {
    915       node->set_in_new_space_list(false);
    916       isolate_->heap()->IncrementNodesDiedInNewSpace();
    917     }
    918   }
    919   new_space_nodes_.Rewind(last);
    920   new_space_nodes_.Trim();
    921 }
    922 
    923 
    924 int GlobalHandles::DispatchPendingPhantomCallbacks(
    925     bool synchronous_second_pass) {
    926   int freed_nodes = 0;
    927   {
    928     // The initial pass callbacks must simply clear the nodes.
    929     for (auto i = pending_phantom_callbacks_.begin();
    930          i != pending_phantom_callbacks_.end(); ++i) {
    931       auto callback = i;
    932       // Skip callbacks that have already been processed once.
    933       if (callback->node() == nullptr) continue;
    934       callback->Invoke(isolate());
    935       freed_nodes++;
    936     }
    937   }
    938   if (pending_phantom_callbacks_.length() > 0) {
    939     if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) {
    940       isolate()->heap()->CallGCPrologueCallbacks(
    941           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    942       InvokeSecondPassPhantomCallbacks(&pending_phantom_callbacks_, isolate());
    943       isolate()->heap()->CallGCEpilogueCallbacks(
    944           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    945     } else {
    946       auto task = new PendingPhantomCallbacksSecondPassTask(
    947           &pending_phantom_callbacks_, isolate());
    948       V8::GetCurrentPlatform()->CallOnForegroundThread(
    949           reinterpret_cast<v8::Isolate*>(isolate()), task);
    950     }
    951   }
    952   pending_phantom_callbacks_.Clear();
    953   return freed_nodes;
    954 }
    955 
    956 
    957 void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate) {
    958   Data::Callback* callback_addr = nullptr;
    959   if (node_ != nullptr) {
    960     // Initialize for first pass callback.
    961     DCHECK(node_->state() == Node::NEAR_DEATH);
    962     callback_addr = &callback_;
    963   }
    964   Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
    965             internal_fields_, callback_addr);
    966   Data::Callback callback = callback_;
    967   callback_ = nullptr;
    968   callback(data);
    969   if (node_ != nullptr) {
    970     // Transition to second pass state.
    971     DCHECK(node_->state() == Node::FREE);
    972     node_ = nullptr;
    973   }
    974 }
    975 
    976 
    977 int GlobalHandles::PostGarbageCollectionProcessing(
    978     GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
    979   // Process weak global handle callbacks. This must be done after the
    980   // GC is completely done, because the callbacks may invoke arbitrary
    981   // API functions.
    982   DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
    983   const int initial_post_gc_processing_count = ++post_gc_processing_count_;
    984   int freed_nodes = 0;
    985   bool synchronous_second_pass =
    986       (gc_callback_flags &
    987        (kGCCallbackFlagForced |
    988         kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
    989   freed_nodes += DispatchPendingPhantomCallbacks(synchronous_second_pass);
    990   if (initial_post_gc_processing_count != post_gc_processing_count_) {
    991     // If the callbacks caused a nested GC, then return.  See comment in
    992     // PostScavengeProcessing.
    993     return freed_nodes;
    994   }
    995   if (collector == SCAVENGER) {
    996     freed_nodes += PostScavengeProcessing(initial_post_gc_processing_count);
    997   } else {
    998     freed_nodes += PostMarkSweepProcessing(initial_post_gc_processing_count);
    999   }
   1000   if (initial_post_gc_processing_count != post_gc_processing_count_) {
   1001     // If the callbacks caused a nested GC, then return.  See comment in
   1002     // PostScavengeProcessing.
   1003     return freed_nodes;
   1004   }
   1005   if (initial_post_gc_processing_count == post_gc_processing_count_) {
   1006     UpdateListOfNewSpaceNodes();
   1007   }
   1008   return freed_nodes;
   1009 }
   1010 
   1011 
   1012 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
   1013   for (NodeIterator it(this); !it.done(); it.Advance()) {
   1014     if (it.node()->IsStrongRetainer()) {
   1015       v->VisitPointer(it.node()->location());
   1016     }
   1017   }
   1018 }
   1019 
   1020 
   1021 void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
   1022   for (NodeIterator it(this); !it.done(); it.Advance()) {
   1023     if (it.node()->IsRetainer()) {
   1024       v->VisitPointer(it.node()->location());
   1025     }
   1026   }
   1027 }
   1028 
   1029 
   1030 void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
   1031   for (NodeIterator it(this); !it.done(); it.Advance()) {
   1032     if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
   1033       v->VisitEmbedderReference(it.node()->location(),
   1034                                 it.node()->wrapper_class_id());
   1035     }
   1036   }
   1037 }
   1038 
   1039 
   1040 void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
   1041   for (int i = 0; i < new_space_nodes_.length(); ++i) {
   1042     Node* node = new_space_nodes_[i];
   1043     if (node->IsRetainer() && node->has_wrapper_class_id()) {
   1044       v->VisitEmbedderReference(node->location(),
   1045                                 node->wrapper_class_id());
   1046     }
   1047   }
   1048 }
   1049 
   1050 
   1051 void GlobalHandles::IterateWeakRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
   1052   for (int i = 0; i < new_space_nodes_.length(); ++i) {
   1053     Node* node = new_space_nodes_[i];
   1054     if (node->has_wrapper_class_id() && node->IsWeak()) {
   1055       v->VisitEmbedderReference(node->location(), node->wrapper_class_id());
   1056     }
   1057   }
   1058 }
   1059 
   1060 
   1061 int GlobalHandles::NumberOfWeakHandles() {
   1062   int count = 0;
   1063   for (NodeIterator it(this); !it.done(); it.Advance()) {
   1064     if (it.node()->IsWeakRetainer()) {
   1065       count++;
   1066     }
   1067   }
   1068   return count;
   1069 }
   1070 
   1071 
   1072 int GlobalHandles::NumberOfGlobalObjectWeakHandles() {
   1073   int count = 0;
   1074   for (NodeIterator it(this); !it.done(); it.Advance()) {
   1075     if (it.node()->IsWeakRetainer() &&
   1076         it.node()->object()->IsJSGlobalObject()) {
   1077       count++;
   1078     }
   1079   }
   1080   return count;
   1081 }
   1082 
   1083 
   1084 void GlobalHandles::RecordStats(HeapStats* stats) {
   1085   *stats->global_handle_count = 0;
   1086   *stats->weak_global_handle_count = 0;
   1087   *stats->pending_global_handle_count = 0;
   1088   *stats->near_death_global_handle_count = 0;
   1089   *stats->free_global_handle_count = 0;
   1090   for (NodeIterator it(this); !it.done(); it.Advance()) {
   1091     *stats->global_handle_count += 1;
   1092     if (it.node()->state() == Node::WEAK) {
   1093       *stats->weak_global_handle_count += 1;
   1094     } else if (it.node()->state() == Node::PENDING) {
   1095       *stats->pending_global_handle_count += 1;
   1096     } else if (it.node()->state() == Node::NEAR_DEATH) {
   1097       *stats->near_death_global_handle_count += 1;
   1098     } else if (it.node()->state() == Node::FREE) {
   1099       *stats->free_global_handle_count += 1;
   1100     }
   1101   }
   1102 }
   1103 
   1104 #ifdef DEBUG
   1105 
   1106 void GlobalHandles::PrintStats() {
   1107   int total = 0;
   1108   int weak = 0;
   1109   int pending = 0;
   1110   int near_death = 0;
   1111   int destroyed = 0;
   1112 
   1113   for (NodeIterator it(this); !it.done(); it.Advance()) {
   1114     total++;
   1115     if (it.node()->state() == Node::WEAK) weak++;
   1116     if (it.node()->state() == Node::PENDING) pending++;
   1117     if (it.node()->state() == Node::NEAR_DEATH) near_death++;
   1118     if (it.node()->state() == Node::FREE) destroyed++;
   1119   }
   1120 
   1121   PrintF("Global Handle Statistics:\n");
   1122   PrintF("  allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
   1123   PrintF("  # weak       = %d\n", weak);
   1124   PrintF("  # pending    = %d\n", pending);
   1125   PrintF("  # near_death = %d\n", near_death);
   1126   PrintF("  # free       = %d\n", destroyed);
   1127   PrintF("  # total      = %d\n", total);
   1128 }
   1129 
   1130 
   1131 void GlobalHandles::Print() {
   1132   PrintF("Global handles:\n");
   1133   for (NodeIterator it(this); !it.done(); it.Advance()) {
   1134     PrintF("  handle %p to %p%s\n",
   1135            reinterpret_cast<void*>(it.node()->location()),
   1136            reinterpret_cast<void*>(it.node()->object()),
   1137            it.node()->IsWeak() ? " (weak)" : "");
   1138   }
   1139 }
   1140 
   1141 #endif
   1142 
   1143 
   1144 
   1145 void GlobalHandles::AddObjectGroup(Object*** handles,
   1146                                    size_t length,
   1147                                    v8::RetainedObjectInfo* info) {
   1148 #ifdef DEBUG
   1149   for (size_t i = 0; i < length; ++i) {
   1150     DCHECK(!Node::FromLocation(handles[i])->is_independent());
   1151   }
   1152 #endif
   1153   if (length == 0) {
   1154     if (info != NULL) info->Dispose();
   1155     return;
   1156   }
   1157   ObjectGroup* group = new ObjectGroup(length);
   1158   for (size_t i = 0; i < length; ++i)
   1159     group->objects[i] = handles[i];
   1160   group->info = info;
   1161   object_groups_.Add(group);
   1162 }
   1163 
   1164 
   1165 void GlobalHandles::SetObjectGroupId(Object** handle,
   1166                                      UniqueId id) {
   1167   object_group_connections_.Add(ObjectGroupConnection(id, handle));
   1168 }
   1169 
   1170 
   1171 void GlobalHandles::SetRetainedObjectInfo(UniqueId id,
   1172                                           RetainedObjectInfo* info) {
   1173   retainer_infos_.Add(ObjectGroupRetainerInfo(id, info));
   1174 }
   1175 
   1176 
   1177 void GlobalHandles::SetReferenceFromGroup(UniqueId id, Object** child) {
   1178   DCHECK(!Node::FromLocation(child)->is_independent());
   1179   implicit_ref_connections_.Add(ObjectGroupConnection(id, child));
   1180 }
   1181 
   1182 
   1183 void GlobalHandles::SetReference(HeapObject** parent, Object** child) {
   1184   DCHECK(!Node::FromLocation(child)->is_independent());
   1185   ImplicitRefGroup* group = new ImplicitRefGroup(parent, 1);
   1186   group->children[0] = child;
   1187   implicit_ref_groups_.Add(group);
   1188 }
   1189 
   1190 
   1191 void GlobalHandles::RemoveObjectGroups() {
   1192   for (int i = 0; i < object_groups_.length(); i++)
   1193     delete object_groups_.at(i);
   1194   object_groups_.Clear();
   1195   for (int i = 0; i < retainer_infos_.length(); ++i)
   1196     retainer_infos_[i].info->Dispose();
   1197   retainer_infos_.Clear();
   1198   object_group_connections_.Clear();
   1199   object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
   1200 }
   1201 
   1202 
   1203 void GlobalHandles::RemoveImplicitRefGroups() {
   1204   for (int i = 0; i < implicit_ref_groups_.length(); i++) {
   1205     delete implicit_ref_groups_.at(i);
   1206   }
   1207   implicit_ref_groups_.Clear();
   1208   implicit_ref_connections_.Clear();
   1209 }
   1210 
   1211 
   1212 void GlobalHandles::TearDown() {
   1213   // TODO(1428): invoke weak callbacks.
   1214 }
   1215 
   1216 
   1217 void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() {
   1218   if (object_group_connections_.length() == 0) {
   1219     for (int i = 0; i < retainer_infos_.length(); ++i)
   1220       retainer_infos_[i].info->Dispose();
   1221     retainer_infos_.Clear();
   1222     implicit_ref_connections_.Clear();
   1223     return;
   1224   }
   1225 
   1226   object_group_connections_.Sort();
   1227   retainer_infos_.Sort();
   1228   implicit_ref_connections_.Sort();
   1229 
   1230   int info_index = 0;  // For iterating retainer_infos_.
   1231   UniqueId current_group_id(0);
   1232   int current_group_start = 0;
   1233 
   1234   int current_implicit_refs_start = 0;
   1235   int current_implicit_refs_end = 0;
   1236   for (int i = 0; i <= object_group_connections_.length(); ++i) {
   1237     if (i == 0)
   1238       current_group_id = object_group_connections_[i].id;
   1239     if (i == object_group_connections_.length() ||
   1240         current_group_id != object_group_connections_[i].id) {
   1241       // Group detected: objects in indices [current_group_start, i[.
   1242 
   1243       // Find out which implicit references are related to this group. (We want
   1244       // to ignore object groups which only have 1 object, but that object is
   1245       // needed as a representative object for the implicit refrerence group.)
   1246       while (current_implicit_refs_start < implicit_ref_connections_.length() &&
   1247              implicit_ref_connections_[current_implicit_refs_start].id <
   1248                  current_group_id)
   1249         ++current_implicit_refs_start;
   1250       current_implicit_refs_end = current_implicit_refs_start;
   1251       while (current_implicit_refs_end < implicit_ref_connections_.length() &&
   1252              implicit_ref_connections_[current_implicit_refs_end].id ==
   1253                  current_group_id)
   1254         ++current_implicit_refs_end;
   1255 
   1256       if (current_implicit_refs_end > current_implicit_refs_start) {
   1257         // Find a representative object for the implicit references.
   1258         HeapObject** representative = NULL;
   1259         for (int j = current_group_start; j < i; ++j) {
   1260           Object** object = object_group_connections_[j].object;
   1261           if ((*object)->IsHeapObject()) {
   1262             representative = reinterpret_cast<HeapObject**>(object);
   1263             break;
   1264           }
   1265         }
   1266         if (representative) {
   1267           ImplicitRefGroup* group = new ImplicitRefGroup(
   1268               representative,
   1269               current_implicit_refs_end - current_implicit_refs_start);
   1270           for (int j = current_implicit_refs_start;
   1271                j < current_implicit_refs_end;
   1272                ++j) {
   1273             group->children[j - current_implicit_refs_start] =
   1274                 implicit_ref_connections_[j].object;
   1275           }
   1276           implicit_ref_groups_.Add(group);
   1277         }
   1278         current_implicit_refs_start = current_implicit_refs_end;
   1279       }
   1280 
   1281       // Find a RetainedObjectInfo for the group.
   1282       RetainedObjectInfo* info = NULL;
   1283       while (info_index < retainer_infos_.length() &&
   1284              retainer_infos_[info_index].id < current_group_id) {
   1285         retainer_infos_[info_index].info->Dispose();
   1286         ++info_index;
   1287       }
   1288       if (info_index < retainer_infos_.length() &&
   1289           retainer_infos_[info_index].id == current_group_id) {
   1290         // This object group has an associated ObjectGroupRetainerInfo.
   1291         info = retainer_infos_[info_index].info;
   1292         ++info_index;
   1293       }
   1294 
   1295       // Ignore groups which only contain one object.
   1296       if (i > current_group_start + 1) {
   1297         ObjectGroup* group = new ObjectGroup(i - current_group_start);
   1298         for (int j = current_group_start; j < i; ++j) {
   1299           group->objects[j - current_group_start] =
   1300               object_group_connections_[j].object;
   1301         }
   1302         group->info = info;
   1303         object_groups_.Add(group);
   1304       } else if (info) {
   1305         info->Dispose();
   1306       }
   1307 
   1308       if (i < object_group_connections_.length()) {
   1309         current_group_id = object_group_connections_[i].id;
   1310         current_group_start = i;
   1311       }
   1312     }
   1313   }
   1314   object_group_connections_.Clear();
   1315   object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
   1316   retainer_infos_.Clear();
   1317   implicit_ref_connections_.Clear();
   1318 }
   1319 
   1320 
   1321 EternalHandles::EternalHandles() : size_(0) {
   1322   for (unsigned i = 0; i < arraysize(singleton_handles_); i++) {
   1323     singleton_handles_[i] = kInvalidIndex;
   1324   }
   1325 }
   1326 
   1327 
   1328 EternalHandles::~EternalHandles() {
   1329   for (int i = 0; i < blocks_.length(); i++) delete[] blocks_[i];
   1330 }
   1331 
   1332 
   1333 void EternalHandles::IterateAllRoots(ObjectVisitor* visitor) {
   1334   int limit = size_;
   1335   for (int i = 0; i < blocks_.length(); i++) {
   1336     DCHECK(limit > 0);
   1337     Object** block = blocks_[i];
   1338     visitor->VisitPointers(block, block + Min(limit, kSize));
   1339     limit -= kSize;
   1340   }
   1341 }
   1342 
   1343 
   1344 void EternalHandles::IterateNewSpaceRoots(ObjectVisitor* visitor) {
   1345   for (int i = 0; i < new_space_indices_.length(); i++) {
   1346     visitor->VisitPointer(GetLocation(new_space_indices_[i]));
   1347   }
   1348 }
   1349 
   1350 
   1351 void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) {
   1352   int last = 0;
   1353   for (int i = 0; i < new_space_indices_.length(); i++) {
   1354     int index = new_space_indices_[i];
   1355     if (heap->InNewSpace(*GetLocation(index))) {
   1356       new_space_indices_[last++] = index;
   1357     }
   1358   }
   1359   new_space_indices_.Rewind(last);
   1360 }
   1361 
   1362 
   1363 void EternalHandles::Create(Isolate* isolate, Object* object, int* index) {
   1364   DCHECK_EQ(kInvalidIndex, *index);
   1365   if (object == NULL) return;
   1366   DCHECK_NE(isolate->heap()->the_hole_value(), object);
   1367   int block = size_ >> kShift;
   1368   int offset = size_ & kMask;
   1369   // need to resize
   1370   if (offset == 0) {
   1371     Object** next_block = new Object*[kSize];
   1372     Object* the_hole = isolate->heap()->the_hole_value();
   1373     MemsetPointer(next_block, the_hole, kSize);
   1374     blocks_.Add(next_block);
   1375   }
   1376   DCHECK_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]);
   1377   blocks_[block][offset] = object;
   1378   if (isolate->heap()->InNewSpace(object)) {
   1379     new_space_indices_.Add(size_);
   1380   }
   1381   *index = size_++;
   1382 }
   1383 
   1384 
   1385 }  // namespace internal
   1386 }  // namespace v8
   1387