diff options
Diffstat (limited to 'deps/v8/src/handles/global-handles.cc')
-rw-r--r-- | deps/v8/src/handles/global-handles.cc | 100 |
1 files changed, 82 insertions, 18 deletions
diff --git a/deps/v8/src/handles/global-handles.cc b/deps/v8/src/handles/global-handles.cc index db4f806e58..aed5b3fa83 100644 --- a/deps/v8/src/handles/global-handles.cc +++ b/deps/v8/src/handles/global-handles.cc @@ -22,6 +22,10 @@ namespace internal { namespace { +// Specifies whether V8 expects the holder memory of a global handle to be live +// or dead. +enum class HandleHolder { kLive, kDead }; + constexpr size_t kBlockSize = 256; } // namespace @@ -32,6 +36,7 @@ class GlobalHandles::NodeBlock final { using BlockType = NodeBlock<_NodeType>; using NodeType = _NodeType; + V8_INLINE static const NodeBlock* From(const NodeType* node); V8_INLINE static NodeBlock* From(NodeType* node); NodeBlock(GlobalHandles* global_handles, @@ -67,6 +72,16 @@ class GlobalHandles::NodeBlock final { }; template <class NodeType> +const GlobalHandles::NodeBlock<NodeType>* +GlobalHandles::NodeBlock<NodeType>::From(const NodeType* node) { + uintptr_t ptr = reinterpret_cast<const uintptr_t>(node) - + sizeof(NodeType) * node->index(); + const BlockType* block = reinterpret_cast<const BlockType*>(ptr); + DCHECK_EQ(node, block->at(node->index())); + return block; +} + +template <class NodeType> GlobalHandles::NodeBlock<NodeType>* GlobalHandles::NodeBlock<NodeType>::From( NodeType* node) { uintptr_t ptr = @@ -239,6 +254,10 @@ void GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) { template <class Child> class NodeBase { public: + static const Child* FromLocation(const Address* location) { + return reinterpret_cast<const Child*>(location); + } + static Child* FromLocation(Address* location) { return reinterpret_cast<Child*>(location); } @@ -532,7 +551,8 @@ class GlobalHandles::Node final : public NodeBase<GlobalHandles::Node> { set_state(NEAR_DEATH); } - void ResetPhantomHandle() { + void ResetPhantomHandle(HandleHolder handle_holder) { + DCHECK_EQ(HandleHolder::kLive, handle_holder); DCHECK_EQ(PHANTOM_WEAK_RESET_HANDLE, weakness_type()); DCHECK_EQ(PENDING, state()); DCHECK_NULL(weak_callback_); @@ -580,10 +600,9 @@ class GlobalHandles::Node final : public NodeBase<GlobalHandles::Node> { // This stores three flags (independent, partially_dependent and // in_young_list) and a State. - class NodeState : public BitField8<State, 0, 3> {}; - class IsInYoungList : public BitField8<bool, NodeState::kNext, 1> {}; - class NodeWeaknessType - : public BitField8<WeaknessType, IsInYoungList::kNext, 2> {}; + using NodeState = BitField8<State, 0, 3>; + using IsInYoungList = NodeState::Next<bool, 1>; + using NodeWeaknessType = IsInYoungList::Next<WeaknessType, 2>; // Handle specific callback - might be a weak reference in disguise. WeakCallbackInfo<void>::Callback weak_callback_; @@ -615,6 +634,9 @@ class GlobalHandles::TracedNode final bool is_root() const { return IsRoot::decode(flags_); } void set_root(bool v) { flags_ = IsRoot::update(flags_, v); } + bool has_destructor() const { return HasDestructor::decode(flags_); } + void set_has_destructor(bool v) { flags_ = HasDestructor::update(flags_, v); } + void SetFinalizationCallback(void* parameter, WeakCallbackInfo<void>::Callback callback) { set_parameter(parameter); @@ -641,18 +663,21 @@ class GlobalHandles::TracedNode final set_state(NEAR_DEATH); } - void ResetPhantomHandle() { + void ResetPhantomHandle(HandleHolder handle_holder) { DCHECK(IsInUse()); - Address** handle = reinterpret_cast<Address**>(data_.parameter); - *handle = nullptr; + if (handle_holder == HandleHolder::kLive) { + Address** handle = reinterpret_cast<Address**>(data_.parameter); + *handle = nullptr; + } NodeSpace<TracedNode>::Release(this); DCHECK(!IsInUse()); } protected: - class NodeState : public BitField8<State, 0, 2> {}; - class IsInYoungList : public BitField8<bool, NodeState::kNext, 1> {}; - class IsRoot : public BitField8<bool, IsInYoungList::kNext, 1> {}; + using NodeState = BitField8<State, 0, 2>; + using IsInYoungList = NodeState::Next<bool, 1>; + using IsRoot = IsInYoungList::Next<bool, 1>; + using HasDestructor = IsRoot::Next<bool, 1>; void ClearImplFields() { set_root(true); @@ -691,18 +716,21 @@ Handle<Object> GlobalHandles::Create(Address value) { return Create(Object(value)); } -Handle<Object> GlobalHandles::CreateTraced(Object value, Address* slot) { +Handle<Object> GlobalHandles::CreateTraced(Object value, Address* slot, + bool has_destructor) { GlobalHandles::TracedNode* result = traced_nodes_->Acquire(value); if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) { traced_young_nodes_.push_back(result); result->set_in_young_list(true); } result->set_parameter(slot); + result->set_has_destructor(has_destructor); return result->handle(); } -Handle<Object> GlobalHandles::CreateTraced(Address value, Address* slot) { - return CreateTraced(Object(value), slot); +Handle<Object> GlobalHandles::CreateTraced(Address value, Address* slot, + bool has_destructor) { + return CreateTraced(Object(value), slot, has_destructor); } Handle<Object> GlobalHandles::CopyGlobal(Address* location) { @@ -717,6 +745,27 @@ Handle<Object> GlobalHandles::CopyGlobal(Address* location) { return global_handles->Create(*location); } +// static +void GlobalHandles::CopyTracedGlobal(const Address* const* from, Address** to) { + DCHECK_NOT_NULL(*from); + DCHECK_NULL(*to); + const TracedNode* node = TracedNode::FromLocation(*from); + // Copying a traced handle with finalization callback is prohibited because + // the callback may require knowing about multiple copies of the traced + // handle. + CHECK(!node->HasFinalizationCallback()); + GlobalHandles* global_handles = + NodeBlock<TracedNode>::From(node)->global_handles(); + Handle<Object> o = global_handles->CreateTraced( + node->object(), reinterpret_cast<Address*>(to), node->has_destructor()); + *to = o.location(); +#ifdef VERIFY_HEAP + if (i::FLAG_verify_heap) { + Object(**to).ObjectVerify(global_handles->isolate()); + } +#endif // VERIFY_HEAP +} + void GlobalHandles::MoveGlobal(Address** from, Address** to) { DCHECK_NOT_NULL(*from); DCHECK_NOT_NULL(*to); @@ -809,7 +858,7 @@ void GlobalHandles::IterateWeakRootsForPhantomHandles( should_reset_handle(isolate()->heap(), node->location())) { if (node->IsPhantomResetHandle()) { node->MarkPending(); - node->ResetPhantomHandle(); + node->ResetPhantomHandle(HandleHolder::kLive); ++number_of_phantom_handle_resets_; } else if (node->IsPhantomCallback()) { node->MarkPending(); @@ -821,7 +870,8 @@ void GlobalHandles::IterateWeakRootsForPhantomHandles( if (node->IsInUse() && should_reset_handle(isolate()->heap(), node->location())) { if (node->IsPhantomResetHandle()) { - node->ResetPhantomHandle(); + node->ResetPhantomHandle(node->has_destructor() ? HandleHolder::kLive + : HandleHolder::kDead); ++number_of_phantom_handle_resets_; } else { node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_); @@ -907,7 +957,7 @@ void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles( DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback()); if (node->IsPhantomResetHandle()) { node->MarkPending(); - node->ResetPhantomHandle(); + node->ResetPhantomHandle(HandleHolder::kLive); ++number_of_phantom_handle_resets_; } else if (node->IsPhantomCallback()) { node->MarkPending(); @@ -922,6 +972,9 @@ void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles( } } } + + LocalEmbedderHeapTracer* const tracer = + isolate()->heap()->local_embedder_heap_tracer(); for (TracedNode* node : traced_young_nodes_) { if (!node->IsInUse()) continue; @@ -929,7 +982,18 @@ void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles( !should_reset_handle(isolate_->heap(), node->location())); if (should_reset_handle(isolate_->heap(), node->location())) { if (node->IsPhantomResetHandle()) { - node->ResetPhantomHandle(); + if (node->has_destructor()) { + // For handles with destructor it is guaranteed that the embedder + // memory is still alive as the destructor would have otherwise + // removed the memory. + node->ResetPhantomHandle(HandleHolder::kLive); + } else { + v8::Value* value = ToApi<v8::Value>(node->handle()); + tracer->ResetHandleInNonTracingGC( + *reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value)); + DCHECK(!node->IsInUse()); + } + ++number_of_phantom_handle_resets_; } else { node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_); |