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