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