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