• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~ObjectGroup()39 ObjectGroup::~ObjectGroup() {
40   if (info_ != NULL) info_->Dispose();
41 }
42 
43 
44 class GlobalHandles::Node {
45  public:
46   // State transition diagram:
47   // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
48   enum State {
49     FREE,
50     NORMAL,     // Normal global handle.
51     WEAK,       // Flagged as weak but not yet finalized.
52     PENDING,    // Has been recognized as only reachable by weak handles.
53     NEAR_DEATH  // Callback has informed the handle is near death.
54   };
55 
56   // Maps handle location (slot) to the containing node.
FromLocation(Object ** location)57   static Node* FromLocation(Object** location) {
58     ASSERT(OFFSET_OF(Node, object_) == 0);
59     return reinterpret_cast<Node*>(location);
60   }
61 
Node()62   Node() {}
63 
64 #ifdef DEBUG
~Node()65   ~Node() {
66     // TODO(1428): if it's a weak handle we should have invoked its callback.
67     // Zap the values for eager trapping.
68     object_ = NULL;
69     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
70     index_ = 0;
71     independent_ = false;
72     in_new_space_list_ = false;
73     parameter_or_next_free_.next_free = NULL;
74     callback_ = NULL;
75   }
76 #endif
77 
Initialize(int index,Node ** first_free)78   void Initialize(int index, Node** first_free) {
79     index_ = static_cast<uint8_t>(index);
80     ASSERT(static_cast<int>(index_) == index);
81     state_ = FREE;
82     in_new_space_list_ = false;
83     parameter_or_next_free_.next_free = *first_free;
84     *first_free = this;
85   }
86 
Acquire(Object * object,GlobalHandles * global_handles)87   void Acquire(Object* object, GlobalHandles* global_handles) {
88     ASSERT(state_ == FREE);
89     object_ = object;
90     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
91     independent_ = false;
92     state_  = NORMAL;
93     parameter_or_next_free_.parameter = NULL;
94     callback_ = NULL;
95     IncreaseBlockUses(global_handles);
96   }
97 
Release(GlobalHandles * global_handles)98   void Release(GlobalHandles* global_handles) {
99     ASSERT(state_ != FREE);
100     if (IsWeakRetainer()) {
101       global_handles->number_of_weak_handles_--;
102       if (object_->IsJSGlobalObject()) {
103         global_handles->number_of_global_object_weak_handles_--;
104       }
105     }
106     state_ = FREE;
107     parameter_or_next_free_.next_free = global_handles->first_free_;
108     global_handles->first_free_ = this;
109     DecreaseBlockUses(global_handles);
110   }
111 
112   // Object slot accessors.
object() const113   Object* object() const { return object_; }
location()114   Object** location() { return &object_; }
handle()115   Handle<Object> handle() { return Handle<Object>(location()); }
116 
117   // Wrapper class ID accessors.
has_wrapper_class_id() const118   bool has_wrapper_class_id() const {
119     return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
120   }
wrapper_class_id() const121   uint16_t wrapper_class_id() const { return class_id_; }
set_wrapper_class_id(uint16_t class_id)122   void set_wrapper_class_id(uint16_t class_id) {
123     class_id_ = class_id;
124   }
125 
126   // State accessors.
127 
state() const128   State state() const { return state_; }
129 
IsNearDeath() const130   bool IsNearDeath() const {
131     // Check for PENDING to ensure correct answer when processing callbacks.
132     return state_ == PENDING || state_ == NEAR_DEATH;
133   }
134 
IsWeak() const135   bool IsWeak() const { return state_ == WEAK; }
136 
IsRetainer() const137   bool IsRetainer() const { return state_ != FREE; }
138 
IsStrongRetainer() const139   bool IsStrongRetainer() const { return state_ == NORMAL; }
140 
IsWeakRetainer() const141   bool IsWeakRetainer() const {
142     return state_ == WEAK || state_ == PENDING || state_ == NEAR_DEATH;
143   }
144 
MarkPending()145   void MarkPending() {
146     ASSERT(state_ == WEAK);
147     state_ = PENDING;
148   }
149 
150   // Independent flag accessors.
MarkIndependent()151   void MarkIndependent() {
152     ASSERT(state_ != FREE);
153     independent_ = true;
154   }
is_independent() const155   bool is_independent() const { return independent_; }
156 
157   // In-new-space-list flag accessors.
set_in_new_space_list(bool v)158   void set_in_new_space_list(bool v) { in_new_space_list_ = v; }
is_in_new_space_list() const159   bool is_in_new_space_list() const { return in_new_space_list_; }
160 
161   // Callback accessor.
callback()162   WeakReferenceCallback callback() { return callback_; }
163 
164   // Callback parameter accessors.
set_parameter(void * parameter)165   void set_parameter(void* parameter) {
166     ASSERT(state_ != FREE);
167     parameter_or_next_free_.parameter = parameter;
168   }
parameter() const169   void* parameter() const {
170     ASSERT(state_ != FREE);
171     return parameter_or_next_free_.parameter;
172   }
173 
174   // Accessors for next free node in the free list.
next_free()175   Node* next_free() {
176     ASSERT(state_ == FREE);
177     return parameter_or_next_free_.next_free;
178   }
set_next_free(Node * value)179   void set_next_free(Node* value) {
180     ASSERT(state_ == FREE);
181     parameter_or_next_free_.next_free = value;
182   }
183 
MakeWeak(GlobalHandles * global_handles,void * parameter,WeakReferenceCallback callback)184   void MakeWeak(GlobalHandles* global_handles,
185                 void* parameter,
186                 WeakReferenceCallback callback) {
187     ASSERT(state_ != FREE);
188     if (!IsWeakRetainer()) {
189       global_handles->number_of_weak_handles_++;
190       if (object_->IsJSGlobalObject()) {
191         global_handles->number_of_global_object_weak_handles_++;
192       }
193     }
194     state_ = WEAK;
195     set_parameter(parameter);
196     callback_ = callback;
197   }
198 
ClearWeakness(GlobalHandles * global_handles)199   void ClearWeakness(GlobalHandles* global_handles) {
200     ASSERT(state_ != FREE);
201     if (IsWeakRetainer()) {
202       global_handles->number_of_weak_handles_--;
203       if (object_->IsJSGlobalObject()) {
204         global_handles->number_of_global_object_weak_handles_--;
205       }
206     }
207     state_ = NORMAL;
208     set_parameter(NULL);
209   }
210 
PostGarbageCollectionProcessing(Isolate * isolate,GlobalHandles * global_handles)211   bool PostGarbageCollectionProcessing(Isolate* isolate,
212                                        GlobalHandles* global_handles) {
213     if (state_ != Node::PENDING) return false;
214     WeakReferenceCallback func = callback();
215     if (func == NULL) {
216       Release(global_handles);
217       return false;
218     }
219     void* par = parameter();
220     state_ = NEAR_DEATH;
221     set_parameter(NULL);
222 
223     v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
224     {
225       // Check that we are not passing a finalized external string to
226       // the callback.
227       ASSERT(!object_->IsExternalAsciiString() ||
228              ExternalAsciiString::cast(object_)->resource() != NULL);
229       ASSERT(!object_->IsExternalTwoByteString() ||
230              ExternalTwoByteString::cast(object_)->resource() != NULL);
231       // Leaving V8.
232       VMState state(isolate, EXTERNAL);
233       func(object, par);
234     }
235     // Absence of explicit cleanup or revival of weak handle
236     // in most of the cases would lead to memory leak.
237     ASSERT(state_ != NEAR_DEATH);
238     return true;
239   }
240 
241  private:
242   inline NodeBlock* FindBlock();
243   inline void IncreaseBlockUses(GlobalHandles* global_handles);
244   inline void DecreaseBlockUses(GlobalHandles* global_handles);
245 
246   // Storage for object pointer.
247   // Placed first to avoid offset computation.
248   Object* object_;
249 
250   // Next word stores class_id, index, state, and independent.
251   // Note: the most aligned fields should go first.
252 
253   // Wrapper class ID.
254   uint16_t class_id_;
255 
256   // Index in the containing handle block.
257   uint8_t index_;
258 
259   // Need one more bit for MSVC as it treats enums as signed.
260   State state_ : 4;
261 
262   bool independent_ : 1;
263   bool in_new_space_list_ : 1;
264 
265   // Handle specific callback.
266   WeakReferenceCallback callback_;
267 
268   // Provided data for callback.  In FREE state, this is used for
269   // the free list link.
270   union {
271     void* parameter;
272     Node* next_free;
273   } parameter_or_next_free_;
274 
275   DISALLOW_COPY_AND_ASSIGN(Node);
276 };
277 
278 
279 class GlobalHandles::NodeBlock {
280  public:
281   static const int kSize = 256;
282 
NodeBlock(NodeBlock * next)283   explicit NodeBlock(NodeBlock* next)
284       : next_(next), used_nodes_(0), next_used_(NULL), prev_used_(NULL) {}
285 
PutNodesOnFreeList(Node ** first_free)286   void PutNodesOnFreeList(Node** first_free) {
287     for (int i = kSize - 1; i >= 0; --i) {
288       nodes_[i].Initialize(i, first_free);
289     }
290   }
291 
node_at(int index)292   Node* node_at(int index) {
293     ASSERT(0 <= index && index < kSize);
294     return &nodes_[index];
295   }
296 
IncreaseUses(GlobalHandles * global_handles)297   void IncreaseUses(GlobalHandles* global_handles) {
298     ASSERT(used_nodes_ < kSize);
299     if (used_nodes_++ == 0) {
300       NodeBlock* old_first = global_handles->first_used_block_;
301       global_handles->first_used_block_ = this;
302       next_used_ = old_first;
303       prev_used_ = NULL;
304       if (old_first == NULL) return;
305       old_first->prev_used_ = this;
306     }
307   }
308 
DecreaseUses(GlobalHandles * global_handles)309   void DecreaseUses(GlobalHandles* global_handles) {
310     ASSERT(used_nodes_ > 0);
311     if (--used_nodes_ == 0) {
312       if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
313       if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
314       if (this == global_handles->first_used_block_) {
315         global_handles->first_used_block_ = next_used_;
316       }
317     }
318   }
319 
320   // Next block in the list of all blocks.
next() const321   NodeBlock* next() const { return next_; }
322 
323   // Next/previous block in the list of blocks with used nodes.
next_used() const324   NodeBlock* next_used() const { return next_used_; }
prev_used() const325   NodeBlock* prev_used() const { return prev_used_; }
326 
327  private:
328   Node nodes_[kSize];
329   NodeBlock* const next_;
330   int used_nodes_;
331   NodeBlock* next_used_;
332   NodeBlock* prev_used_;
333 };
334 
335 
FindBlock()336 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
337   intptr_t ptr = reinterpret_cast<intptr_t>(this);
338   ptr = ptr - index_ * sizeof(Node);
339   NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
340   ASSERT(block->node_at(index_) == this);
341   return block;
342 }
343 
344 
IncreaseBlockUses(GlobalHandles * global_handles)345 void GlobalHandles::Node::IncreaseBlockUses(GlobalHandles* global_handles) {
346   FindBlock()->IncreaseUses(global_handles);
347 }
348 
349 
DecreaseBlockUses(GlobalHandles * global_handles)350 void GlobalHandles::Node::DecreaseBlockUses(GlobalHandles* global_handles) {
351   FindBlock()->DecreaseUses(global_handles);
352 }
353 
354 
355 class GlobalHandles::NodeIterator {
356  public:
NodeIterator(GlobalHandles * global_handles)357   explicit NodeIterator(GlobalHandles* global_handles)
358       : block_(global_handles->first_used_block_),
359         index_(0) {}
360 
done() const361   bool done() const { return block_ == NULL; }
362 
node() const363   Node* node() const {
364     ASSERT(!done());
365     return block_->node_at(index_);
366   }
367 
Advance()368   void Advance() {
369     ASSERT(!done());
370     if (++index_ < NodeBlock::kSize) return;
371     index_ = 0;
372     block_ = block_->next_used();
373   }
374 
375  private:
376   NodeBlock* block_;
377   int index_;
378 
379   DISALLOW_COPY_AND_ASSIGN(NodeIterator);
380 };
381 
382 
GlobalHandles(Isolate * isolate)383 GlobalHandles::GlobalHandles(Isolate* isolate)
384     : isolate_(isolate),
385       number_of_weak_handles_(0),
386       number_of_global_object_weak_handles_(0),
387       number_of_global_handles_(0),
388       first_block_(NULL),
389       first_used_block_(NULL),
390       first_free_(NULL),
391       post_gc_processing_count_(0) {}
392 
393 
~GlobalHandles()394 GlobalHandles::~GlobalHandles() {
395   NodeBlock* block = first_block_;
396   while (block != NULL) {
397     NodeBlock* tmp = block->next();
398     delete block;
399     block = tmp;
400   }
401   first_block_ = NULL;
402 }
403 
404 
Create(Object * value)405 Handle<Object> GlobalHandles::Create(Object* value) {
406   isolate_->counters()->global_handles()->Increment();
407   number_of_global_handles_++;
408   if (first_free_ == NULL) {
409     first_block_ = new NodeBlock(first_block_);
410     first_block_->PutNodesOnFreeList(&first_free_);
411   }
412   ASSERT(first_free_ != NULL);
413   // Take the first node in the free list.
414   Node* result = first_free_;
415   first_free_ = result->next_free();
416   result->Acquire(value, this);
417   if (isolate_->heap()->InNewSpace(value) &&
418       !result->is_in_new_space_list()) {
419     new_space_nodes_.Add(result);
420     result->set_in_new_space_list(true);
421   }
422   return result->handle();
423 }
424 
425 
Destroy(Object ** location)426 void GlobalHandles::Destroy(Object** location) {
427   isolate_->counters()->global_handles()->Decrement();
428   number_of_global_handles_--;
429   if (location == NULL) return;
430   Node::FromLocation(location)->Release(this);
431 }
432 
433 
MakeWeak(Object ** location,void * parameter,WeakReferenceCallback callback)434 void GlobalHandles::MakeWeak(Object** location, void* parameter,
435                              WeakReferenceCallback callback) {
436   ASSERT(callback != NULL);
437   Node::FromLocation(location)->MakeWeak(this, parameter, callback);
438 }
439 
440 
ClearWeakness(Object ** location)441 void GlobalHandles::ClearWeakness(Object** location) {
442   Node::FromLocation(location)->ClearWeakness(this);
443 }
444 
445 
MarkIndependent(Object ** location)446 void GlobalHandles::MarkIndependent(Object** location) {
447   Node::FromLocation(location)->MarkIndependent();
448 }
449 
450 
IsNearDeath(Object ** location)451 bool GlobalHandles::IsNearDeath(Object** location) {
452   return Node::FromLocation(location)->IsNearDeath();
453 }
454 
455 
IsWeak(Object ** location)456 bool GlobalHandles::IsWeak(Object** location) {
457   return Node::FromLocation(location)->IsWeak();
458 }
459 
460 
SetWrapperClassId(Object ** location,uint16_t class_id)461 void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) {
462   Node::FromLocation(location)->set_wrapper_class_id(class_id);
463 }
464 
465 
IterateWeakRoots(ObjectVisitor * v)466 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
467   for (NodeIterator it(this); !it.done(); it.Advance()) {
468     if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location());
469   }
470 }
471 
472 
IterateWeakRoots(WeakReferenceGuest f,WeakReferenceCallback callback)473 void GlobalHandles::IterateWeakRoots(WeakReferenceGuest f,
474                                      WeakReferenceCallback callback) {
475   for (NodeIterator it(this); !it.done(); it.Advance()) {
476     if (it.node()->IsWeak() && it.node()->callback() == callback) {
477       f(it.node()->object(), it.node()->parameter());
478     }
479   }
480 }
481 
482 
IdentifyWeakHandles(WeakSlotCallback f)483 void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
484   for (NodeIterator it(this); !it.done(); it.Advance()) {
485     if (it.node()->IsWeak() && f(it.node()->location())) {
486       it.node()->MarkPending();
487     }
488   }
489 }
490 
491 
IterateNewSpaceStrongAndDependentRoots(ObjectVisitor * v)492 void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
493   for (int i = 0; i < new_space_nodes_.length(); ++i) {
494     Node* node = new_space_nodes_[i];
495     if (node->IsStrongRetainer() ||
496         (node->IsWeakRetainer() && !node->is_independent())) {
497       v->VisitPointer(node->location());
498     }
499   }
500 }
501 
502 
IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f)503 void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles(
504     WeakSlotCallbackWithHeap f) {
505   for (int i = 0; i < new_space_nodes_.length(); ++i) {
506     Node* node = new_space_nodes_[i];
507     ASSERT(node->is_in_new_space_list());
508     if (node->is_independent() && node->IsWeak() &&
509         f(isolate_->heap(), node->location())) {
510       node->MarkPending();
511     }
512   }
513 }
514 
515 
IterateNewSpaceWeakIndependentRoots(ObjectVisitor * v)516 void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
517   for (int i = 0; i < new_space_nodes_.length(); ++i) {
518     Node* node = new_space_nodes_[i];
519     ASSERT(node->is_in_new_space_list());
520     if (node->is_independent() && node->IsWeakRetainer()) {
521       v->VisitPointer(node->location());
522     }
523   }
524 }
525 
526 
PostGarbageCollectionProcessing(GarbageCollector collector)527 bool GlobalHandles::PostGarbageCollectionProcessing(
528     GarbageCollector collector) {
529   // Process weak global handle callbacks. This must be done after the
530   // GC is completely done, because the callbacks may invoke arbitrary
531   // API functions.
532   ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
533   const int initial_post_gc_processing_count = ++post_gc_processing_count_;
534   bool next_gc_likely_to_collect_more = false;
535   if (collector == SCAVENGER) {
536     for (int i = 0; i < new_space_nodes_.length(); ++i) {
537       Node* node = new_space_nodes_[i];
538       ASSERT(node->is_in_new_space_list());
539       // Skip dependent handles. Their weak callbacks might expect to be
540       // called between two global garbage collection callbacks which
541       // are not called for minor collections.
542       if (!node->is_independent()) continue;
543       if (node->PostGarbageCollectionProcessing(isolate_, this)) {
544         if (initial_post_gc_processing_count != post_gc_processing_count_) {
545           // Weak callback triggered another GC and another round of
546           // PostGarbageCollection processing.  The current node might
547           // have been deleted in that round, so we need to bail out (or
548           // restart the processing).
549           return next_gc_likely_to_collect_more;
550         }
551       }
552       if (!node->IsRetainer()) {
553         next_gc_likely_to_collect_more = true;
554       }
555     }
556   } else {
557     for (NodeIterator it(this); !it.done(); it.Advance()) {
558       if (it.node()->PostGarbageCollectionProcessing(isolate_, this)) {
559         if (initial_post_gc_processing_count != post_gc_processing_count_) {
560           // See the comment above.
561           return next_gc_likely_to_collect_more;
562         }
563       }
564       if (!it.node()->IsRetainer()) {
565         next_gc_likely_to_collect_more = true;
566       }
567     }
568   }
569   // Update the list of new space nodes.
570   int last = 0;
571   for (int i = 0; i < new_space_nodes_.length(); ++i) {
572     Node* node = new_space_nodes_[i];
573     ASSERT(node->is_in_new_space_list());
574     if (node->IsRetainer() && isolate_->heap()->InNewSpace(node->object())) {
575       new_space_nodes_[last++] = node;
576     } else {
577       node->set_in_new_space_list(false);
578     }
579   }
580   new_space_nodes_.Rewind(last);
581   return next_gc_likely_to_collect_more;
582 }
583 
584 
IterateStrongRoots(ObjectVisitor * v)585 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
586   for (NodeIterator it(this); !it.done(); it.Advance()) {
587     if (it.node()->IsStrongRetainer()) {
588       v->VisitPointer(it.node()->location());
589     }
590   }
591 }
592 
593 
IterateAllRoots(ObjectVisitor * v)594 void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
595   for (NodeIterator it(this); !it.done(); it.Advance()) {
596     if (it.node()->IsRetainer()) {
597       v->VisitPointer(it.node()->location());
598     }
599   }
600 }
601 
602 
IterateAllRootsWithClassIds(ObjectVisitor * v)603 void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
604   for (NodeIterator it(this); !it.done(); it.Advance()) {
605     if (it.node()->has_wrapper_class_id() && it.node()->IsRetainer()) {
606       v->VisitEmbedderReference(it.node()->location(),
607                                 it.node()->wrapper_class_id());
608     }
609   }
610 }
611 
612 
RecordStats(HeapStats * stats)613 void GlobalHandles::RecordStats(HeapStats* stats) {
614   *stats->global_handle_count = 0;
615   *stats->weak_global_handle_count = 0;
616   *stats->pending_global_handle_count = 0;
617   *stats->near_death_global_handle_count = 0;
618   *stats->free_global_handle_count = 0;
619   for (NodeIterator it(this); !it.done(); it.Advance()) {
620     *stats->global_handle_count += 1;
621     if (it.node()->state() == Node::WEAK) {
622       *stats->weak_global_handle_count += 1;
623     } else if (it.node()->state() == Node::PENDING) {
624       *stats->pending_global_handle_count += 1;
625     } else if (it.node()->state() == Node::NEAR_DEATH) {
626       *stats->near_death_global_handle_count += 1;
627     } else if (it.node()->state() == Node::FREE) {
628       *stats->free_global_handle_count += 1;
629     }
630   }
631 }
632 
633 #ifdef DEBUG
634 
PrintStats()635 void GlobalHandles::PrintStats() {
636   int total = 0;
637   int weak = 0;
638   int pending = 0;
639   int near_death = 0;
640   int destroyed = 0;
641 
642   for (NodeIterator it(this); !it.done(); it.Advance()) {
643     total++;
644     if (it.node()->state() == Node::WEAK) weak++;
645     if (it.node()->state() == Node::PENDING) pending++;
646     if (it.node()->state() == Node::NEAR_DEATH) near_death++;
647     if (it.node()->state() == Node::FREE) destroyed++;
648   }
649 
650   PrintF("Global Handle Statistics:\n");
651   PrintF("  allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
652   PrintF("  # weak       = %d\n", weak);
653   PrintF("  # pending    = %d\n", pending);
654   PrintF("  # near_death = %d\n", near_death);
655   PrintF("  # free       = %d\n", destroyed);
656   PrintF("  # total      = %d\n", total);
657 }
658 
Print()659 void GlobalHandles::Print() {
660   PrintF("Global handles:\n");
661   for (NodeIterator it(this); !it.done(); it.Advance()) {
662     PrintF("  handle %p to %p%s\n",
663            reinterpret_cast<void*>(it.node()->location()),
664            reinterpret_cast<void*>(it.node()->object()),
665            it.node()->IsWeak() ? " (weak)" : "");
666   }
667 }
668 
669 #endif
670 
671 
672 
AddObjectGroup(Object *** handles,size_t length,v8::RetainedObjectInfo * info)673 void GlobalHandles::AddObjectGroup(Object*** handles,
674                                    size_t length,
675                                    v8::RetainedObjectInfo* info) {
676 #ifdef DEBUG
677   for (size_t i = 0; i < length; ++i) {
678     ASSERT(!Node::FromLocation(handles[i])->is_independent());
679   }
680 #endif
681   if (length == 0) {
682     if (info != NULL) info->Dispose();
683     return;
684   }
685   object_groups_.Add(ObjectGroup::New(handles, length, info));
686 }
687 
688 
AddImplicitReferences(HeapObject ** parent,Object *** children,size_t length)689 void GlobalHandles::AddImplicitReferences(HeapObject** parent,
690                                           Object*** children,
691                                           size_t length) {
692 #ifdef DEBUG
693   ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->is_independent());
694   for (size_t i = 0; i < length; ++i) {
695     ASSERT(!Node::FromLocation(children[i])->is_independent());
696   }
697 #endif
698   if (length == 0) return;
699   implicit_ref_groups_.Add(ImplicitRefGroup::New(parent, children, length));
700 }
701 
702 
RemoveObjectGroups()703 void GlobalHandles::RemoveObjectGroups() {
704   for (int i = 0; i < object_groups_.length(); i++) {
705     object_groups_.at(i)->Dispose();
706   }
707   object_groups_.Clear();
708 }
709 
710 
RemoveImplicitRefGroups()711 void GlobalHandles::RemoveImplicitRefGroups() {
712   for (int i = 0; i < implicit_ref_groups_.length(); i++) {
713     implicit_ref_groups_.at(i)->Dispose();
714   }
715   implicit_ref_groups_.Clear();
716 }
717 
718 
TearDown()719 void GlobalHandles::TearDown() {
720   // TODO(1428): invoke weak callbacks.
721 }
722 
723 
724 } }  // namespace v8::internal
725