5 #include "src/global-handles.h" 7 #include "src/api-inl.h" 8 #include "src/cancelable-task.h" 9 #include "src/objects-inl.h" 10 #include "src/objects/slots.h" 11 #include "src/task-utils.h" 13 #include "src/visitors.h" 14 #include "src/vm-state-inl.h" 34 DCHECK_EQ(offsetof(
Node, object_), 0);
35 return reinterpret_cast<Node*
>(location);
39 DCHECK_EQ(offsetof(
Node, class_id_), Internals::kNodeClassIdOffset);
40 DCHECK_EQ(offsetof(
Node, flags_), Internals::kNodeFlagsOffset);
41 STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
42 Internals::kNodeStateMask);
43 STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
44 STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
45 STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
46 STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
47 Internals::kNodeIsIndependentShift);
48 STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
49 Internals::kNodeIsActiveShift);
52 #ifdef ENABLE_HANDLE_ZAPPING 56 object_ = kGlobalHandleZapValue;
59 set_independent(
false);
61 set_in_new_space_list(
false);
62 data_.next_free =
nullptr;
63 weak_callback_ =
nullptr;
67 void Initialize(
int index,
Node** first_free) {
68 object_ = kGlobalHandleZapValue;
69 index_ =
static_cast<uint8_t
>(index);
70 DCHECK(static_cast<int>(index_) == index);
72 set_in_new_space_list(
false);
73 data_.next_free = *first_free;
77 void Acquire(
Object*
object) {
78 DCHECK(state() == FREE);
79 object_ =
object->ptr();
81 set_independent(
false);
84 data_.parameter =
nullptr;
85 weak_callback_ =
nullptr;
92 object_ = kGlobalHandleZapValue;
99 object_ = kGlobalHandleZapValue;
101 set_independent(
false);
103 weak_callback_ =
nullptr;
110 const char* label() {
return state() == NORMAL ? data_.label :
nullptr; }
114 bool has_wrapper_class_id()
const {
118 uint16_t wrapper_class_id()
const {
return class_id_; }
122 State state()
const {
123 return NodeState::decode(flags_);
125 void set_state(State state) {
126 flags_ = NodeState::update(flags_, state);
129 bool is_independent() {
return IsIndependent::decode(flags_); }
130 void set_independent(
bool v) { flags_ = IsIndependent::update(flags_, v); }
133 return IsActive::decode(flags_);
135 void set_active(
bool v) {
136 flags_ = IsActive::update(flags_, v);
139 bool is_in_new_space_list() {
140 return IsInNewSpaceList::decode(flags_);
142 void set_in_new_space_list(
bool v) {
143 flags_ = IsInNewSpaceList::update(flags_, v);
146 WeaknessType weakness_type()
const {
147 return NodeWeaknessType::decode(flags_);
149 void set_weakness_type(WeaknessType weakness_type) {
150 flags_ = NodeWeaknessType::update(flags_, weakness_type);
153 bool IsNearDeath()
const {
155 return state() == PENDING || state() == NEAR_DEATH;
158 bool IsWeak()
const {
return state() == WEAK; }
160 bool IsInUse()
const {
return state() != FREE; }
162 bool IsPhantomCallback()
const {
163 return weakness_type() == PHANTOM_WEAK ||
164 weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS;
167 bool IsPhantomResetHandle()
const {
168 return weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
171 bool IsPendingPhantomCallback()
const {
172 return state() == PENDING && IsPhantomCallback();
175 bool IsPendingPhantomResetHandle()
const {
176 return state() == PENDING && IsPhantomResetHandle();
179 bool IsRetainer()
const {
180 return state() != FREE &&
181 !(state() == NEAR_DEATH && weakness_type() != FINALIZER_WEAK);
184 bool IsStrongRetainer()
const {
return state() == NORMAL; }
186 bool IsWeakRetainer()
const {
187 return state() == WEAK || state() == PENDING ||
188 (state() == NEAR_DEATH && weakness_type() == FINALIZER_WEAK);
192 DCHECK(state() == WEAK);
197 void set_parameter(
void* parameter) {
199 data_.parameter = parameter;
201 void* parameter()
const {
203 return data_.parameter;
208 DCHECK(state() == FREE);
209 return data_.next_free;
211 void set_next_free(
Node* value) {
212 DCHECK(state() == FREE);
213 data_.next_free = value;
216 void MakeWeak(
void* parameter,
218 v8::WeakCallbackType
type) {
219 DCHECK_NOT_NULL(phantom_callback);
221 CHECK_NE(object_, kGlobalHandleZapValue);
224 case v8::WeakCallbackType::kParameter:
225 set_weakness_type(PHANTOM_WEAK);
227 case v8::WeakCallbackType::kInternalFields:
228 set_weakness_type(PHANTOM_WEAK_2_EMBEDDER_FIELDS);
230 case v8::WeakCallbackType::kFinalizer:
231 set_weakness_type(FINALIZER_WEAK);
234 set_parameter(parameter);
235 weak_callback_ = phantom_callback;
238 void MakeWeak(
Address** location_addr) {
240 CHECK_NE(object_, kGlobalHandleZapValue);
242 set_weakness_type(PHANTOM_WEAK_RESET_HANDLE);
243 set_parameter(location_addr);
244 weak_callback_ =
nullptr;
247 void* ClearWeakness() {
249 void* p = parameter();
251 set_parameter(
nullptr);
255 void AnnotateStrongRetainer(
const char* label) {
256 DCHECK_EQ(state(), NORMAL);
260 void CollectPhantomCallbackData(
262 std::vector<PendingPhantomCallback>* pending_phantom_callbacks) {
263 DCHECK(weakness_type() == PHANTOM_WEAK ||
264 weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
265 DCHECK(state() == PENDING);
266 DCHECK_NOT_NULL(weak_callback_);
268 void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {
nullptr,
270 if (weakness_type() != PHANTOM_WEAK &&
object()->IsJSObject()) {
271 JSObject* jsobject = JSObject::cast(
object());
272 int field_count = jsobject->GetEmbedderFieldCount();
273 for (
int i = 0;
i < v8::kEmbedderFieldsInWeakCallback; ++
i) {
274 if (field_count ==
i)
break;
277 embedder_fields[
i] = pointer;
283 location().store(reinterpret_cast<Object*>(0x6057CA11));
286 this, weak_callback_, parameter(), embedder_fields));
288 set_state(NEAR_DEATH);
291 void ResetPhantomHandle() {
292 DCHECK(weakness_type() == PHANTOM_WEAK_RESET_HANDLE);
293 DCHECK(state() == PENDING);
294 DCHECK_NULL(weak_callback_);
300 bool PostGarbageCollectionProcessing(
Isolate* isolate) {
302 if (state() != Node::PENDING)
return false;
303 if (weak_callback_ ==
nullptr) {
307 set_state(NEAR_DEATH);
311 DCHECK(!
object()->IsExternalOneByteString() ||
312 ExternalOneByteString::cast(
object())->resource() !=
nullptr);
313 DCHECK(!
object()->IsExternalTwoByteString() ||
314 ExternalTwoByteString::cast(
object())->resource() !=
nullptr);
315 if (weakness_type() != FINALIZER_WEAK) {
322 void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {
nullptr,
325 parameter(), embedder_fields,
nullptr);
326 weak_callback_(data);
330 CHECK(state() != NEAR_DEATH);
338 inline void IncreaseBlockUses();
339 inline void DecreaseBlockUses();
359 class NodeState :
public BitField<State, 0, 3> {};
360 class IsIndependent :
public BitField<bool, 3, 1> {};
362 class IsActive :
public BitField<bool, 4, 1> {};
363 class IsInNewSpaceList :
public BitField<bool, 5, 1> {};
364 class NodeWeaknessType :
public BitField<WeaknessType, 6, 2> {};
381 DISALLOW_COPY_AND_ASSIGN(
Node);
387 static const int kSize = 256;
394 global_handles_(global_handles) {}
396 void PutNodesOnFreeList(
Node** first_free) {
397 for (
int i = kSize - 1;
i >= 0; --
i) {
398 nodes_[
i].Initialize(
i, first_free);
402 Node* node_at(
int index) {
403 DCHECK(0 <= index && index < kSize);
404 return &nodes_[index];
407 void IncreaseUses() {
408 DCHECK_LT(used_nodes_, kSize);
409 if (used_nodes_++ == 0) {
410 NodeBlock* old_first = global_handles_->first_used_block_;
411 global_handles_->first_used_block_ =
this;
412 next_used_ = old_first;
413 prev_used_ =
nullptr;
414 if (old_first ==
nullptr)
return;
415 old_first->prev_used_ =
this;
419 void DecreaseUses() {
420 DCHECK_GT(used_nodes_, 0);
421 if (--used_nodes_ == 0) {
422 if (next_used_ !=
nullptr) next_used_->prev_used_ = prev_used_;
423 if (prev_used_ !=
nullptr) prev_used_->next_used_ = next_used_;
424 if (
this == global_handles_->first_used_block_) {
425 global_handles_->first_used_block_ = next_used_;
433 NodeBlock* next()
const {
return next_; }
436 NodeBlock* next_used()
const {
return next_used_; }
437 NodeBlock* prev_used()
const {
return prev_used_; }
450 return FindBlock()->global_handles();
455 intptr_t ptr =
reinterpret_cast<intptr_t
>(
this);
456 ptr = ptr - index_ *
sizeof(
Node);
457 NodeBlock* block =
reinterpret_cast<NodeBlock*
>(ptr);
458 DCHECK(block->node_at(index_) ==
this);
463 void GlobalHandles::Node::IncreaseBlockUses() {
464 NodeBlock* node_block = FindBlock();
465 node_block->IncreaseUses();
466 GlobalHandles* global_handles = node_block->global_handles();
467 global_handles->isolate()->counters()->global_handles()->Increment();
468 global_handles->number_of_global_handles_++;
472 void GlobalHandles::Node::DecreaseBlockUses() {
473 NodeBlock* node_block = FindBlock();
474 GlobalHandles* global_handles = node_block->global_handles();
475 data_.next_free = global_handles->first_free_;
476 global_handles->first_free_ =
this;
477 node_block->DecreaseUses();
478 global_handles->isolate()->counters()->global_handles()->Decrement();
479 global_handles->number_of_global_handles_--;
486 : block_(global_handles->first_used_block_),
489 bool done()
const {
return block_ ==
nullptr; }
493 return block_->node_at(index_);
498 if (++index_ < NodeBlock::kSize)
return;
500 block_ = block_->next_used();
510 GlobalHandles::GlobalHandles(
Isolate* isolate)
512 first_block_(nullptr),
513 first_used_block_(nullptr),
514 first_free_(nullptr),
515 number_of_global_handles_(0),
516 post_gc_processing_count_(0),
517 number_of_phantom_handle_resets_(0) {}
519 GlobalHandles::~GlobalHandles() {
520 NodeBlock* block = first_block_;
521 while (block !=
nullptr) {
522 NodeBlock* tmp = block->next();
526 first_block_ =
nullptr;
530 Handle<Object> GlobalHandles::Create(Object* value) {
531 if (first_free_ ==
nullptr) {
532 first_block_ =
new NodeBlock(
this, first_block_);
533 first_block_->PutNodesOnFreeList(&first_free_);
535 DCHECK_NOT_NULL(first_free_);
537 Node* result = first_free_;
538 first_free_ = result->next_free();
539 result->Acquire(value);
540 if (Heap::InNewSpace(value) && !result->is_in_new_space_list()) {
541 new_space_nodes_.push_back(result);
542 result->set_in_new_space_list(
true);
544 return result->handle();
547 Handle<Object> GlobalHandles::Create(Address value) {
548 return Create(reinterpret_cast<Object*>(value));
551 Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
552 DCHECK_NOT_NULL(location);
553 GlobalHandles* global_handles =
554 Node::FromLocation(location)->GetGlobalHandles();
556 if (i::FLAG_verify_heap) {
557 ObjectPtr(*location)->ObjectVerify(global_handles->isolate());
559 #endif // VERIFY_HEAP 560 return global_handles->Create(*location);
563 void GlobalHandles::Destroy(Address* location) {
564 if (location !=
nullptr) Node::FromLocation(location)->Release();
570 void GlobalHandles::MakeWeak(Address* location,
void* parameter,
571 GenericCallback phantom_callback,
572 v8::WeakCallbackType type) {
573 Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
576 void GlobalHandles::MakeWeak(Address** location_addr) {
577 Node::FromLocation(*location_addr)->MakeWeak(location_addr);
580 void* GlobalHandles::ClearWeakness(Address* location) {
581 return Node::FromLocation(location)->ClearWeakness();
584 void GlobalHandles::AnnotateStrongRetainer(Address* location,
586 Node::FromLocation(location)->AnnotateStrongRetainer(label);
589 bool GlobalHandles::IsNearDeath(Address* location) {
590 return Node::FromLocation(location)->IsNearDeath();
593 bool GlobalHandles::IsWeak(Address* location) {
594 return Node::FromLocation(location)->IsWeak();
598 void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) {
599 for (NodeIterator it(
this); !it.done(); it.Advance()) {
600 Node* node = it.node();
601 if (node->IsWeakRetainer() && node->state() == Node::PENDING) {
602 DCHECK(!node->IsPhantomCallback());
603 DCHECK(!node->IsPhantomResetHandle());
605 v->VisitRootPointer(Root::kGlobalHandles, node->label(),
612 void GlobalHandles::IterateWeakRootsForPhantomHandles(
613 WeakSlotCallbackWithHeap should_reset_handle) {
614 for (NodeIterator it(
this); !it.done(); it.Advance()) {
615 Node* node = it.node();
616 if (node->IsWeakRetainer() &&
617 should_reset_handle(isolate()->heap(), node->location())) {
618 if (node->IsPhantomResetHandle()) {
620 node->ResetPhantomHandle();
621 ++number_of_phantom_handle_resets_;
622 }
else if (node->IsPhantomCallback()) {
624 node->CollectPhantomCallbackData(&pending_phantom_callbacks_);
630 void GlobalHandles::IdentifyWeakHandles(
631 WeakSlotCallbackWithHeap should_reset_handle) {
632 for (NodeIterator it(
this); !it.done(); it.Advance()) {
633 Node* node = it.node();
634 if (node->IsWeak() &&
635 should_reset_handle(isolate()->heap(), node->location())) {
636 if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
643 void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(RootVisitor* v) {
644 for (Node* node : new_space_nodes_) {
645 if (node->IsStrongRetainer() ||
646 (node->IsWeakRetainer() && !node->is_independent() &&
647 node->is_active())) {
648 v->VisitRootPointer(Root::kGlobalHandles, node->label(),
654 void GlobalHandles::IterateNewSpaceStrongAndDependentRootsAndIdentifyUnmodified(
655 RootVisitor* v,
size_t start,
size_t end) {
656 for (
size_t i = start;
i < end; ++
i) {
657 Node* node = new_space_nodes_[
i];
658 if (node->IsWeak() && !JSObject::IsUnmodifiedApiObject(node->location())) {
659 node->set_active(
true);
661 if (node->IsStrongRetainer() ||
662 (node->IsWeakRetainer() && !node->is_independent() &&
663 node->is_active())) {
664 v->VisitRootPointer(Root::kGlobalHandles, node->label(),
670 void GlobalHandles::IdentifyWeakUnmodifiedObjects(
671 WeakSlotCallback is_unmodified) {
672 for (Node* node : new_space_nodes_) {
673 if (node->IsWeak() && !is_unmodified(node->location())) {
674 node->set_active(
true);
679 void GlobalHandles::MarkNewSpaceWeakUnmodifiedObjectsPending(
680 WeakSlotCallbackWithHeap is_dead) {
681 for (Node* node : new_space_nodes_) {
682 DCHECK(node->is_in_new_space_list());
683 if ((node->is_independent() || !node->is_active()) && node->IsWeak() &&
684 is_dead(isolate_->heap(), node->location())) {
685 if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
692 void GlobalHandles::IterateNewSpaceWeakUnmodifiedRootsForFinalizers(
694 for (Node* node : new_space_nodes_) {
695 DCHECK(node->is_in_new_space_list());
696 if ((node->is_independent() || !node->is_active()) &&
697 node->IsWeakRetainer() && (node->state() == Node::PENDING)) {
698 DCHECK(!node->IsPhantomCallback());
699 DCHECK(!node->IsPhantomResetHandle());
701 v->VisitRootPointer(Root::kGlobalHandles, node->label(),
707 void GlobalHandles::IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles(
708 RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle) {
709 for (Node* node : new_space_nodes_) {
710 DCHECK(node->is_in_new_space_list());
711 if ((node->is_independent() || !node->is_active()) &&
712 node->IsWeakRetainer() && (node->state() != Node::PENDING)) {
713 DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback());
714 if (should_reset_handle(isolate_->heap(), node->location())) {
715 if (node->IsPhantomResetHandle()) {
717 node->ResetPhantomHandle();
718 ++number_of_phantom_handle_resets_;
720 }
else if (node->IsPhantomCallback()) {
722 node->CollectPhantomCallbackData(&pending_phantom_callbacks_);
728 v->VisitRootPointer(Root::kGlobalHandles, node->label(),
735 void GlobalHandles::InvokeSecondPassPhantomCallbacksFromTask() {
736 DCHECK(second_pass_callbacks_task_posted_);
737 second_pass_callbacks_task_posted_ =
false;
738 TRACE_EVENT0(
"v8",
"V8.GCPhantomHandleProcessingCallback");
739 isolate()->heap()->CallGCPrologueCallbacks(
740 GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
741 InvokeSecondPassPhantomCallbacks();
742 isolate()->heap()->CallGCEpilogueCallbacks(
743 GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
746 void GlobalHandles::InvokeSecondPassPhantomCallbacks() {
747 while (!second_pass_callbacks_.empty()) {
748 auto callback = second_pass_callbacks_.back();
749 second_pass_callbacks_.pop_back();
750 DCHECK_NULL(callback.node());
752 callback.Invoke(isolate());
756 int GlobalHandles::PostScavengeProcessing(
757 const int initial_post_gc_processing_count) {
759 for (Node* node : new_space_nodes_) {
760 DCHECK(node->is_in_new_space_list());
761 if (!node->IsRetainer()) {
770 if (!node->is_independent() && (node->is_active())) {
771 node->set_active(
false);
774 node->set_active(
false);
776 if (node->PostGarbageCollectionProcessing(isolate_)) {
777 if (initial_post_gc_processing_count != post_gc_processing_count_) {
785 if (!node->IsRetainer()) {
793 int GlobalHandles::PostMarkSweepProcessing(
794 const int initial_post_gc_processing_count) {
796 for (NodeIterator it(
this); !it.done(); it.Advance()) {
797 if (!it.node()->IsRetainer()) {
802 it.node()->set_active(
false);
803 if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
804 if (initial_post_gc_processing_count != post_gc_processing_count_) {
809 if (!it.node()->IsRetainer()) {
817 void GlobalHandles::UpdateListOfNewSpaceNodes() {
819 for (Node* node : new_space_nodes_) {
820 DCHECK(node->is_in_new_space_list());
821 if (node->IsRetainer()) {
822 if (Heap::InNewSpace(node->object())) {
823 new_space_nodes_[last++] = node;
824 isolate_->heap()->IncrementNodesCopiedInNewSpace();
826 node->set_in_new_space_list(
false);
827 isolate_->heap()->IncrementNodesPromoted();
830 node->set_in_new_space_list(
false);
831 isolate_->heap()->IncrementNodesDiedInNewSpace();
834 DCHECK_LE(last, new_space_nodes_.size());
835 new_space_nodes_.resize(last);
836 new_space_nodes_.shrink_to_fit();
839 int GlobalHandles::InvokeFirstPassWeakCallbacks() {
841 std::vector<PendingPhantomCallback> pending_phantom_callbacks;
842 pending_phantom_callbacks.swap(pending_phantom_callbacks_);
845 for (
auto callback : pending_phantom_callbacks) {
847 if (callback.node() ==
nullptr)
continue;
848 callback.Invoke(isolate());
849 if (callback.callback()) second_pass_callbacks_.push_back(callback);
856 void GlobalHandles::InvokeOrScheduleSecondPassPhantomCallbacks(
857 bool synchronous_second_pass) {
858 if (!second_pass_callbacks_.empty()) {
859 if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) {
860 isolate()->heap()->CallGCPrologueCallbacks(
861 GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
862 InvokeSecondPassPhantomCallbacks();
863 isolate()->heap()->CallGCEpilogueCallbacks(
864 GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
865 }
else if (!second_pass_callbacks_task_posted_) {
866 second_pass_callbacks_task_posted_ =
true;
867 auto taskrunner = V8::GetCurrentPlatform()->GetForegroundTaskRunner(
868 reinterpret_cast<v8::Isolate*>(isolate()));
869 taskrunner->PostTask(MakeCancelableTask(
870 isolate(), [
this] { InvokeSecondPassPhantomCallbacksFromTask(); }));
875 void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate) {
876 Data::Callback* callback_addr =
nullptr;
877 if (node_ !=
nullptr) {
879 DCHECK(node_->state() == Node::NEAR_DEATH);
880 callback_addr = &callback_;
882 Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
883 embedder_fields_, callback_addr);
884 Data::Callback callback = callback_;
887 if (node_ !=
nullptr) {
891 CHECK_WITH_MSG(Node::FREE == node_->state(),
892 "Handle not reset in first callback. See comments on " 893 "|v8::WeakCallbackInfo|.");
898 int GlobalHandles::PostGarbageCollectionProcessing(
899 GarbageCollector collector,
const v8::GCCallbackFlags gc_callback_flags) {
903 DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
904 const int initial_post_gc_processing_count = ++post_gc_processing_count_;
906 bool synchronous_second_pass =
907 isolate_->heap()->IsTearingDown() ||
909 (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage |
910 kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
911 InvokeOrScheduleSecondPassPhantomCallbacks(synchronous_second_pass);
912 if (initial_post_gc_processing_count != post_gc_processing_count_) {
917 if (Heap::IsYoungGenerationCollector(collector)) {
918 freed_nodes += PostScavengeProcessing(initial_post_gc_processing_count);
920 freed_nodes += PostMarkSweepProcessing(initial_post_gc_processing_count);
922 if (initial_post_gc_processing_count != post_gc_processing_count_) {
927 if (initial_post_gc_processing_count == post_gc_processing_count_) {
928 UpdateListOfNewSpaceNodes();
933 void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
934 for (NodeIterator it(
this); !it.done(); it.Advance()) {
935 if (it.node()->IsStrongRetainer()) {
936 v->VisitRootPointer(Root::kGlobalHandles, it.node()->label(),
937 it.node()->location());
942 void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
943 for (NodeIterator it(
this); !it.done(); it.Advance()) {
944 if (it.node()->IsWeak()) {
945 v->VisitRootPointer(Root::kGlobalHandles, it.node()->label(),
946 it.node()->location());
952 void GlobalHandles::IterateAllRoots(RootVisitor* v) {
953 for (NodeIterator it(
this); !it.done(); it.Advance()) {
954 if (it.node()->IsRetainer()) {
955 v->VisitRootPointer(Root::kGlobalHandles, it.node()->label(),
956 it.node()->location());
962 void GlobalHandles::IterateAllNewSpaceRoots(RootVisitor* v) {
963 for (Node* node : new_space_nodes_) {
964 if (node->IsRetainer()) {
965 v->VisitRootPointer(Root::kGlobalHandles, node->label(),
972 void GlobalHandles::IterateNewSpaceRoots(RootVisitor* v,
size_t start,
974 for (
size_t i = start;
i < end; ++
i) {
975 Node* node = new_space_nodes_[
i];
976 if (node->IsRetainer()) {
977 v->VisitRootPointer(Root::kGlobalHandles, node->label(),
984 void GlobalHandles::ApplyPersistentHandleVisitor(
985 v8::PersistentHandleVisitor* visitor, GlobalHandles::Node* node) {
986 v8::Value* value = ToApi<v8::Value>(node->handle());
987 visitor->VisitPersistentHandle(
989 node->wrapper_class_id());
993 void GlobalHandles::IterateAllRootsWithClassIds(
994 v8::PersistentHandleVisitor* visitor) {
995 for (NodeIterator it(
this); !it.done(); it.Advance()) {
996 if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
997 ApplyPersistentHandleVisitor(visitor, it.node());
1004 void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(
1005 v8::PersistentHandleVisitor* visitor) {
1006 for (Node* node : new_space_nodes_) {
1007 if (node->IsRetainer() && node->has_wrapper_class_id()) {
1008 ApplyPersistentHandleVisitor(visitor, node);
1015 void GlobalHandles::IterateWeakRootsInNewSpaceWithClassIds(
1016 v8::PersistentHandleVisitor* visitor) {
1017 for (Node* node : new_space_nodes_) {
1018 if (node->has_wrapper_class_id() && node->IsWeak()) {
1019 ApplyPersistentHandleVisitor(visitor, node);
1024 void GlobalHandles::RecordStats(HeapStats* stats) {
1025 *stats->global_handle_count = 0;
1026 *stats->weak_global_handle_count = 0;
1027 *stats->pending_global_handle_count = 0;
1028 *stats->near_death_global_handle_count = 0;
1029 *stats->free_global_handle_count = 0;
1030 for (NodeIterator it(
this); !it.done(); it.Advance()) {
1031 *stats->global_handle_count += 1;
1032 if (it.node()->state() == Node::WEAK) {
1033 *stats->weak_global_handle_count += 1;
1034 }
else if (it.node()->state() == Node::PENDING) {
1035 *stats->pending_global_handle_count += 1;
1036 }
else if (it.node()->state() == Node::NEAR_DEATH) {
1037 *stats->near_death_global_handle_count += 1;
1038 }
else if (it.node()->state() == Node::FREE) {
1039 *stats->free_global_handle_count += 1;
1046 void GlobalHandles::PrintStats() {
1053 for (NodeIterator it(
this); !it.done(); it.Advance()) {
1055 if (it.node()->state() == Node::WEAK) weak++;
1056 if (it.node()->state() == Node::PENDING) pending++;
1057 if (it.node()->state() == Node::NEAR_DEATH) near_death++;
1058 if (it.node()->state() == Node::FREE) destroyed++;
1061 PrintF(
"Global Handle Statistics:\n");
1062 PrintF(
" allocated memory = %" PRIuS
"B\n", total *
sizeof(Node));
1063 PrintF(
" # weak = %d\n", weak);
1064 PrintF(
" # pending = %d\n", pending);
1065 PrintF(
" # near_death = %d\n", near_death);
1066 PrintF(
" # free = %d\n", destroyed);
1067 PrintF(
" # total = %d\n", total);
1071 void GlobalHandles::Print() {
1072 PrintF(
"Global handles:\n");
1073 for (NodeIterator it(
this); !it.done(); it.Advance()) {
1074 PrintF(
" handle %p to %p%s\n", it.node()->location().ToVoidPtr(),
1075 reinterpret_cast<void*
>(it.node()->object()->ptr()),
1076 it.node()->IsWeak() ?
" (weak)" :
"");
1082 void GlobalHandles::TearDown() {}
1084 EternalHandles::EternalHandles() : size_(0) {}
1086 EternalHandles::~EternalHandles() {
1087 for (Address* block : blocks_)
delete[] block;
1090 void EternalHandles::IterateAllRoots(RootVisitor* visitor) {
1092 for (Address* block : blocks_) {
1093 DCHECK_GT(limit, 0);
1094 visitor->VisitRootPointers(Root::kEternalHandles,
nullptr,
1096 ObjectSlot(block + Min(limit, kSize)));
1101 void EternalHandles::IterateNewSpaceRoots(RootVisitor* visitor) {
1102 for (
int index : new_space_indices_) {
1103 visitor->VisitRootPointer(Root::kEternalHandles,
nullptr,
1104 ObjectSlot(GetLocation(index)));
1108 void EternalHandles::PostGarbageCollectionProcessing() {
1110 for (
int index : new_space_indices_) {
1111 if (Heap::InNewSpace(ObjectPtr(*GetLocation(index)))) {
1112 new_space_indices_[last++] = index;
1115 DCHECK_LE(last, new_space_indices_.size());
1116 new_space_indices_.resize(last);
1120 void EternalHandles::Create(Isolate* isolate, Object*
object,
int* index) {
1121 DCHECK_EQ(kInvalidIndex, *index);
1122 if (
object ==
nullptr)
return;
1123 Object* the_hole = ReadOnlyRoots(isolate).the_hole_value();
1124 DCHECK_NE(the_hole,
object);
1125 int block = size_ >> kShift;
1126 int offset = size_ & kMask;
1129 Address* next_block =
new Address[kSize];
1130 MemsetPointer(ObjectSlot(next_block), the_hole, kSize);
1131 blocks_.push_back(next_block);
1133 DCHECK_EQ(the_hole->ptr(), blocks_[block][offset]);
1134 blocks_[block][offset] =
object->ptr();
1135 if (Heap::InNewSpace(
object)) {
1136 new_space_indices_.push_back(size_);
static const uint16_t kPersistentHandleNoClassId