Home | History | Annotate | Download | only in src
      1 // Copyright 2009 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "api.h"
     31 #include "global-handles.h"
     32 
     33 #include "vm-state-inl.h"
     34 
     35 namespace v8 {
     36 namespace internal {
     37 
     38 
     39 ObjectGroup::~ObjectGroup() {
     40   if (info != NULL) info->Dispose();
     41   delete[] objects;
     42 }
     43 
     44 
     45 ImplicitRefGroup::~ImplicitRefGroup() {
     46   delete[] children;
     47 }
     48 
     49 
     50 class GlobalHandles::Node {
     51  public:
     52   // State transition diagram:
     53   // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
     54   enum State {
     55     FREE = 0,
     56     NORMAL,     // Normal global handle.
     57     WEAK,       // Flagged as weak but not yet finalized.
     58     PENDING,    // Has been recognized as only reachable by weak handles.
     59     NEAR_DEATH  // Callback has informed the handle is near death.
     60   };
     61 
     62   // Maps handle location (slot) to the containing node.
     63   static Node* FromLocation(Object** location) {
     64     ASSERT(OFFSET_OF(Node, object_) == 0);
     65     return reinterpret_cast<Node*>(location);
     66   }
     67 
     68   Node() {
     69     ASSERT(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset);
     70     ASSERT(OFFSET_OF(Node, flags_) == Internals::kNodeFlagsOffset);
     71     STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
     72                   Internals::kNodeStateMask);
     73     STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
     74     STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
     75     STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
     76     STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
     77                   Internals::kNodeIsIndependentShift);
     78     STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
     79                   Internals::kNodeIsPartiallyDependentShift);
     80   }
     81 
     82 #ifdef ENABLE_HANDLE_ZAPPING
     83   ~Node() {
     84     // TODO(1428): if it's a weak handle we should have invoked its callback.
     85     // Zap the values for eager trapping.
     86     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
     87     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
     88     index_ = 0;
     89     set_independent(false);
     90     set_partially_dependent(false);
     91     set_in_new_space_list(false);
     92     parameter_or_next_free_.next_free = NULL;
     93     weak_callback_ = NULL;
     94   }
     95 #endif
     96 
     97   void Initialize(int index, Node** first_free) {
     98     index_ = static_cast<uint8_t>(index);
     99     ASSERT(static_cast<int>(index_) == index);
    100     set_state(FREE);
    101     set_in_new_space_list(false);
    102     parameter_or_next_free_.next_free = *first_free;
    103     *first_free = this;
    104   }
    105 
    106   void Acquire(Object* object) {
    107     ASSERT(state() == FREE);
    108     object_ = object;
    109     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
    110     set_independent(false);
    111     set_partially_dependent(false);
    112     set_state(NORMAL);
    113     parameter_or_next_free_.parameter = NULL;
    114     weak_callback_ = NULL;
    115     IncreaseBlockUses();
    116   }
    117 
    118   void Release() {
    119     ASSERT(state() != FREE);
    120     set_state(FREE);
    121     // Zap the values for eager trapping.
    122     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
    123     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
    124     set_independent(false);
    125     set_partially_dependent(false);
    126     weak_callback_ = NULL;
    127     DecreaseBlockUses();
    128   }
    129 
    130   // Object slot accessors.
    131   Object* object() const { return object_; }
    132   Object** location() { return &object_; }
    133   Handle<Object> handle() { return Handle<Object>(location()); }
    134 
    135   // Wrapper class ID accessors.
    136   bool has_wrapper_class_id() const {
    137     return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
    138   }
    139 
    140   uint16_t wrapper_class_id() const { return class_id_; }
    141 
    142   // State and flag accessors.
    143 
    144   State state() const {
    145     return NodeState::decode(flags_);
    146   }
    147   void set_state(State state) {
    148     flags_ = NodeState::update(flags_, state);
    149   }
    150 
    151   bool is_independent() {
    152     return IsIndependent::decode(flags_);
    153   }
    154   void set_independent(bool v) {
    155     flags_ = IsIndependent::update(flags_, v);
    156   }
    157 
    158   bool is_partially_dependent() {
    159     return IsPartiallyDependent::decode(flags_);
    160   }
    161   void set_partially_dependent(bool v) {
    162     flags_ = IsPartiallyDependent::update(flags_, v);
    163   }
    164 
    165   bool is_in_new_space_list() {
    166     return IsInNewSpaceList::decode(flags_);
    167   }
    168   void set_in_new_space_list(bool v) {
    169     flags_ = IsInNewSpaceList::update(flags_, v);
    170   }
    171 
    172   bool is_revivable_callback() {
    173     return IsRevivableCallback::decode(flags_);
    174   }
    175   void set_revivable_callback(bool v) {
    176     flags_ = IsRevivableCallback::update(flags_, v);
    177   }
    178 
    179   bool IsNearDeath() const {
    180     // Check for PENDING to ensure correct answer when processing callbacks.
    181     return state() == PENDING || state() == NEAR_DEATH;
    182   }
    183 
    184   bool IsWeak() const { return state() == WEAK; }
    185 
    186   bool IsRetainer() const { return state() != FREE; }
    187 
    188   bool IsStrongRetainer() const { return state() == NORMAL; }
    189 
    190   bool IsWeakRetainer() const {
    191     return state() == WEAK || state() == PENDING || state() == NEAR_DEATH;
    192   }
    193 
    194   void MarkPending() {
    195     ASSERT(state() == WEAK);
    196     set_state(PENDING);
    197   }
    198 
    199   // Independent flag accessors.
    200   void MarkIndependent() {
    201     ASSERT(state() != FREE);
    202     set_independent(true);
    203   }
    204 
    205   void MarkPartiallyDependent() {
    206     ASSERT(state() != FREE);
    207     if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
    208       set_partially_dependent(true);
    209     }
    210   }
    211   void clear_partially_dependent() { set_partially_dependent(false); }
    212 
    213   // Callback accessor.
    214   // TODO(svenpanne) Re-enable or nuke later.
    215   // WeakReferenceCallback callback() { return callback_; }
    216 
    217   // Callback parameter accessors.
    218   void set_parameter(void* parameter) {
    219     ASSERT(state() != FREE);
    220     parameter_or_next_free_.parameter = parameter;
    221   }
    222   void* parameter() const {
    223     ASSERT(state() != FREE);
    224     return parameter_or_next_free_.parameter;
    225   }
    226 
    227   // Accessors for next free node in the free list.
    228   Node* next_free() {
    229     ASSERT(state() == FREE);
    230     return parameter_or_next_free_.next_free;
    231   }
    232   void set_next_free(Node* value) {
    233     ASSERT(state() == FREE);
    234     parameter_or_next_free_.next_free = value;
    235   }
    236 
    237   void MakeWeak(void* parameter,
    238                 WeakCallback weak_callback,
    239                 RevivableCallback revivable_callback) {
    240     ASSERT((weak_callback == NULL) != (revivable_callback == NULL));
    241     ASSERT(state() != FREE);
    242     set_state(WEAK);
    243     set_parameter(parameter);
    244     if (weak_callback != NULL) {
    245       weak_callback_ = weak_callback;
    246       set_revivable_callback(false);
    247     } else {
    248       weak_callback_ =
    249           reinterpret_cast<WeakCallback>(revivable_callback);
    250       set_revivable_callback(true);
    251     }
    252   }
    253 
    254   void ClearWeakness() {
    255     ASSERT(state() != FREE);
    256     set_state(NORMAL);
    257     set_parameter(NULL);
    258   }
    259 
    260   bool PostGarbageCollectionProcessing(Isolate* isolate) {
    261     if (state() != Node::PENDING) return false;
    262     if (weak_callback_ == NULL) {
    263       Release();
    264       return false;
    265     }
    266     void* par = parameter();
    267     set_state(NEAR_DEATH);
    268     set_parameter(NULL);
    269 
    270     Object** object = location();
    271     {
    272       // Check that we are not passing a finalized external string to
    273       // the callback.
    274       ASSERT(!object_->IsExternalAsciiString() ||
    275              ExternalAsciiString::cast(object_)->resource() != NULL);
    276       ASSERT(!object_->IsExternalTwoByteString() ||
    277              ExternalTwoByteString::cast(object_)->resource() != NULL);
    278       // Leaving V8.
    279       VMState<EXTERNAL> state(isolate);
    280       HandleScope handle_scope(isolate);
    281       if (is_revivable_callback()) {
    282         RevivableCallback revivable =
    283             reinterpret_cast<RevivableCallback>(weak_callback_);
    284         revivable(reinterpret_cast<v8::Isolate*>(isolate),
    285                   reinterpret_cast<Persistent<Value>*>(&object),
    286                   par);
    287       } else {
    288         Handle<Object> handle(*object, isolate);
    289         v8::WeakCallbackData<v8::Value, void> data(
    290             reinterpret_cast<v8::Isolate*>(isolate),
    291             v8::Utils::ToLocal(handle),
    292             par);
    293         weak_callback_(data);
    294       }
    295     }
    296     // Absence of explicit cleanup or revival of weak handle
    297     // in most of the cases would lead to memory leak.
    298     ASSERT(state() != NEAR_DEATH);
    299     return true;
    300   }
    301 
    302   inline GlobalHandles* GetGlobalHandles();
    303 
    304  private:
    305   inline NodeBlock* FindBlock();
    306   inline void IncreaseBlockUses();
    307   inline void DecreaseBlockUses();
    308 
    309   // Storage for object pointer.
    310   // Placed first to avoid offset computation.
    311   Object* object_;
    312 
    313   // Next word stores class_id, index, state, and independent.
    314   // Note: the most aligned fields should go first.
    315 
    316   // Wrapper class ID.
    317   uint16_t class_id_;
    318 
    319   // Index in the containing handle block.
    320   uint8_t index_;
    321 
    322   // This stores three flags (independent, partially_dependent and
    323   // in_new_space_list) and a State.
    324   class NodeState:            public BitField<State, 0, 4> {};
    325   class IsIndependent:        public BitField<bool,  4, 1> {};
    326   class IsPartiallyDependent: public BitField<bool,  5, 1> {};
    327   class IsInNewSpaceList:     public BitField<bool,  6, 1> {};
    328   class IsRevivableCallback:  public BitField<bool,  7, 1> {};
    329 
    330   uint8_t flags_;
    331 
    332   // Handle specific callback - might be a weak reference in disguise.
    333   WeakCallback weak_callback_;
    334 
    335   // Provided data for callback.  In FREE state, this is used for
    336   // the free list link.
    337   union {
    338     void* parameter;
    339     Node* next_free;
    340   } parameter_or_next_free_;
    341 
    342   DISALLOW_COPY_AND_ASSIGN(Node);
    343 };
    344 
    345 
    346 class GlobalHandles::NodeBlock {
    347  public:
    348   static const int kSize = 256;
    349 
    350   explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
    351       : next_(next),
    352         used_nodes_(0),
    353         next_used_(NULL),
    354         prev_used_(NULL),
    355         global_handles_(global_handles) {}
    356 
    357   void PutNodesOnFreeList(Node** first_free) {
    358     for (int i = kSize - 1; i >= 0; --i) {
    359       nodes_[i].Initialize(i, first_free);
    360     }
    361   }
    362 
    363   Node* node_at(int index) {
    364     ASSERT(0 <= index && index < kSize);
    365     return &nodes_[index];
    366   }
    367 
    368   void IncreaseUses() {
    369     ASSERT(used_nodes_ < kSize);
    370     if (used_nodes_++ == 0) {
    371       NodeBlock* old_first = global_handles_->first_used_block_;
    372       global_handles_->first_used_block_ = this;
    373       next_used_ = old_first;
    374       prev_used_ = NULL;
    375       if (old_first == NULL) return;
    376       old_first->prev_used_ = this;
    377     }
    378   }
    379 
    380   void DecreaseUses() {
    381     ASSERT(used_nodes_ > 0);
    382     if (--used_nodes_ == 0) {
    383       if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
    384       if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
    385       if (this == global_handles_->first_used_block_) {
    386         global_handles_->first_used_block_ = next_used_;
    387       }
    388     }
    389   }
    390 
    391   GlobalHandles* global_handles() { return global_handles_; }
    392 
    393   // Next block in the list of all blocks.
    394   NodeBlock* next() const { return next_; }
    395 
    396   // Next/previous block in the list of blocks with used nodes.
    397   NodeBlock* next_used() const { return next_used_; }
    398   NodeBlock* prev_used() const { return prev_used_; }
    399 
    400  private:
    401   Node nodes_[kSize];
    402   NodeBlock* const next_;
    403   int used_nodes_;
    404   NodeBlock* next_used_;
    405   NodeBlock* prev_used_;
    406   GlobalHandles* global_handles_;
    407 };
    408 
    409 
    410 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
    411   return FindBlock()->global_handles();
    412 }
    413 
    414 
    415 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
    416   intptr_t ptr = reinterpret_cast<intptr_t>(this);
    417   ptr = ptr - index_ * sizeof(Node);
    418   NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
    419   ASSERT(block->node_at(index_) == this);
    420   return block;
    421 }
    422 
    423 
    424 void GlobalHandles::Node::IncreaseBlockUses() {
    425   NodeBlock* node_block = FindBlock();
    426   node_block->IncreaseUses();
    427   GlobalHandles* global_handles = node_block->global_handles();
    428   global_handles->isolate()->counters()->global_handles()->Increment();
    429   global_handles->number_of_global_handles_++;
    430 }
    431 
    432 
    433 void GlobalHandles::Node::DecreaseBlockUses() {
    434   NodeBlock* node_block = FindBlock();
    435   GlobalHandles* global_handles = node_block->global_handles();
    436   parameter_or_next_free_.next_free = global_handles->first_free_;
    437   global_handles->first_free_ = this;
    438   node_block->DecreaseUses();
    439   global_handles->isolate()->counters()->global_handles()->Decrement();
    440   global_handles->number_of_global_handles_--;
    441 }
    442 
    443 
    444 class GlobalHandles::NodeIterator {
    445  public:
    446   explicit NodeIterator(GlobalHandles* global_handles)
    447       : block_(global_handles->first_used_block_),
    448         index_(0) {}
    449 
    450   bool done() const { return block_ == NULL; }
    451 
    452   Node* node() const {
    453     ASSERT(!done());
    454     return block_->node_at(index_);
    455   }
    456 
    457   void Advance() {
    458     ASSERT(!done());
    459     if (++index_ < NodeBlock::kSize) return;
    460     index_ = 0;
    461     block_ = block_->next_used();
    462   }
    463 
    464  private:
    465   NodeBlock* block_;
    466   int index_;
    467 
    468   DISALLOW_COPY_AND_ASSIGN(NodeIterator);
    469 };
    470 
    471 
    472 GlobalHandles::GlobalHandles(Isolate* isolate)
    473     : isolate_(isolate),
    474       number_of_global_handles_(0),
    475       first_block_(NULL),
    476       first_used_block_(NULL),
    477       first_free_(NULL),
    478       post_gc_processing_count_(0),
    479       object_group_connections_(kObjectGroupConnectionsCapacity) {}
    480 
    481 
    482 GlobalHandles::~GlobalHandles() {
    483   NodeBlock* block = first_block_;
    484   while (block != NULL) {
    485     NodeBlock* tmp = block->next();
    486     delete block;
    487     block = tmp;
    488   }
    489   first_block_ = NULL;
    490 }
    491 
    492 
    493 Handle<Object> GlobalHandles::Create(Object* value) {
    494   if (first_free_ == NULL) {
    495     first_block_ = new NodeBlock(this, first_block_);
    496     first_block_->PutNodesOnFreeList(&first_free_);
    497   }
    498   ASSERT(first_free_ != NULL);
    499   // Take the first node in the free list.
    500   Node* result = first_free_;
    501   first_free_ = result->next_free();
    502   result->Acquire(value);
    503   if (isolate_->heap()->InNewSpace(value) &&
    504       !result->is_in_new_space_list()) {
    505     new_space_nodes_.Add(result);
    506     result->set_in_new_space_list(true);
    507   }
    508   return result->handle();
    509 }
    510 
    511 
    512 Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
    513   ASSERT(location != NULL);
    514   return Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
    515 }
    516 
    517 
    518 void GlobalHandles::Destroy(Object** location) {
    519   if (location != NULL) Node::FromLocation(location)->Release();
    520 }
    521 
    522 
    523 void GlobalHandles::MakeWeak(Object** location,
    524                              void* parameter,
    525                              WeakCallback weak_callback,
    526                              RevivableCallback revivable_callback) {
    527   Node::FromLocation(location)->MakeWeak(
    528       parameter, weak_callback, revivable_callback);
    529 }
    530 
    531 
    532 void GlobalHandles::ClearWeakness(Object** location) {
    533   Node::FromLocation(location)->ClearWeakness();
    534 }
    535 
    536 
    537 void GlobalHandles::MarkIndependent(Object** location) {
    538   Node::FromLocation(location)->MarkIndependent();
    539 }
    540 
    541 
    542 void GlobalHandles::MarkPartiallyDependent(Object** location) {
    543   Node::FromLocation(location)->MarkPartiallyDependent();
    544 }
    545 
    546 
    547 bool GlobalHandles::IsIndependent(Object** location) {
    548   return Node::FromLocation(location)->is_independent();
    549 }
    550 
    551 
    552 bool GlobalHandles::IsNearDeath(Object** location) {
    553   return Node::FromLocation(location)->IsNearDeath();
    554 }
    555 
    556 
    557 bool GlobalHandles::IsWeak(Object** location) {
    558   return Node::FromLocation(location)->IsWeak();
    559 }
    560 
    561 
    562 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
    563   for (NodeIterator it(this); !it.done(); it.Advance()) {
    564     if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location());
    565   }
    566 }
    567 
    568 
    569 void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
    570   for (NodeIterator it(this); !it.done(); it.Advance()) {
    571     if (it.node()->IsWeak() && f(it.node()->location())) {
    572       it.node()->MarkPending();
    573     }
    574   }
    575 }
    576 
    577 
    578 void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
    579   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    580     Node* node = new_space_nodes_[i];
    581     if (node->IsStrongRetainer() ||
    582         (node->IsWeakRetainer() && !node->is_independent() &&
    583          !node->is_partially_dependent())) {
    584         v->VisitPointer(node->location());
    585     }
    586   }
    587 }
    588 
    589 
    590 void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles(
    591     WeakSlotCallbackWithHeap f) {
    592   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    593     Node* node = new_space_nodes_[i];
    594     ASSERT(node->is_in_new_space_list());
    595     if ((node->is_independent() || node->is_partially_dependent()) &&
    596         node->IsWeak() && f(isolate_->heap(), node->location())) {
    597       node->MarkPending();
    598     }
    599   }
    600 }
    601 
    602 
    603 void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
    604   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    605     Node* node = new_space_nodes_[i];
    606     ASSERT(node->is_in_new_space_list());
    607     if ((node->is_independent() || node->is_partially_dependent()) &&
    608         node->IsWeakRetainer()) {
    609       v->VisitPointer(node->location());
    610     }
    611   }
    612 }
    613 
    614 
    615 bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
    616                                         WeakSlotCallbackWithHeap can_skip) {
    617   ComputeObjectGroupsAndImplicitReferences();
    618   int last = 0;
    619   bool any_group_was_visited = false;
    620   for (int i = 0; i < object_groups_.length(); i++) {
    621     ObjectGroup* entry = object_groups_.at(i);
    622     ASSERT(entry != NULL);
    623 
    624     Object*** objects = entry->objects;
    625     bool group_should_be_visited = false;
    626     for (size_t j = 0; j < entry->length; j++) {
    627       Object* object = *objects[j];
    628       if (object->IsHeapObject()) {
    629         if (!can_skip(isolate_->heap(), &object)) {
    630           group_should_be_visited = true;
    631           break;
    632         }
    633       }
    634     }
    635 
    636     if (!group_should_be_visited) {
    637       object_groups_[last++] = entry;
    638       continue;
    639     }
    640 
    641     // An object in the group requires visiting, so iterate over all
    642     // objects in the group.
    643     for (size_t j = 0; j < entry->length; ++j) {
    644       Object* object = *objects[j];
    645       if (object->IsHeapObject()) {
    646         v->VisitPointer(&object);
    647         any_group_was_visited = true;
    648       }
    649     }
    650 
    651     // Once the entire group has been iterated over, set the object
    652     // group to NULL so it won't be processed again.
    653     delete entry;
    654     object_groups_.at(i) = NULL;
    655   }
    656   object_groups_.Rewind(last);
    657   return any_group_was_visited;
    658 }
    659 
    660 
    661 bool GlobalHandles::PostGarbageCollectionProcessing(
    662     GarbageCollector collector, GCTracer* tracer) {
    663   // Process weak global handle callbacks. This must be done after the
    664   // GC is completely done, because the callbacks may invoke arbitrary
    665   // API functions.
    666   ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
    667   const int initial_post_gc_processing_count = ++post_gc_processing_count_;
    668   bool next_gc_likely_to_collect_more = false;
    669   if (collector == SCAVENGER) {
    670     for (int i = 0; i < new_space_nodes_.length(); ++i) {
    671       Node* node = new_space_nodes_[i];
    672       ASSERT(node->is_in_new_space_list());
    673       if (!node->IsRetainer()) {
    674         // Free nodes do not have weak callbacks. Do not use them to compute
    675         // the next_gc_likely_to_collect_more.
    676         continue;
    677       }
    678       // Skip dependent handles. Their weak callbacks might expect to be
    679       // called between two global garbage collection callbacks which
    680       // are not called for minor collections.
    681       if (!node->is_independent() && !node->is_partially_dependent()) {
    682         continue;
    683       }
    684       node->clear_partially_dependent();
    685       if (node->PostGarbageCollectionProcessing(isolate_)) {
    686         if (initial_post_gc_processing_count != post_gc_processing_count_) {
    687           // Weak callback triggered another GC and another round of
    688           // PostGarbageCollection processing.  The current node might
    689           // have been deleted in that round, so we need to bail out (or
    690           // restart the processing).
    691           return next_gc_likely_to_collect_more;
    692         }
    693       }
    694       if (!node->IsRetainer()) {
    695         next_gc_likely_to_collect_more = true;
    696       }
    697     }
    698   } else {
    699     for (NodeIterator it(this); !it.done(); it.Advance()) {
    700       if (!it.node()->IsRetainer()) {
    701         // Free nodes do not have weak callbacks. Do not use them to compute
    702         // the next_gc_likely_to_collect_more.
    703         continue;
    704       }
    705       it.node()->clear_partially_dependent();
    706       if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
    707         if (initial_post_gc_processing_count != post_gc_processing_count_) {
    708           // See the comment above.
    709           return next_gc_likely_to_collect_more;
    710         }
    711       }
    712       if (!it.node()->IsRetainer()) {
    713         next_gc_likely_to_collect_more = true;
    714       }
    715     }
    716   }
    717   // Update the list of new space nodes.
    718   int last = 0;
    719   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    720     Node* node = new_space_nodes_[i];
    721     ASSERT(node->is_in_new_space_list());
    722     if (node->IsRetainer()) {
    723       if (isolate_->heap()->InNewSpace(node->object())) {
    724         new_space_nodes_[last++] = node;
    725         tracer->increment_nodes_copied_in_new_space();
    726       } else {
    727         node->set_in_new_space_list(false);
    728         tracer->increment_nodes_promoted();
    729       }
    730     } else {
    731       node->set_in_new_space_list(false);
    732       tracer->increment_nodes_died_in_new_space();
    733     }
    734   }
    735   new_space_nodes_.Rewind(last);
    736   return next_gc_likely_to_collect_more;
    737 }
    738 
    739 
    740 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
    741   for (NodeIterator it(this); !it.done(); it.Advance()) {
    742     if (it.node()->IsStrongRetainer()) {
    743       v->VisitPointer(it.node()->location());
    744     }
    745   }
    746 }
    747 
    748 
    749 void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
    750   for (NodeIterator it(this); !it.done(); it.Advance()) {
    751     if (it.node()->IsRetainer()) {
    752       v->VisitPointer(it.node()->location());
    753     }
    754   }
    755 }
    756 
    757 
    758 void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
    759   for (NodeIterator it(this); !it.done(); it.Advance()) {
    760     if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
    761       v->VisitEmbedderReference(it.node()->location(),
    762                                 it.node()->wrapper_class_id());
    763     }
    764   }
    765 }
    766 
    767 
    768 void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
    769   for (int i = 0; i < new_space_nodes_.length(); ++i) {
    770     Node* node = new_space_nodes_[i];
    771     if (node->IsRetainer() && node->has_wrapper_class_id()) {
    772       v->VisitEmbedderReference(node->location(),
    773                                 node->wrapper_class_id());
    774     }
    775   }
    776 }
    777 
    778 
    779 int GlobalHandles::NumberOfWeakHandles() {
    780   int count = 0;
    781   for (NodeIterator it(this); !it.done(); it.Advance()) {
    782     if (it.node()->IsWeakRetainer()) {
    783       count++;
    784     }
    785   }
    786   return count;
    787 }
    788 
    789 
    790 int GlobalHandles::NumberOfGlobalObjectWeakHandles() {
    791   int count = 0;
    792   for (NodeIterator it(this); !it.done(); it.Advance()) {
    793     if (it.node()->IsWeakRetainer() &&
    794         it.node()->object()->IsJSGlobalObject()) {
    795       count++;
    796     }
    797   }
    798   return count;
    799 }
    800 
    801 
    802 void GlobalHandles::RecordStats(HeapStats* stats) {
    803   *stats->global_handle_count = 0;
    804   *stats->weak_global_handle_count = 0;
    805   *stats->pending_global_handle_count = 0;
    806   *stats->near_death_global_handle_count = 0;
    807   *stats->free_global_handle_count = 0;
    808   for (NodeIterator it(this); !it.done(); it.Advance()) {
    809     *stats->global_handle_count += 1;
    810     if (it.node()->state() == Node::WEAK) {
    811       *stats->weak_global_handle_count += 1;
    812     } else if (it.node()->state() == Node::PENDING) {
    813       *stats->pending_global_handle_count += 1;
    814     } else if (it.node()->state() == Node::NEAR_DEATH) {
    815       *stats->near_death_global_handle_count += 1;
    816     } else if (it.node()->state() == Node::FREE) {
    817       *stats->free_global_handle_count += 1;
    818     }
    819   }
    820 }
    821 
    822 #ifdef DEBUG
    823 
    824 void GlobalHandles::PrintStats() {
    825   int total = 0;
    826   int weak = 0;
    827   int pending = 0;
    828   int near_death = 0;
    829   int destroyed = 0;
    830 
    831   for (NodeIterator it(this); !it.done(); it.Advance()) {
    832     total++;
    833     if (it.node()->state() == Node::WEAK) weak++;
    834     if (it.node()->state() == Node::PENDING) pending++;
    835     if (it.node()->state() == Node::NEAR_DEATH) near_death++;
    836     if (it.node()->state() == Node::FREE) destroyed++;
    837   }
    838 
    839   PrintF("Global Handle Statistics:\n");
    840   PrintF("  allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
    841   PrintF("  # weak       = %d\n", weak);
    842   PrintF("  # pending    = %d\n", pending);
    843   PrintF("  # near_death = %d\n", near_death);
    844   PrintF("  # free       = %d\n", destroyed);
    845   PrintF("  # total      = %d\n", total);
    846 }
    847 
    848 
    849 void GlobalHandles::Print() {
    850   PrintF("Global handles:\n");
    851   for (NodeIterator it(this); !it.done(); it.Advance()) {
    852     PrintF("  handle %p to %p%s\n",
    853            reinterpret_cast<void*>(it.node()->location()),
    854            reinterpret_cast<void*>(it.node()->object()),
    855            it.node()->IsWeak() ? " (weak)" : "");
    856   }
    857 }
    858 
    859 #endif
    860 
    861 
    862 
    863 void GlobalHandles::AddObjectGroup(Object*** handles,
    864                                    size_t length,
    865                                    v8::RetainedObjectInfo* info) {
    866 #ifdef DEBUG
    867   for (size_t i = 0; i < length; ++i) {
    868     ASSERT(!Node::FromLocation(handles[i])->is_independent());
    869   }
    870 #endif
    871   if (length == 0) {
    872     if (info != NULL) info->Dispose();
    873     return;
    874   }
    875   ObjectGroup* group = new ObjectGroup(length);
    876   for (size_t i = 0; i < length; ++i)
    877     group->objects[i] = handles[i];
    878   group->info = info;
    879   object_groups_.Add(group);
    880 }
    881 
    882 
    883 void GlobalHandles::SetObjectGroupId(Object** handle,
    884                                      UniqueId id) {
    885   object_group_connections_.Add(ObjectGroupConnection(id, handle));
    886 }
    887 
    888 
    889 void GlobalHandles::SetRetainedObjectInfo(UniqueId id,
    890                                           RetainedObjectInfo* info) {
    891   retainer_infos_.Add(ObjectGroupRetainerInfo(id, info));
    892 }
    893 
    894 
    895 void GlobalHandles::AddImplicitReferences(HeapObject** parent,
    896                                           Object*** children,
    897                                           size_t length) {
    898 #ifdef DEBUG
    899   ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->is_independent());
    900   for (size_t i = 0; i < length; ++i) {
    901     ASSERT(!Node::FromLocation(children[i])->is_independent());
    902   }
    903 #endif
    904   if (length == 0) return;
    905   ImplicitRefGroup* group = new ImplicitRefGroup(parent, length);
    906   for (size_t i = 0; i < length; ++i)
    907     group->children[i] = children[i];
    908   implicit_ref_groups_.Add(group);
    909 }
    910 
    911 
    912 void GlobalHandles::SetReferenceFromGroup(UniqueId id, Object** child) {
    913   ASSERT(!Node::FromLocation(child)->is_independent());
    914   implicit_ref_connections_.Add(ObjectGroupConnection(id, child));
    915 }
    916 
    917 
    918 void GlobalHandles::SetReference(HeapObject** parent, Object** child) {
    919   ASSERT(!Node::FromLocation(child)->is_independent());
    920   ImplicitRefGroup* group = new ImplicitRefGroup(parent, 1);
    921   group->children[0] = child;
    922   implicit_ref_groups_.Add(group);
    923 }
    924 
    925 
    926 void GlobalHandles::RemoveObjectGroups() {
    927   for (int i = 0; i < object_groups_.length(); i++)
    928     delete object_groups_.at(i);
    929   object_groups_.Clear();
    930   for (int i = 0; i < retainer_infos_.length(); ++i)
    931     retainer_infos_[i].info->Dispose();
    932   retainer_infos_.Clear();
    933   object_group_connections_.Clear();
    934   object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
    935 }
    936 
    937 
    938 void GlobalHandles::RemoveImplicitRefGroups() {
    939   for (int i = 0; i < implicit_ref_groups_.length(); i++) {
    940     delete implicit_ref_groups_.at(i);
    941   }
    942   implicit_ref_groups_.Clear();
    943   implicit_ref_connections_.Clear();
    944 }
    945 
    946 
    947 void GlobalHandles::TearDown() {
    948   // TODO(1428): invoke weak callbacks.
    949 }
    950 
    951 
    952 void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() {
    953   if (object_group_connections_.length() == 0) {
    954     for (int i = 0; i < retainer_infos_.length(); ++i)
    955       retainer_infos_[i].info->Dispose();
    956     retainer_infos_.Clear();
    957     implicit_ref_connections_.Clear();
    958     return;
    959   }
    960 
    961   object_group_connections_.Sort();
    962   retainer_infos_.Sort();
    963   implicit_ref_connections_.Sort();
    964 
    965   int info_index = 0;  // For iterating retainer_infos_.
    966   UniqueId current_group_id(0);
    967   int current_group_start = 0;
    968 
    969   int current_implicit_refs_start = 0;
    970   int current_implicit_refs_end = 0;
    971   for (int i = 0; i <= object_group_connections_.length(); ++i) {
    972     if (i == 0)
    973       current_group_id = object_group_connections_[i].id;
    974     if (i == object_group_connections_.length() ||
    975         current_group_id != object_group_connections_[i].id) {
    976       // Group detected: objects in indices [current_group_start, i[.
    977 
    978       // Find out which implicit references are related to this group. (We want
    979       // to ignore object groups which only have 1 object, but that object is
    980       // needed as a representative object for the implicit refrerence group.)
    981       while (current_implicit_refs_start < implicit_ref_connections_.length() &&
    982              implicit_ref_connections_[current_implicit_refs_start].id <
    983                  current_group_id)
    984         ++current_implicit_refs_start;
    985       current_implicit_refs_end = current_implicit_refs_start;
    986       while (current_implicit_refs_end < implicit_ref_connections_.length() &&
    987              implicit_ref_connections_[current_implicit_refs_end].id ==
    988                  current_group_id)
    989         ++current_implicit_refs_end;
    990 
    991       if (current_implicit_refs_end > current_implicit_refs_start) {
    992         // Find a representative object for the implicit references.
    993         HeapObject** representative = NULL;
    994         for (int j = current_group_start; j < i; ++j) {
    995           Object** object = object_group_connections_[j].object;
    996           if ((*object)->IsHeapObject()) {
    997             representative = reinterpret_cast<HeapObject**>(object);
    998             break;
    999           }
   1000         }
   1001         if (representative) {
   1002           ImplicitRefGroup* group = new ImplicitRefGroup(
   1003               representative,
   1004               current_implicit_refs_end - current_implicit_refs_start);
   1005           for (int j = current_implicit_refs_start;
   1006                j < current_implicit_refs_end;
   1007                ++j) {
   1008             group->children[j - current_implicit_refs_start] =
   1009                 implicit_ref_connections_[j].object;
   1010           }
   1011           implicit_ref_groups_.Add(group);
   1012         }
   1013         current_implicit_refs_start = current_implicit_refs_end;
   1014       }
   1015 
   1016       // Find a RetainedObjectInfo for the group.
   1017       RetainedObjectInfo* info = NULL;
   1018       while (info_index < retainer_infos_.length() &&
   1019              retainer_infos_[info_index].id < current_group_id) {
   1020         retainer_infos_[info_index].info->Dispose();
   1021         ++info_index;
   1022       }
   1023       if (info_index < retainer_infos_.length() &&
   1024           retainer_infos_[info_index].id == current_group_id) {
   1025         // This object group has an associated ObjectGroupRetainerInfo.
   1026         info = retainer_infos_[info_index].info;
   1027         ++info_index;
   1028       }
   1029 
   1030       // Ignore groups which only contain one object.
   1031       if (i > current_group_start + 1) {
   1032         ObjectGroup* group = new ObjectGroup(i - current_group_start);
   1033         for (int j = current_group_start; j < i; ++j) {
   1034           group->objects[j - current_group_start] =
   1035               object_group_connections_[j].object;
   1036         }
   1037         group->info = info;
   1038         object_groups_.Add(group);
   1039       } else if (info) {
   1040         info->Dispose();
   1041       }
   1042 
   1043       if (i < object_group_connections_.length()) {
   1044         current_group_id = object_group_connections_[i].id;
   1045         current_group_start = i;
   1046       }
   1047     }
   1048   }
   1049   object_group_connections_.Clear();
   1050   object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
   1051   retainer_infos_.Clear();
   1052   implicit_ref_connections_.Clear();
   1053 }
   1054 
   1055 
   1056 EternalHandles::EternalHandles() : size_(0) {
   1057   for (unsigned i = 0; i < ARRAY_SIZE(singleton_handles_); i++) {
   1058     singleton_handles_[i] = kInvalidIndex;
   1059   }
   1060 }
   1061 
   1062 
   1063 EternalHandles::~EternalHandles() {
   1064   for (int i = 0; i < blocks_.length(); i++) delete[] blocks_[i];
   1065 }
   1066 
   1067 
   1068 void EternalHandles::IterateAllRoots(ObjectVisitor* visitor) {
   1069   int limit = size_;
   1070   for (int i = 0; i < blocks_.length(); i++) {
   1071     ASSERT(limit > 0);
   1072     Object** block = blocks_[i];
   1073     visitor->VisitPointers(block, block + Min(limit, kSize));
   1074     limit -= kSize;
   1075   }
   1076 }
   1077 
   1078 
   1079 void EternalHandles::IterateNewSpaceRoots(ObjectVisitor* visitor) {
   1080   for (int i = 0; i < new_space_indices_.length(); i++) {
   1081     visitor->VisitPointer(GetLocation(new_space_indices_[i]));
   1082   }
   1083 }
   1084 
   1085 
   1086 void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) {
   1087   int last = 0;
   1088   for (int i = 0; i < new_space_indices_.length(); i++) {
   1089     int index = new_space_indices_[i];
   1090     if (heap->InNewSpace(*GetLocation(index))) {
   1091       new_space_indices_[last++] = index;
   1092     }
   1093   }
   1094   new_space_indices_.Rewind(last);
   1095 }
   1096 
   1097 
   1098 void EternalHandles::Create(Isolate* isolate, Object* object, int* index) {
   1099   ASSERT_EQ(kInvalidIndex, *index);
   1100   if (object == NULL) return;
   1101   ASSERT_NE(isolate->heap()->the_hole_value(), object);
   1102   int block = size_ >> kShift;
   1103   int offset = size_ & kMask;
   1104   // need to resize
   1105   if (offset == 0) {
   1106     Object** next_block = new Object*[kSize];
   1107     Object* the_hole = isolate->heap()->the_hole_value();
   1108     MemsetPointer(next_block, the_hole, kSize);
   1109     blocks_.Add(next_block);
   1110   }
   1111   ASSERT_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]);
   1112   blocks_[block][offset] = object;
   1113   if (isolate->heap()->InNewSpace(object)) {
   1114     new_space_indices_.Add(size_);
   1115   }
   1116   *index = size_++;
   1117 }
   1118 
   1119 
   1120 } }  // namespace v8::internal
   1121