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
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.
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.
31 #include "global-handles.h"
33 #include "vm-state-inl.h"
39 ObjectGroup::~ObjectGroup() {
40 if (info != NULL) info->Dispose();
45 ImplicitRefGroup::~ImplicitRefGroup() {
50 class GlobalHandles::Node {
52 // State transition diagram:
53 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
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.
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);
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);
82 #ifdef ENABLE_EXTRA_CHECKS
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;
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_reference_callback_ = NULL;
97 void Initialize(int index, Node** first_free) {
98 index_ = static_cast<uint8_t>(index);
99 ASSERT(static_cast<int>(index_) == index);
101 set_in_new_space_list(false);
102 parameter_or_next_free_.next_free = *first_free;
106 void Acquire(Object* object) {
107 ASSERT(state() == FREE);
109 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
110 set_independent(false);
111 set_partially_dependent(false);
113 parameter_or_next_free_.parameter = NULL;
114 weak_reference_callback_ = NULL;
119 ASSERT(state() != FREE);
121 #ifdef ENABLE_EXTRA_CHECKS
122 // Zap the values for eager trapping.
123 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
124 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
125 set_independent(false);
126 set_partially_dependent(false);
127 weak_reference_callback_ = NULL;
132 // Object slot accessors.
133 Object* object() const { return object_; }
134 Object** location() { return &object_; }
135 Handle<Object> handle() { return Handle<Object>(location()); }
137 // Wrapper class ID accessors.
138 bool has_wrapper_class_id() const {
139 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
142 uint16_t wrapper_class_id() const { return class_id_; }
144 // State and flag accessors.
146 State state() const {
147 return NodeState::decode(flags_);
149 void set_state(State state) {
150 flags_ = NodeState::update(flags_, state);
153 bool is_independent() {
154 return IsIndependent::decode(flags_);
156 void set_independent(bool v) {
157 flags_ = IsIndependent::update(flags_, v);
160 bool is_partially_dependent() {
161 return IsPartiallyDependent::decode(flags_);
163 void set_partially_dependent(bool v) {
164 flags_ = IsPartiallyDependent::update(flags_, v);
167 bool is_in_new_space_list() {
168 return IsInNewSpaceList::decode(flags_);
170 void set_in_new_space_list(bool v) {
171 flags_ = IsInNewSpaceList::update(flags_, v);
174 bool IsNearDeath() const {
175 // Check for PENDING to ensure correct answer when processing callbacks.
176 return state() == PENDING || state() == NEAR_DEATH;
179 bool IsWeak() const { return state() == WEAK; }
181 bool IsRetainer() const { return state() != FREE; }
183 bool IsStrongRetainer() const { return state() == NORMAL; }
185 bool IsWeakRetainer() const {
186 return state() == WEAK || state() == PENDING || state() == NEAR_DEATH;
190 ASSERT(state() == WEAK);
194 // Independent flag accessors.
195 void MarkIndependent() {
196 ASSERT(state() != FREE);
197 set_independent(true);
200 void MarkPartiallyDependent() {
201 ASSERT(state() != FREE);
202 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
203 set_partially_dependent(true);
206 void clear_partially_dependent() { set_partially_dependent(false); }
208 // Callback accessor.
209 // TODO(svenpanne) Re-enable or nuke later.
210 // WeakReferenceCallback callback() { return callback_; }
212 // Callback parameter accessors.
213 void set_parameter(void* parameter) {
214 ASSERT(state() != FREE);
215 parameter_or_next_free_.parameter = parameter;
217 void* parameter() const {
218 ASSERT(state() != FREE);
219 return parameter_or_next_free_.parameter;
222 // Accessors for next free node in the free list.
224 ASSERT(state() == FREE);
225 return parameter_or_next_free_.next_free;
227 void set_next_free(Node* value) {
228 ASSERT(state() == FREE);
229 parameter_or_next_free_.next_free = value;
232 void MakeWeak(void* parameter,
233 RevivableCallback weak_reference_callback) {
234 ASSERT(state() != FREE);
236 set_parameter(parameter);
237 weak_reference_callback_ = weak_reference_callback;
240 void ClearWeakness() {
241 ASSERT(state() != FREE);
246 bool PostGarbageCollectionProcessing(Isolate* isolate) {
247 if (state() != Node::PENDING) return false;
248 if (weak_reference_callback_ == NULL) {
252 void* par = parameter();
253 set_state(NEAR_DEATH);
256 Object** object = location();
258 // Check that we are not passing a finalized external string to
260 ASSERT(!object_->IsExternalAsciiString() ||
261 ExternalAsciiString::cast(object_)->resource() != NULL);
262 ASSERT(!object_->IsExternalTwoByteString() ||
263 ExternalTwoByteString::cast(object_)->resource() != NULL);
265 VMState<EXTERNAL> state(isolate);
266 HandleScope handle_scope(isolate);
267 weak_reference_callback_(reinterpret_cast<v8::Isolate*>(isolate),
268 reinterpret_cast<Persistent<Value>*>(&object),
271 // Absence of explicit cleanup or revival of weak handle
272 // in most of the cases would lead to memory leak.
273 ASSERT(state() != NEAR_DEATH);
278 inline NodeBlock* FindBlock();
279 inline GlobalHandles* GetGlobalHandles();
280 inline void IncreaseBlockUses();
281 inline void DecreaseBlockUses();
283 // Storage for object pointer.
284 // Placed first to avoid offset computation.
287 // Next word stores class_id, index, state, and independent.
288 // Note: the most aligned fields should go first.
293 // Index in the containing handle block.
296 // This stores three flags (independent, partially_dependent and
297 // in_new_space_list) and a State.
298 class NodeState: public BitField<State, 0, 4> {};
299 class IsIndependent: public BitField<bool, 4, 1> {};
300 class IsPartiallyDependent: public BitField<bool, 5, 1> {};
301 class IsInNewSpaceList: public BitField<bool, 6, 1> {};
305 // Handle specific callback - might be a weak reference in disguise.
306 RevivableCallback weak_reference_callback_;
308 // Provided data for callback. In FREE state, this is used for
309 // the free list link.
313 } parameter_or_next_free_;
315 DISALLOW_COPY_AND_ASSIGN(Node);
319 class GlobalHandles::NodeBlock {
321 static const int kSize = 256;
323 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
328 global_handles_(global_handles) {}
330 void PutNodesOnFreeList(Node** first_free) {
331 for (int i = kSize - 1; i >= 0; --i) {
332 nodes_[i].Initialize(i, first_free);
336 Node* node_at(int index) {
337 ASSERT(0 <= index && index < kSize);
338 return &nodes_[index];
341 void IncreaseUses() {
342 ASSERT(used_nodes_ < kSize);
343 if (used_nodes_++ == 0) {
344 NodeBlock* old_first = global_handles_->first_used_block_;
345 global_handles_->first_used_block_ = this;
346 next_used_ = old_first;
348 if (old_first == NULL) return;
349 old_first->prev_used_ = this;
353 void DecreaseUses() {
354 ASSERT(used_nodes_ > 0);
355 if (--used_nodes_ == 0) {
356 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
357 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
358 if (this == global_handles_->first_used_block_) {
359 global_handles_->first_used_block_ = next_used_;
364 GlobalHandles* global_handles() { return global_handles_; }
366 // Next block in the list of all blocks.
367 NodeBlock* next() const { return next_; }
369 // Next/previous block in the list of blocks with used nodes.
370 NodeBlock* next_used() const { return next_used_; }
371 NodeBlock* prev_used() const { return prev_used_; }
375 NodeBlock* const next_;
377 NodeBlock* next_used_;
378 NodeBlock* prev_used_;
379 GlobalHandles* global_handles_;
383 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
384 return FindBlock()->global_handles();
388 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
389 intptr_t ptr = reinterpret_cast<intptr_t>(this);
390 ptr = ptr - index_ * sizeof(Node);
391 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
392 ASSERT(block->node_at(index_) == this);
397 void GlobalHandles::Node::IncreaseBlockUses() {
398 NodeBlock* node_block = FindBlock();
399 node_block->IncreaseUses();
400 GlobalHandles* global_handles = node_block->global_handles();
401 global_handles->isolate()->counters()->global_handles()->Increment();
402 global_handles->number_of_global_handles_++;
406 void GlobalHandles::Node::DecreaseBlockUses() {
407 NodeBlock* node_block = FindBlock();
408 GlobalHandles* global_handles = node_block->global_handles();
409 parameter_or_next_free_.next_free = global_handles->first_free_;
410 global_handles->first_free_ = this;
411 node_block->DecreaseUses();
412 global_handles->isolate()->counters()->global_handles()->Decrement();
413 global_handles->number_of_global_handles_--;
417 class GlobalHandles::NodeIterator {
419 explicit NodeIterator(GlobalHandles* global_handles)
420 : block_(global_handles->first_used_block_),
423 bool done() const { return block_ == NULL; }
427 return block_->node_at(index_);
432 if (++index_ < NodeBlock::kSize) return;
434 block_ = block_->next_used();
441 DISALLOW_COPY_AND_ASSIGN(NodeIterator);
445 GlobalHandles::GlobalHandles(Isolate* isolate)
447 number_of_global_handles_(0),
449 first_used_block_(NULL),
451 post_gc_processing_count_(0),
452 object_group_connections_(kObjectGroupConnectionsCapacity) {}
455 GlobalHandles::~GlobalHandles() {
456 NodeBlock* block = first_block_;
457 while (block != NULL) {
458 NodeBlock* tmp = block->next();
466 Handle<Object> GlobalHandles::Create(Object* value) {
467 if (first_free_ == NULL) {
468 first_block_ = new NodeBlock(this, first_block_);
469 first_block_->PutNodesOnFreeList(&first_free_);
471 ASSERT(first_free_ != NULL);
472 // Take the first node in the free list.
473 Node* result = first_free_;
474 first_free_ = result->next_free();
475 result->Acquire(value);
476 if (isolate_->heap()->InNewSpace(value) &&
477 !result->is_in_new_space_list()) {
478 new_space_nodes_.Add(result);
479 result->set_in_new_space_list(true);
481 return result->handle();
485 void GlobalHandles::Destroy(Object** location) {
486 if (location != NULL) Node::FromLocation(location)->Release();
490 void GlobalHandles::MakeWeak(Object** location,
492 RevivableCallback weak_reference_callback) {
493 ASSERT(weak_reference_callback != NULL);
494 Node::FromLocation(location)->MakeWeak(parameter, weak_reference_callback);
498 void GlobalHandles::ClearWeakness(Object** location) {
499 Node::FromLocation(location)->ClearWeakness();
503 void GlobalHandles::MarkIndependent(Object** location) {
504 Node::FromLocation(location)->MarkIndependent();
508 void GlobalHandles::MarkPartiallyDependent(Object** location) {
509 Node::FromLocation(location)->MarkPartiallyDependent();
513 bool GlobalHandles::IsIndependent(Object** location) {
514 return Node::FromLocation(location)->is_independent();
518 bool GlobalHandles::IsNearDeath(Object** location) {
519 return Node::FromLocation(location)->IsNearDeath();
523 bool GlobalHandles::IsWeak(Object** location) {
524 return Node::FromLocation(location)->IsWeak();
528 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
529 for (NodeIterator it(this); !it.done(); it.Advance()) {
530 if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location());
535 void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
536 for (NodeIterator it(this); !it.done(); it.Advance()) {
537 if (it.node()->IsWeak() && f(it.node()->location())) {
538 it.node()->MarkPending();
544 void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
545 for (int i = 0; i < new_space_nodes_.length(); ++i) {
546 Node* node = new_space_nodes_[i];
547 if (node->IsStrongRetainer() ||
548 (node->IsWeakRetainer() && !node->is_independent() &&
549 !node->is_partially_dependent())) {
550 v->VisitPointer(node->location());
556 void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles(
557 WeakSlotCallbackWithHeap f) {
558 for (int i = 0; i < new_space_nodes_.length(); ++i) {
559 Node* node = new_space_nodes_[i];
560 ASSERT(node->is_in_new_space_list());
561 if ((node->is_independent() || node->is_partially_dependent()) &&
562 node->IsWeak() && f(isolate_->heap(), node->location())) {
569 void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
570 for (int i = 0; i < new_space_nodes_.length(); ++i) {
571 Node* node = new_space_nodes_[i];
572 ASSERT(node->is_in_new_space_list());
573 if ((node->is_independent() || node->is_partially_dependent()) &&
574 node->IsWeakRetainer()) {
575 v->VisitPointer(node->location());
581 bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
582 WeakSlotCallbackWithHeap can_skip) {
583 ComputeObjectGroupsAndImplicitReferences();
585 bool any_group_was_visited = false;
586 for (int i = 0; i < object_groups_.length(); i++) {
587 ObjectGroup* entry = object_groups_.at(i);
588 ASSERT(entry != NULL);
590 Object*** objects = entry->objects;
591 bool group_should_be_visited = false;
592 for (size_t j = 0; j < entry->length; j++) {
593 Object* object = *objects[j];
594 if (object->IsHeapObject()) {
595 if (!can_skip(isolate_->heap(), &object)) {
596 group_should_be_visited = true;
602 if (!group_should_be_visited) {
603 object_groups_[last++] = entry;
607 // An object in the group requires visiting, so iterate over all
608 // objects in the group.
609 for (size_t j = 0; j < entry->length; ++j) {
610 Object* object = *objects[j];
611 if (object->IsHeapObject()) {
612 v->VisitPointer(&object);
613 any_group_was_visited = true;
617 // Once the entire group has been iterated over, set the object
618 // group to NULL so it won't be processed again.
620 object_groups_.at(i) = NULL;
622 object_groups_.Rewind(last);
623 return any_group_was_visited;
627 bool GlobalHandles::PostGarbageCollectionProcessing(
628 GarbageCollector collector, GCTracer* tracer) {
629 // Process weak global handle callbacks. This must be done after the
630 // GC is completely done, because the callbacks may invoke arbitrary
632 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
633 const int initial_post_gc_processing_count = ++post_gc_processing_count_;
634 bool next_gc_likely_to_collect_more = false;
635 if (collector == SCAVENGER) {
636 for (int i = 0; i < new_space_nodes_.length(); ++i) {
637 Node* node = new_space_nodes_[i];
638 ASSERT(node->is_in_new_space_list());
639 if (!node->IsRetainer()) {
640 // Free nodes do not have weak callbacks. Do not use them to compute
641 // the next_gc_likely_to_collect_more.
644 // Skip dependent handles. Their weak callbacks might expect to be
645 // called between two global garbage collection callbacks which
646 // are not called for minor collections.
647 if (!node->is_independent() && !node->is_partially_dependent()) {
650 node->clear_partially_dependent();
651 if (node->PostGarbageCollectionProcessing(isolate_)) {
652 if (initial_post_gc_processing_count != post_gc_processing_count_) {
653 // Weak callback triggered another GC and another round of
654 // PostGarbageCollection processing. The current node might
655 // have been deleted in that round, so we need to bail out (or
656 // restart the processing).
657 return next_gc_likely_to_collect_more;
660 if (!node->IsRetainer()) {
661 next_gc_likely_to_collect_more = true;
665 for (NodeIterator it(this); !it.done(); it.Advance()) {
666 if (!it.node()->IsRetainer()) {
667 // Free nodes do not have weak callbacks. Do not use them to compute
668 // the next_gc_likely_to_collect_more.
671 it.node()->clear_partially_dependent();
672 if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
673 if (initial_post_gc_processing_count != post_gc_processing_count_) {
674 // See the comment above.
675 return next_gc_likely_to_collect_more;
678 if (!it.node()->IsRetainer()) {
679 next_gc_likely_to_collect_more = true;
683 // Update the list of new space nodes.
685 for (int i = 0; i < new_space_nodes_.length(); ++i) {
686 Node* node = new_space_nodes_[i];
687 ASSERT(node->is_in_new_space_list());
688 if (node->IsRetainer()) {
689 if (isolate_->heap()->InNewSpace(node->object())) {
690 new_space_nodes_[last++] = node;
691 tracer->increment_nodes_copied_in_new_space();
693 node->set_in_new_space_list(false);
694 tracer->increment_nodes_promoted();
697 node->set_in_new_space_list(false);
698 tracer->increment_nodes_died_in_new_space();
701 new_space_nodes_.Rewind(last);
702 return next_gc_likely_to_collect_more;
706 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
707 for (NodeIterator it(this); !it.done(); it.Advance()) {
708 if (it.node()->IsStrongRetainer()) {
709 v->VisitPointer(it.node()->location());
715 void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
716 for (NodeIterator it(this); !it.done(); it.Advance()) {
717 if (it.node()->IsRetainer()) {
718 v->VisitPointer(it.node()->location());
724 void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
725 for (NodeIterator it(this); !it.done(); it.Advance()) {
726 if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
727 v->VisitEmbedderReference(it.node()->location(),
728 it.node()->wrapper_class_id());
734 void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
735 for (int i = 0; i < new_space_nodes_.length(); ++i) {
736 Node* node = new_space_nodes_[i];
737 if (node->IsRetainer() && node->has_wrapper_class_id()) {
738 v->VisitEmbedderReference(node->location(),
739 node->wrapper_class_id());
745 int GlobalHandles::NumberOfWeakHandles() {
747 for (NodeIterator it(this); !it.done(); it.Advance()) {
748 if (it.node()->IsWeakRetainer()) {
756 int GlobalHandles::NumberOfGlobalObjectWeakHandles() {
758 for (NodeIterator it(this); !it.done(); it.Advance()) {
759 if (it.node()->IsWeakRetainer() &&
760 it.node()->object()->IsJSGlobalObject()) {
768 void GlobalHandles::RecordStats(HeapStats* stats) {
769 *stats->global_handle_count = 0;
770 *stats->weak_global_handle_count = 0;
771 *stats->pending_global_handle_count = 0;
772 *stats->near_death_global_handle_count = 0;
773 *stats->free_global_handle_count = 0;
774 for (NodeIterator it(this); !it.done(); it.Advance()) {
775 *stats->global_handle_count += 1;
776 if (it.node()->state() == Node::WEAK) {
777 *stats->weak_global_handle_count += 1;
778 } else if (it.node()->state() == Node::PENDING) {
779 *stats->pending_global_handle_count += 1;
780 } else if (it.node()->state() == Node::NEAR_DEATH) {
781 *stats->near_death_global_handle_count += 1;
782 } else if (it.node()->state() == Node::FREE) {
783 *stats->free_global_handle_count += 1;
790 void GlobalHandles::PrintStats() {
797 for (NodeIterator it(this); !it.done(); it.Advance()) {
799 if (it.node()->state() == Node::WEAK) weak++;
800 if (it.node()->state() == Node::PENDING) pending++;
801 if (it.node()->state() == Node::NEAR_DEATH) near_death++;
802 if (it.node()->state() == Node::FREE) destroyed++;
805 PrintF("Global Handle Statistics:\n");
806 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
807 PrintF(" # weak = %d\n", weak);
808 PrintF(" # pending = %d\n", pending);
809 PrintF(" # near_death = %d\n", near_death);
810 PrintF(" # free = %d\n", destroyed);
811 PrintF(" # total = %d\n", total);
815 void GlobalHandles::Print() {
816 PrintF("Global handles:\n");
817 for (NodeIterator it(this); !it.done(); it.Advance()) {
818 PrintF(" handle %p to %p%s\n",
819 reinterpret_cast<void*>(it.node()->location()),
820 reinterpret_cast<void*>(it.node()->object()),
821 it.node()->IsWeak() ? " (weak)" : "");
829 void GlobalHandles::AddObjectGroup(Object*** handles,
831 v8::RetainedObjectInfo* info) {
833 for (size_t i = 0; i < length; ++i) {
834 ASSERT(!Node::FromLocation(handles[i])->is_independent());
838 if (info != NULL) info->Dispose();
841 ObjectGroup* group = new ObjectGroup(length);
842 for (size_t i = 0; i < length; ++i)
843 group->objects[i] = handles[i];
845 object_groups_.Add(group);
849 void GlobalHandles::SetObjectGroupId(Object** handle,
851 object_group_connections_.Add(ObjectGroupConnection(id, handle));
855 void GlobalHandles::SetRetainedObjectInfo(UniqueId id,
856 RetainedObjectInfo* info) {
857 retainer_infos_.Add(ObjectGroupRetainerInfo(id, info));
861 void GlobalHandles::AddImplicitReferences(HeapObject** parent,
865 ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->is_independent());
866 for (size_t i = 0; i < length; ++i) {
867 ASSERT(!Node::FromLocation(children[i])->is_independent());
870 if (length == 0) return;
871 ImplicitRefGroup* group = new ImplicitRefGroup(parent, length);
872 for (size_t i = 0; i < length; ++i)
873 group->children[i] = children[i];
874 implicit_ref_groups_.Add(group);
878 void GlobalHandles::SetReferenceFromGroup(UniqueId id, Object** child) {
879 ASSERT(!Node::FromLocation(child)->is_independent());
880 implicit_ref_connections_.Add(ObjectGroupConnection(id, child));
884 void GlobalHandles::SetReference(HeapObject** parent, Object** child) {
885 ASSERT(!Node::FromLocation(child)->is_independent());
886 ImplicitRefGroup* group = new ImplicitRefGroup(parent, 1);
887 group->children[0] = child;
888 implicit_ref_groups_.Add(group);
892 void GlobalHandles::RemoveObjectGroups() {
893 for (int i = 0; i < object_groups_.length(); i++)
894 delete object_groups_.at(i);
895 object_groups_.Clear();
896 for (int i = 0; i < retainer_infos_.length(); ++i)
897 retainer_infos_[i].info->Dispose();
898 retainer_infos_.Clear();
899 object_group_connections_.Clear();
900 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
904 void GlobalHandles::RemoveImplicitRefGroups() {
905 for (int i = 0; i < implicit_ref_groups_.length(); i++) {
906 delete implicit_ref_groups_.at(i);
908 implicit_ref_groups_.Clear();
909 implicit_ref_connections_.Clear();
913 void GlobalHandles::TearDown() {
914 // TODO(1428): invoke weak callbacks.
918 void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() {
919 if (object_group_connections_.length() == 0) {
920 for (int i = 0; i < retainer_infos_.length(); ++i)
921 retainer_infos_[i].info->Dispose();
922 retainer_infos_.Clear();
923 implicit_ref_connections_.Clear();
927 object_group_connections_.Sort();
928 retainer_infos_.Sort();
929 implicit_ref_connections_.Sort();
931 int info_index = 0; // For iterating retainer_infos_.
932 UniqueId current_group_id(0);
933 int current_group_start = 0;
935 int current_implicit_refs_start = 0;
936 int current_implicit_refs_end = 0;
937 for (int i = 0; i <= object_group_connections_.length(); ++i) {
939 current_group_id = object_group_connections_[i].id;
940 if (i == object_group_connections_.length() ||
941 current_group_id != object_group_connections_[i].id) {
942 // Group detected: objects in indices [current_group_start, i[.
944 // Find out which implicit references are related to this group. (We want
945 // to ignore object groups which only have 1 object, but that object is
946 // needed as a representative object for the implicit refrerence group.)
947 while (current_implicit_refs_start < implicit_ref_connections_.length() &&
948 implicit_ref_connections_[current_implicit_refs_start].id <
950 ++current_implicit_refs_start;
951 current_implicit_refs_end = current_implicit_refs_start;
952 while (current_implicit_refs_end < implicit_ref_connections_.length() &&
953 implicit_ref_connections_[current_implicit_refs_end].id ==
955 ++current_implicit_refs_end;
957 if (current_implicit_refs_end > current_implicit_refs_start) {
958 // Find a representative object for the implicit references.
959 HeapObject** representative = NULL;
960 for (int j = current_group_start; j < i; ++j) {
961 Object** object = object_group_connections_[j].object;
962 if ((*object)->IsHeapObject()) {
963 representative = reinterpret_cast<HeapObject**>(object);
967 if (representative) {
968 ImplicitRefGroup* group = new ImplicitRefGroup(
970 current_implicit_refs_end - current_implicit_refs_start);
971 for (int j = current_implicit_refs_start;
972 j < current_implicit_refs_end;
974 group->children[j - current_implicit_refs_start] =
975 implicit_ref_connections_[j].object;
977 implicit_ref_groups_.Add(group);
979 current_implicit_refs_start = current_implicit_refs_end;
982 // Find a RetainedObjectInfo for the group.
983 RetainedObjectInfo* info = NULL;
984 while (info_index < retainer_infos_.length() &&
985 retainer_infos_[info_index].id < current_group_id) {
986 retainer_infos_[info_index].info->Dispose();
989 if (info_index < retainer_infos_.length() &&
990 retainer_infos_[info_index].id == current_group_id) {
991 // This object group has an associated ObjectGroupRetainerInfo.
992 info = retainer_infos_[info_index].info;
996 // Ignore groups which only contain one object.
997 if (i > current_group_start + 1) {
998 ObjectGroup* group = new ObjectGroup(i - current_group_start);
999 for (int j = current_group_start; j < i; ++j) {
1000 group->objects[j - current_group_start] =
1001 object_group_connections_[j].object;
1004 object_groups_.Add(group);
1009 if (i < object_group_connections_.length()) {
1010 current_group_id = object_group_connections_[i].id;
1011 current_group_start = i;
1015 object_group_connections_.Clear();
1016 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
1017 retainer_infos_.Clear();
1018 implicit_ref_connections_.Clear();
1022 EternalHandles::EternalHandles() : size_(0) {
1023 STATIC_ASSERT(v8::kUninitializedEternalIndex == kInvalidIndex);
1024 for (unsigned i = 0; i < ARRAY_SIZE(singleton_handles_); i++) {
1025 singleton_handles_[i] = kInvalidIndex;
1030 EternalHandles::~EternalHandles() {
1031 for (int i = 0; i < blocks_.length(); i++) delete[] blocks_[i];
1035 void EternalHandles::IterateAllRoots(ObjectVisitor* visitor) {
1037 for (int i = 0; i < blocks_.length(); i++) {
1039 Object** block = blocks_[i];
1040 visitor->VisitPointers(block, block + Min(limit, kSize));
1046 void EternalHandles::IterateNewSpaceRoots(ObjectVisitor* visitor) {
1047 for (int i = 0; i < new_space_indices_.length(); i++) {
1048 visitor->VisitPointer(GetLocation(new_space_indices_[i]));
1053 void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) {
1055 for (int i = 0; i < new_space_indices_.length(); i++) {
1056 int index = new_space_indices_[i];
1057 if (heap->InNewSpace(*GetLocation(index))) {
1058 new_space_indices_[last++] = index;
1061 new_space_indices_.Rewind(last);
1065 int EternalHandles::Create(Isolate* isolate, Object* object) {
1066 if (object == NULL) return kInvalidIndex;
1067 ASSERT_NE(isolate->heap()->the_hole_value(), object);
1068 int block = size_ >> kShift;
1069 int offset = size_ & kMask;
1072 Object** next_block = new Object*[kSize];
1073 Object* the_hole = isolate->heap()->the_hole_value();
1074 MemsetPointer(next_block, the_hole, kSize);
1075 blocks_.Add(next_block);
1077 ASSERT_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]);
1078 blocks_[block][offset] = object;
1079 if (isolate->heap()->InNewSpace(object)) {
1080 new_space_indices_.Add(size_);
1086 } } // namespace v8::internal