11cb0ef41Sopenharmony_ci// Copyright 2009 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/handles/global-handles.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <algorithm> 81cb0ef41Sopenharmony_ci#include <atomic> 91cb0ef41Sopenharmony_ci#include <climits> 101cb0ef41Sopenharmony_ci#include <cstdint> 111cb0ef41Sopenharmony_ci#include <map> 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ci#include "include/v8-traced-handle.h" 141cb0ef41Sopenharmony_ci#include "src/api/api-inl.h" 151cb0ef41Sopenharmony_ci#include "src/base/bits.h" 161cb0ef41Sopenharmony_ci#include "src/base/compiler-specific.h" 171cb0ef41Sopenharmony_ci#include "src/base/sanitizer/asan.h" 181cb0ef41Sopenharmony_ci#include "src/common/allow-deprecated.h" 191cb0ef41Sopenharmony_ci#include "src/common/globals.h" 201cb0ef41Sopenharmony_ci#include "src/execution/vm-state-inl.h" 211cb0ef41Sopenharmony_ci#include "src/heap/base/stack.h" 221cb0ef41Sopenharmony_ci#include "src/heap/embedder-tracing.h" 231cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h" 241cb0ef41Sopenharmony_ci#include "src/heap/heap-write-barrier-inl.h" 251cb0ef41Sopenharmony_ci#include "src/heap/heap-write-barrier.h" 261cb0ef41Sopenharmony_ci#include "src/init/v8.h" 271cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 281cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 291cb0ef41Sopenharmony_ci#include "src/objects/slots.h" 301cb0ef41Sopenharmony_ci#include "src/objects/visitors.h" 311cb0ef41Sopenharmony_ci#include "src/tasks/cancelable-task.h" 321cb0ef41Sopenharmony_ci#include "src/tasks/task-utils.h" 331cb0ef41Sopenharmony_ci#include "src/utils/utils.h" 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_cinamespace v8 { 361cb0ef41Sopenharmony_cinamespace internal { 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_cinamespace { 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ciconstexpr size_t kBlockSize = 256; 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci} // namespace 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_citemplate <class _NodeType> 451cb0ef41Sopenharmony_ciclass GlobalHandles::NodeBlock final { 461cb0ef41Sopenharmony_ci public: 471cb0ef41Sopenharmony_ci using BlockType = NodeBlock<_NodeType>; 481cb0ef41Sopenharmony_ci using NodeType = _NodeType; 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci V8_INLINE static const NodeBlock* From(const NodeType* node); 511cb0ef41Sopenharmony_ci V8_INLINE static NodeBlock* From(NodeType* node); 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci NodeBlock(GlobalHandles* global_handles, 541cb0ef41Sopenharmony_ci GlobalHandles::NodeSpace<NodeType>* space, 551cb0ef41Sopenharmony_ci NodeBlock* next) V8_NOEXCEPT : next_(next), 561cb0ef41Sopenharmony_ci global_handles_(global_handles), 571cb0ef41Sopenharmony_ci space_(space) {} 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci NodeBlock(const NodeBlock&) = delete; 601cb0ef41Sopenharmony_ci NodeBlock& operator=(const NodeBlock&) = delete; 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci NodeType* at(size_t index) { return &nodes_[index]; } 631cb0ef41Sopenharmony_ci const NodeType* at(size_t index) const { return &nodes_[index]; } 641cb0ef41Sopenharmony_ci GlobalHandles::NodeSpace<NodeType>* space() const { return space_; } 651cb0ef41Sopenharmony_ci GlobalHandles* global_handles() const { return global_handles_; } 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci V8_INLINE bool IncreaseUsage(); 681cb0ef41Sopenharmony_ci V8_INLINE bool DecreaseUsage(); 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci V8_INLINE void ListAdd(NodeBlock** top); 711cb0ef41Sopenharmony_ci V8_INLINE void ListRemove(NodeBlock** top); 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci NodeBlock* next() const { return next_; } 741cb0ef41Sopenharmony_ci NodeBlock* next_used() const { return next_used_; } 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci void set_markbit(size_t index) { 771cb0ef41Sopenharmony_ci const auto [cell, bit] = CellAndBit(index); 781cb0ef41Sopenharmony_ci reinterpret_cast<std::atomic<CellType>&>(mark_bits_[cell]) 791cb0ef41Sopenharmony_ci .fetch_or(CellType{1} << bit, std::memory_order_relaxed); 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci void clear_markbit(size_t index) { 831cb0ef41Sopenharmony_ci const auto [cell, bit] = CellAndBit(index); 841cb0ef41Sopenharmony_ci mark_bits_[cell] &= ~(CellType{1} << bit); 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci bool markbit(size_t index) const { 881cb0ef41Sopenharmony_ci const auto [cell, bit] = CellAndBit(index); 891cb0ef41Sopenharmony_ci return mark_bits_[cell] & CellType{1} << bit; 901cb0ef41Sopenharmony_ci } 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci private: 931cb0ef41Sopenharmony_ci using CellType = uint32_t; 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci std::tuple<CellType, CellType> CellAndBit(size_t index) const { 961cb0ef41Sopenharmony_ci static constexpr CellType kMarkBitCellSizeLog2 = 5; 971cb0ef41Sopenharmony_ci static_assert(base::bits::IsPowerOfTwo(kBlockSize), 981cb0ef41Sopenharmony_ci "Block size must be power of two."); 991cb0ef41Sopenharmony_ci static_assert( 1001cb0ef41Sopenharmony_ci sizeof(CellType) * CHAR_BIT == (CellType{1} << kMarkBitCellSizeLog2), 1011cb0ef41Sopenharmony_ci "Markbit CellType not matching defined log2 size."); 1021cb0ef41Sopenharmony_ci static constexpr CellType kCellMask = 1031cb0ef41Sopenharmony_ci (CellType{1} << kMarkBitCellSizeLog2) - 1; 1041cb0ef41Sopenharmony_ci return {static_cast<CellType>(index >> kMarkBitCellSizeLog2), 1051cb0ef41Sopenharmony_ci index & kCellMask}; 1061cb0ef41Sopenharmony_ci } 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci NodeType nodes_[kBlockSize]; 1091cb0ef41Sopenharmony_ci NodeBlock* const next_; 1101cb0ef41Sopenharmony_ci GlobalHandles* const global_handles_; 1111cb0ef41Sopenharmony_ci GlobalHandles::NodeSpace<NodeType>* const space_; 1121cb0ef41Sopenharmony_ci NodeBlock* next_used_ = nullptr; 1131cb0ef41Sopenharmony_ci NodeBlock* prev_used_ = nullptr; 1141cb0ef41Sopenharmony_ci uint32_t used_nodes_ = 0; 1151cb0ef41Sopenharmony_ci CellType mark_bits_[kBlockSize / (sizeof(CellType) * CHAR_BIT)] = {0}; 1161cb0ef41Sopenharmony_ci}; 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_citemplate <class NodeType> 1191cb0ef41Sopenharmony_ciconst GlobalHandles::NodeBlock<NodeType>* 1201cb0ef41Sopenharmony_ciGlobalHandles::NodeBlock<NodeType>::From(const NodeType* node) { 1211cb0ef41Sopenharmony_ci const NodeType* firstNode = node - node->index(); 1221cb0ef41Sopenharmony_ci const BlockType* block = reinterpret_cast<const BlockType*>(firstNode); 1231cb0ef41Sopenharmony_ci DCHECK_EQ(node, block->at(node->index())); 1241cb0ef41Sopenharmony_ci return block; 1251cb0ef41Sopenharmony_ci} 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_citemplate <class NodeType> 1281cb0ef41Sopenharmony_ciGlobalHandles::NodeBlock<NodeType>* GlobalHandles::NodeBlock<NodeType>::From( 1291cb0ef41Sopenharmony_ci NodeType* node) { 1301cb0ef41Sopenharmony_ci NodeType* firstNode = node - node->index(); 1311cb0ef41Sopenharmony_ci BlockType* block = reinterpret_cast<BlockType*>(firstNode); 1321cb0ef41Sopenharmony_ci DCHECK_EQ(node, block->at(node->index())); 1331cb0ef41Sopenharmony_ci return block; 1341cb0ef41Sopenharmony_ci} 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_citemplate <class NodeType> 1371cb0ef41Sopenharmony_cibool GlobalHandles::NodeBlock<NodeType>::IncreaseUsage() { 1381cb0ef41Sopenharmony_ci DCHECK_LT(used_nodes_, kBlockSize); 1391cb0ef41Sopenharmony_ci return used_nodes_++ == 0; 1401cb0ef41Sopenharmony_ci} 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_citemplate <class NodeType> 1431cb0ef41Sopenharmony_civoid GlobalHandles::NodeBlock<NodeType>::ListAdd(BlockType** top) { 1441cb0ef41Sopenharmony_ci BlockType* old_top = *top; 1451cb0ef41Sopenharmony_ci *top = this; 1461cb0ef41Sopenharmony_ci next_used_ = old_top; 1471cb0ef41Sopenharmony_ci prev_used_ = nullptr; 1481cb0ef41Sopenharmony_ci if (old_top != nullptr) { 1491cb0ef41Sopenharmony_ci old_top->prev_used_ = this; 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci} 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_citemplate <class NodeType> 1541cb0ef41Sopenharmony_cibool GlobalHandles::NodeBlock<NodeType>::DecreaseUsage() { 1551cb0ef41Sopenharmony_ci DCHECK_GT(used_nodes_, 0); 1561cb0ef41Sopenharmony_ci return --used_nodes_ == 0; 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_citemplate <class NodeType> 1601cb0ef41Sopenharmony_civoid GlobalHandles::NodeBlock<NodeType>::ListRemove(BlockType** top) { 1611cb0ef41Sopenharmony_ci if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_; 1621cb0ef41Sopenharmony_ci if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_; 1631cb0ef41Sopenharmony_ci if (this == *top) { 1641cb0ef41Sopenharmony_ci *top = next_used_; 1651cb0ef41Sopenharmony_ci } 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_citemplate <class BlockType> 1691cb0ef41Sopenharmony_ciclass GlobalHandles::NodeIterator final { 1701cb0ef41Sopenharmony_ci public: 1711cb0ef41Sopenharmony_ci using NodeType = typename BlockType::NodeType; 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci // Iterator traits. 1741cb0ef41Sopenharmony_ci using iterator_category = std::forward_iterator_tag; 1751cb0ef41Sopenharmony_ci using difference_type = std::ptrdiff_t; 1761cb0ef41Sopenharmony_ci using value_type = NodeType*; 1771cb0ef41Sopenharmony_ci using reference = value_type; 1781cb0ef41Sopenharmony_ci using pointer = value_type*; 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci explicit NodeIterator(BlockType* block) V8_NOEXCEPT : block_(block) {} 1811cb0ef41Sopenharmony_ci NodeIterator(NodeIterator&& other) V8_NOEXCEPT : block_(other.block_), 1821cb0ef41Sopenharmony_ci index_(other.index_) {} 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci NodeIterator(const NodeIterator&) = delete; 1851cb0ef41Sopenharmony_ci NodeIterator& operator=(const NodeIterator&) = delete; 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci bool operator==(const NodeIterator& other) const { 1881cb0ef41Sopenharmony_ci return block_ == other.block_; 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci bool operator!=(const NodeIterator& other) const { 1911cb0ef41Sopenharmony_ci return block_ != other.block_; 1921cb0ef41Sopenharmony_ci } 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci NodeIterator& operator++() { 1951cb0ef41Sopenharmony_ci if (++index_ < kBlockSize) return *this; 1961cb0ef41Sopenharmony_ci index_ = 0; 1971cb0ef41Sopenharmony_ci block_ = block_->next_used(); 1981cb0ef41Sopenharmony_ci return *this; 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci NodeType* operator*() { return block_->at(index_); } 2021cb0ef41Sopenharmony_ci NodeType* operator->() { return block_->at(index_); } 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci private: 2051cb0ef41Sopenharmony_ci BlockType* block_ = nullptr; 2061cb0ef41Sopenharmony_ci size_t index_ = 0; 2071cb0ef41Sopenharmony_ci}; 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_citemplate <class NodeType> 2101cb0ef41Sopenharmony_ciclass GlobalHandles::NodeSpace final { 2111cb0ef41Sopenharmony_ci public: 2121cb0ef41Sopenharmony_ci using BlockType = NodeBlock<NodeType>; 2131cb0ef41Sopenharmony_ci using iterator = NodeIterator<BlockType>; 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci static NodeSpace* From(NodeType* node); 2161cb0ef41Sopenharmony_ci static void Release(NodeType* node); 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci explicit NodeSpace(GlobalHandles* global_handles) V8_NOEXCEPT 2191cb0ef41Sopenharmony_ci : global_handles_(global_handles) {} 2201cb0ef41Sopenharmony_ci ~NodeSpace(); 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci V8_INLINE NodeType* Acquire(Object object); 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci iterator begin() { return iterator(first_used_block_); } 2251cb0ef41Sopenharmony_ci iterator end() { return iterator(nullptr); } 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_ci size_t TotalSize() const { return blocks_ * sizeof(NodeType) * kBlockSize; } 2281cb0ef41Sopenharmony_ci size_t handles_count() const { return handles_count_; } 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci private: 2311cb0ef41Sopenharmony_ci void PutNodesOnFreeList(BlockType* block); 2321cb0ef41Sopenharmony_ci V8_INLINE void Free(NodeType* node); 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci GlobalHandles* const global_handles_; 2351cb0ef41Sopenharmony_ci BlockType* first_block_ = nullptr; 2361cb0ef41Sopenharmony_ci BlockType* first_used_block_ = nullptr; 2371cb0ef41Sopenharmony_ci NodeType* first_free_ = nullptr; 2381cb0ef41Sopenharmony_ci size_t blocks_ = 0; 2391cb0ef41Sopenharmony_ci size_t handles_count_ = 0; 2401cb0ef41Sopenharmony_ci}; 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_citemplate <class NodeType> 2431cb0ef41Sopenharmony_ciGlobalHandles::NodeSpace<NodeType>::~NodeSpace() { 2441cb0ef41Sopenharmony_ci auto* block = first_block_; 2451cb0ef41Sopenharmony_ci while (block != nullptr) { 2461cb0ef41Sopenharmony_ci auto* tmp = block->next(); 2471cb0ef41Sopenharmony_ci delete block; 2481cb0ef41Sopenharmony_ci block = tmp; 2491cb0ef41Sopenharmony_ci } 2501cb0ef41Sopenharmony_ci} 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_citemplate <class NodeType> 2531cb0ef41Sopenharmony_ciNodeType* GlobalHandles::NodeSpace<NodeType>::Acquire(Object object) { 2541cb0ef41Sopenharmony_ci if (first_free_ == nullptr) { 2551cb0ef41Sopenharmony_ci first_block_ = new BlockType(global_handles_, this, first_block_); 2561cb0ef41Sopenharmony_ci blocks_++; 2571cb0ef41Sopenharmony_ci PutNodesOnFreeList(first_block_); 2581cb0ef41Sopenharmony_ci } 2591cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(first_free_); 2601cb0ef41Sopenharmony_ci NodeType* node = first_free_; 2611cb0ef41Sopenharmony_ci first_free_ = first_free_->next_free(); 2621cb0ef41Sopenharmony_ci node->Acquire(object); 2631cb0ef41Sopenharmony_ci BlockType* block = BlockType::From(node); 2641cb0ef41Sopenharmony_ci if (block->IncreaseUsage()) { 2651cb0ef41Sopenharmony_ci block->ListAdd(&first_used_block_); 2661cb0ef41Sopenharmony_ci } 2671cb0ef41Sopenharmony_ci global_handles_->isolate()->counters()->global_handles()->Increment(); 2681cb0ef41Sopenharmony_ci handles_count_++; 2691cb0ef41Sopenharmony_ci DCHECK(node->IsInUse()); 2701cb0ef41Sopenharmony_ci return node; 2711cb0ef41Sopenharmony_ci} 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_citemplate <class NodeType> 2741cb0ef41Sopenharmony_civoid GlobalHandles::NodeSpace<NodeType>::PutNodesOnFreeList(BlockType* block) { 2751cb0ef41Sopenharmony_ci for (int32_t i = kBlockSize - 1; i >= 0; --i) { 2761cb0ef41Sopenharmony_ci NodeType* node = block->at(i); 2771cb0ef41Sopenharmony_ci const uint8_t index = static_cast<uint8_t>(i); 2781cb0ef41Sopenharmony_ci DCHECK_EQ(i, index); 2791cb0ef41Sopenharmony_ci node->set_index(index); 2801cb0ef41Sopenharmony_ci node->Free(first_free_); 2811cb0ef41Sopenharmony_ci first_free_ = node; 2821cb0ef41Sopenharmony_ci } 2831cb0ef41Sopenharmony_ci} 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_citemplate <class NodeType> 2861cb0ef41Sopenharmony_civoid GlobalHandles::NodeSpace<NodeType>::Release(NodeType* node) { 2871cb0ef41Sopenharmony_ci BlockType* block = BlockType::From(node); 2881cb0ef41Sopenharmony_ci block->space()->Free(node); 2891cb0ef41Sopenharmony_ci} 2901cb0ef41Sopenharmony_ci 2911cb0ef41Sopenharmony_citemplate <class NodeType> 2921cb0ef41Sopenharmony_civoid GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) { 2931cb0ef41Sopenharmony_ci node->Release(first_free_); 2941cb0ef41Sopenharmony_ci first_free_ = node; 2951cb0ef41Sopenharmony_ci BlockType* block = BlockType::From(node); 2961cb0ef41Sopenharmony_ci if (block->DecreaseUsage()) { 2971cb0ef41Sopenharmony_ci block->ListRemove(&first_used_block_); 2981cb0ef41Sopenharmony_ci } 2991cb0ef41Sopenharmony_ci global_handles_->isolate()->counters()->global_handles()->Decrement(); 3001cb0ef41Sopenharmony_ci handles_count_--; 3011cb0ef41Sopenharmony_ci} 3021cb0ef41Sopenharmony_ci 3031cb0ef41Sopenharmony_citemplate <class Child> 3041cb0ef41Sopenharmony_ciclass NodeBase { 3051cb0ef41Sopenharmony_ci public: 3061cb0ef41Sopenharmony_ci static const Child* FromLocation(const Address* location) { 3071cb0ef41Sopenharmony_ci return reinterpret_cast<const Child*>(location); 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_ci static Child* FromLocation(Address* location) { 3111cb0ef41Sopenharmony_ci return reinterpret_cast<Child*>(location); 3121cb0ef41Sopenharmony_ci } 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci NodeBase() { 3151cb0ef41Sopenharmony_ci DCHECK_EQ(offsetof(NodeBase, object_), 0); 3161cb0ef41Sopenharmony_ci DCHECK_EQ(offsetof(NodeBase, class_id_), Internals::kNodeClassIdOffset); 3171cb0ef41Sopenharmony_ci DCHECK_EQ(offsetof(NodeBase, flags_), Internals::kNodeFlagsOffset); 3181cb0ef41Sopenharmony_ci } 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci#ifdef ENABLE_HANDLE_ZAPPING 3211cb0ef41Sopenharmony_ci ~NodeBase() { 3221cb0ef41Sopenharmony_ci ClearFields(); 3231cb0ef41Sopenharmony_ci data_.next_free = nullptr; 3241cb0ef41Sopenharmony_ci index_ = 0; 3251cb0ef41Sopenharmony_ci } 3261cb0ef41Sopenharmony_ci#endif 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ci void Free(Child* free_list) { 3291cb0ef41Sopenharmony_ci ClearFields(); 3301cb0ef41Sopenharmony_ci AsChild()->MarkAsFree(); 3311cb0ef41Sopenharmony_ci data_.next_free = free_list; 3321cb0ef41Sopenharmony_ci } 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci void Acquire(Object object) { 3351cb0ef41Sopenharmony_ci DCHECK(!AsChild()->IsInUse()); 3361cb0ef41Sopenharmony_ci CheckFieldsAreCleared(); 3371cb0ef41Sopenharmony_ci reinterpret_cast<std::atomic<Address>*>(&object_)->store( 3381cb0ef41Sopenharmony_ci object.ptr(), std::memory_order_relaxed); 3391cb0ef41Sopenharmony_ci AsChild()->MarkAsUsed(); 3401cb0ef41Sopenharmony_ci data_.parameter = nullptr; 3411cb0ef41Sopenharmony_ci DCHECK(AsChild()->IsInUse()); 3421cb0ef41Sopenharmony_ci } 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_ci void Release(Child* free_list) { 3451cb0ef41Sopenharmony_ci DCHECK(AsChild()->IsInUse()); 3461cb0ef41Sopenharmony_ci Free(free_list); 3471cb0ef41Sopenharmony_ci DCHECK(!AsChild()->IsInUse()); 3481cb0ef41Sopenharmony_ci } 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_ci Object object() const { return Object(object_); } 3511cb0ef41Sopenharmony_ci FullObjectSlot location() { return FullObjectSlot(&object_); } 3521cb0ef41Sopenharmony_ci Handle<Object> handle() { return Handle<Object>(&object_); } 3531cb0ef41Sopenharmony_ci 3541cb0ef41Sopenharmony_ci uint8_t index() const { return index_; } 3551cb0ef41Sopenharmony_ci void set_index(uint8_t value) { index_ = value; } 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ci uint16_t wrapper_class_id() const { return class_id_; } 3581cb0ef41Sopenharmony_ci bool has_wrapper_class_id() const { 3591cb0ef41Sopenharmony_ci return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; 3601cb0ef41Sopenharmony_ci } 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_ci // Accessors for next free node in the free list. 3631cb0ef41Sopenharmony_ci Child* next_free() { 3641cb0ef41Sopenharmony_ci DCHECK(!AsChild()->IsInUse()); 3651cb0ef41Sopenharmony_ci return data_.next_free; 3661cb0ef41Sopenharmony_ci } 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_ci void set_parameter(void* parameter) { 3691cb0ef41Sopenharmony_ci DCHECK(AsChild()->IsInUse()); 3701cb0ef41Sopenharmony_ci data_.parameter = parameter; 3711cb0ef41Sopenharmony_ci } 3721cb0ef41Sopenharmony_ci void* parameter() const { 3731cb0ef41Sopenharmony_ci DCHECK(AsChild()->IsInUse()); 3741cb0ef41Sopenharmony_ci return data_.parameter; 3751cb0ef41Sopenharmony_ci } 3761cb0ef41Sopenharmony_ci 3771cb0ef41Sopenharmony_ci protected: 3781cb0ef41Sopenharmony_ci Child* AsChild() { return reinterpret_cast<Child*>(this); } 3791cb0ef41Sopenharmony_ci const Child* AsChild() const { return reinterpret_cast<const Child*>(this); } 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ci void ClearFields() { 3821cb0ef41Sopenharmony_ci // Zap the values for eager trapping. 3831cb0ef41Sopenharmony_ci object_ = kGlobalHandleZapValue; 3841cb0ef41Sopenharmony_ci class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 3851cb0ef41Sopenharmony_ci AsChild()->ClearImplFields(); 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci 3881cb0ef41Sopenharmony_ci void CheckFieldsAreCleared() { 3891cb0ef41Sopenharmony_ci DCHECK_EQ(kGlobalHandleZapValue, object_); 3901cb0ef41Sopenharmony_ci DCHECK_EQ(v8::HeapProfiler::kPersistentHandleNoClassId, class_id_); 3911cb0ef41Sopenharmony_ci AsChild()->CheckImplFieldsAreCleared(); 3921cb0ef41Sopenharmony_ci } 3931cb0ef41Sopenharmony_ci 3941cb0ef41Sopenharmony_ci // Storage for object pointer. 3951cb0ef41Sopenharmony_ci // 3961cb0ef41Sopenharmony_ci // Placed first to avoid offset computation. The stored data is equivalent to 3971cb0ef41Sopenharmony_ci // an Object. It is stored as a plain Address for convenience (smallest number 3981cb0ef41Sopenharmony_ci // of casts), and because it is a private implementation detail: the public 3991cb0ef41Sopenharmony_ci // interface provides type safety. 4001cb0ef41Sopenharmony_ci Address object_; 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci // Class id set by the embedder. 4031cb0ef41Sopenharmony_ci uint16_t class_id_; 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_ci // Index in the containing handle block. 4061cb0ef41Sopenharmony_ci uint8_t index_; 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci uint8_t flags_; 4091cb0ef41Sopenharmony_ci 4101cb0ef41Sopenharmony_ci // The meaning of this field depends on node state: 4111cb0ef41Sopenharmony_ci // - Node in free list: Stores next free node pointer. 4121cb0ef41Sopenharmony_ci // - Otherwise, specific to the node implementation. 4131cb0ef41Sopenharmony_ci union { 4141cb0ef41Sopenharmony_ci Child* next_free; 4151cb0ef41Sopenharmony_ci void* parameter; 4161cb0ef41Sopenharmony_ci } data_; 4171cb0ef41Sopenharmony_ci}; 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_cinamespace { 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_civoid ExtractInternalFields(JSObject jsobject, void** embedder_fields, int len) { 4221cb0ef41Sopenharmony_ci int field_count = jsobject.GetEmbedderFieldCount(); 4231cb0ef41Sopenharmony_ci Isolate* isolate = GetIsolateForSandbox(jsobject); 4241cb0ef41Sopenharmony_ci for (int i = 0; i < len; ++i) { 4251cb0ef41Sopenharmony_ci if (field_count == i) break; 4261cb0ef41Sopenharmony_ci void* pointer; 4271cb0ef41Sopenharmony_ci if (EmbedderDataSlot(jsobject, i).ToAlignedPointer(isolate, &pointer)) { 4281cb0ef41Sopenharmony_ci embedder_fields[i] = pointer; 4291cb0ef41Sopenharmony_ci } 4301cb0ef41Sopenharmony_ci } 4311cb0ef41Sopenharmony_ci} 4321cb0ef41Sopenharmony_ci 4331cb0ef41Sopenharmony_ci} // namespace 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ciclass GlobalHandles::Node final : public NodeBase<GlobalHandles::Node> { 4361cb0ef41Sopenharmony_ci public: 4371cb0ef41Sopenharmony_ci // State transition diagram: 4381cb0ef41Sopenharmony_ci // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } 4391cb0ef41Sopenharmony_ci enum State { 4401cb0ef41Sopenharmony_ci FREE = 0, 4411cb0ef41Sopenharmony_ci NORMAL, // Normal global handle. 4421cb0ef41Sopenharmony_ci WEAK, // Flagged as weak but not yet finalized. 4431cb0ef41Sopenharmony_ci PENDING, // Has been recognized as only reachable by weak handles. 4441cb0ef41Sopenharmony_ci NEAR_DEATH, // Callback has informed the handle is near death. 4451cb0ef41Sopenharmony_ci NUMBER_OF_NODE_STATES 4461cb0ef41Sopenharmony_ci }; 4471cb0ef41Sopenharmony_ci 4481cb0ef41Sopenharmony_ci Node() { 4491cb0ef41Sopenharmony_ci STATIC_ASSERT(static_cast<int>(NodeState::kMask) == 4501cb0ef41Sopenharmony_ci Internals::kNodeStateMask); 4511cb0ef41Sopenharmony_ci STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue); 4521cb0ef41Sopenharmony_ci STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue); 4531cb0ef41Sopenharmony_ci set_in_young_list(false); 4541cb0ef41Sopenharmony_ci } 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci Node(const Node&) = delete; 4571cb0ef41Sopenharmony_ci Node& operator=(const Node&) = delete; 4581cb0ef41Sopenharmony_ci 4591cb0ef41Sopenharmony_ci const char* label() const { 4601cb0ef41Sopenharmony_ci return state() == NORMAL ? reinterpret_cast<char*>(data_.parameter) 4611cb0ef41Sopenharmony_ci : nullptr; 4621cb0ef41Sopenharmony_ci } 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_ci // State and flag accessors. 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ci State state() const { return NodeState::decode(flags_); } 4671cb0ef41Sopenharmony_ci void set_state(State state) { flags_ = NodeState::update(flags_, state); } 4681cb0ef41Sopenharmony_ci 4691cb0ef41Sopenharmony_ci bool is_in_young_list() const { return IsInYoungList::decode(flags_); } 4701cb0ef41Sopenharmony_ci void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); } 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_ci WeaknessType weakness_type() const { 4731cb0ef41Sopenharmony_ci return NodeWeaknessType::decode(flags_); 4741cb0ef41Sopenharmony_ci } 4751cb0ef41Sopenharmony_ci void set_weakness_type(WeaknessType weakness_type) { 4761cb0ef41Sopenharmony_ci flags_ = NodeWeaknessType::update(flags_, weakness_type); 4771cb0ef41Sopenharmony_ci } 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci bool IsWeak() const { return state() == WEAK; } 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci bool IsInUse() const { return state() != FREE; } 4821cb0ef41Sopenharmony_ci 4831cb0ef41Sopenharmony_ci bool IsPhantomCallback() const { 4841cb0ef41Sopenharmony_ci return weakness_type() == PHANTOM_WEAK || 4851cb0ef41Sopenharmony_ci weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS; 4861cb0ef41Sopenharmony_ci } 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci bool IsPhantomResetHandle() const { 4891cb0ef41Sopenharmony_ci return weakness_type() == PHANTOM_WEAK_RESET_HANDLE; 4901cb0ef41Sopenharmony_ci } 4911cb0ef41Sopenharmony_ci 4921cb0ef41Sopenharmony_ci bool IsFinalizerHandle() const { return weakness_type() == FINALIZER_WEAK; } 4931cb0ef41Sopenharmony_ci 4941cb0ef41Sopenharmony_ci bool IsPendingPhantomCallback() const { 4951cb0ef41Sopenharmony_ci return state() == PENDING && IsPhantomCallback(); 4961cb0ef41Sopenharmony_ci } 4971cb0ef41Sopenharmony_ci 4981cb0ef41Sopenharmony_ci bool IsPendingPhantomResetHandle() const { 4991cb0ef41Sopenharmony_ci return state() == PENDING && IsPhantomResetHandle(); 5001cb0ef41Sopenharmony_ci } 5011cb0ef41Sopenharmony_ci 5021cb0ef41Sopenharmony_ci bool IsPendingFinalizer() const { 5031cb0ef41Sopenharmony_ci return state() == PENDING && weakness_type() == FINALIZER_WEAK; 5041cb0ef41Sopenharmony_ci } 5051cb0ef41Sopenharmony_ci 5061cb0ef41Sopenharmony_ci bool IsPending() const { return state() == PENDING; } 5071cb0ef41Sopenharmony_ci 5081cb0ef41Sopenharmony_ci bool IsRetainer() const { 5091cb0ef41Sopenharmony_ci return state() != FREE && 5101cb0ef41Sopenharmony_ci !(state() == NEAR_DEATH && weakness_type() != FINALIZER_WEAK); 5111cb0ef41Sopenharmony_ci } 5121cb0ef41Sopenharmony_ci 5131cb0ef41Sopenharmony_ci bool IsStrongRetainer() const { return state() == NORMAL; } 5141cb0ef41Sopenharmony_ci 5151cb0ef41Sopenharmony_ci bool IsWeakRetainer() const { 5161cb0ef41Sopenharmony_ci return state() == WEAK || state() == PENDING || 5171cb0ef41Sopenharmony_ci (state() == NEAR_DEATH && weakness_type() == FINALIZER_WEAK); 5181cb0ef41Sopenharmony_ci } 5191cb0ef41Sopenharmony_ci 5201cb0ef41Sopenharmony_ci void MarkPending() { 5211cb0ef41Sopenharmony_ci DCHECK(state() == WEAK); 5221cb0ef41Sopenharmony_ci set_state(PENDING); 5231cb0ef41Sopenharmony_ci } 5241cb0ef41Sopenharmony_ci 5251cb0ef41Sopenharmony_ci bool has_callback() const { return weak_callback_ != nullptr; } 5261cb0ef41Sopenharmony_ci 5271cb0ef41Sopenharmony_ci // Accessors for next free node in the free list. 5281cb0ef41Sopenharmony_ci Node* next_free() { 5291cb0ef41Sopenharmony_ci DCHECK_EQ(FREE, state()); 5301cb0ef41Sopenharmony_ci return data_.next_free; 5311cb0ef41Sopenharmony_ci } 5321cb0ef41Sopenharmony_ci 5331cb0ef41Sopenharmony_ci void MakeWeak(void* parameter, 5341cb0ef41Sopenharmony_ci WeakCallbackInfo<void>::Callback phantom_callback, 5351cb0ef41Sopenharmony_ci v8::WeakCallbackType type) { 5361cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(phantom_callback); 5371cb0ef41Sopenharmony_ci DCHECK(IsInUse()); 5381cb0ef41Sopenharmony_ci CHECK_NE(object_, kGlobalHandleZapValue); 5391cb0ef41Sopenharmony_ci set_state(WEAK); 5401cb0ef41Sopenharmony_ci switch (type) { 5411cb0ef41Sopenharmony_ci case v8::WeakCallbackType::kParameter: 5421cb0ef41Sopenharmony_ci set_weakness_type(PHANTOM_WEAK); 5431cb0ef41Sopenharmony_ci break; 5441cb0ef41Sopenharmony_ci case v8::WeakCallbackType::kInternalFields: 5451cb0ef41Sopenharmony_ci set_weakness_type(PHANTOM_WEAK_2_EMBEDDER_FIELDS); 5461cb0ef41Sopenharmony_ci break; 5471cb0ef41Sopenharmony_ci START_ALLOW_USE_DEPRECATED() 5481cb0ef41Sopenharmony_ci case v8::WeakCallbackType::kFinalizer: 5491cb0ef41Sopenharmony_ci set_weakness_type(FINALIZER_WEAK); 5501cb0ef41Sopenharmony_ci break; 5511cb0ef41Sopenharmony_ci END_ALLOW_USE_DEPRECATED() 5521cb0ef41Sopenharmony_ci } 5531cb0ef41Sopenharmony_ci set_parameter(parameter); 5541cb0ef41Sopenharmony_ci weak_callback_ = phantom_callback; 5551cb0ef41Sopenharmony_ci } 5561cb0ef41Sopenharmony_ci 5571cb0ef41Sopenharmony_ci void MakeWeak(Address** location_addr) { 5581cb0ef41Sopenharmony_ci DCHECK(IsInUse()); 5591cb0ef41Sopenharmony_ci CHECK_NE(object_, kGlobalHandleZapValue); 5601cb0ef41Sopenharmony_ci set_state(WEAK); 5611cb0ef41Sopenharmony_ci set_weakness_type(PHANTOM_WEAK_RESET_HANDLE); 5621cb0ef41Sopenharmony_ci set_parameter(location_addr); 5631cb0ef41Sopenharmony_ci weak_callback_ = nullptr; 5641cb0ef41Sopenharmony_ci } 5651cb0ef41Sopenharmony_ci 5661cb0ef41Sopenharmony_ci void* ClearWeakness() { 5671cb0ef41Sopenharmony_ci DCHECK(IsInUse()); 5681cb0ef41Sopenharmony_ci void* p = parameter(); 5691cb0ef41Sopenharmony_ci set_state(NORMAL); 5701cb0ef41Sopenharmony_ci set_parameter(nullptr); 5711cb0ef41Sopenharmony_ci return p; 5721cb0ef41Sopenharmony_ci } 5731cb0ef41Sopenharmony_ci 5741cb0ef41Sopenharmony_ci void AnnotateStrongRetainer(const char* label) { 5751cb0ef41Sopenharmony_ci DCHECK_EQ(state(), NORMAL); 5761cb0ef41Sopenharmony_ci data_.parameter = const_cast<char*>(label); 5771cb0ef41Sopenharmony_ci } 5781cb0ef41Sopenharmony_ci 5791cb0ef41Sopenharmony_ci void CollectPhantomCallbackData( 5801cb0ef41Sopenharmony_ci std::vector<std::pair<Node*, PendingPhantomCallback>>* 5811cb0ef41Sopenharmony_ci pending_phantom_callbacks) { 5821cb0ef41Sopenharmony_ci DCHECK(weakness_type() == PHANTOM_WEAK || 5831cb0ef41Sopenharmony_ci weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS); 5841cb0ef41Sopenharmony_ci DCHECK(state() == PENDING); 5851cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(weak_callback_); 5861cb0ef41Sopenharmony_ci 5871cb0ef41Sopenharmony_ci void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr, 5881cb0ef41Sopenharmony_ci nullptr}; 5891cb0ef41Sopenharmony_ci if (weakness_type() != PHANTOM_WEAK && object().IsJSObject()) { 5901cb0ef41Sopenharmony_ci ExtractInternalFields(JSObject::cast(object()), embedder_fields, 5911cb0ef41Sopenharmony_ci v8::kEmbedderFieldsInWeakCallback); 5921cb0ef41Sopenharmony_ci } 5931cb0ef41Sopenharmony_ci 5941cb0ef41Sopenharmony_ci // Zap with something dangerous. 5951cb0ef41Sopenharmony_ci location().store(Object(0xCA11)); 5961cb0ef41Sopenharmony_ci 5971cb0ef41Sopenharmony_ci pending_phantom_callbacks->push_back(std::make_pair( 5981cb0ef41Sopenharmony_ci this, 5991cb0ef41Sopenharmony_ci PendingPhantomCallback(weak_callback_, parameter(), embedder_fields))); 6001cb0ef41Sopenharmony_ci DCHECK(IsInUse()); 6011cb0ef41Sopenharmony_ci set_state(NEAR_DEATH); 6021cb0ef41Sopenharmony_ci } 6031cb0ef41Sopenharmony_ci 6041cb0ef41Sopenharmony_ci void ResetPhantomHandle() { 6051cb0ef41Sopenharmony_ci DCHECK_EQ(PHANTOM_WEAK_RESET_HANDLE, weakness_type()); 6061cb0ef41Sopenharmony_ci DCHECK_EQ(PENDING, state()); 6071cb0ef41Sopenharmony_ci DCHECK_NULL(weak_callback_); 6081cb0ef41Sopenharmony_ci Address** handle = reinterpret_cast<Address**>(parameter()); 6091cb0ef41Sopenharmony_ci *handle = nullptr; 6101cb0ef41Sopenharmony_ci NodeSpace<Node>::Release(this); 6111cb0ef41Sopenharmony_ci } 6121cb0ef41Sopenharmony_ci 6131cb0ef41Sopenharmony_ci void PostGarbageCollectionProcessing(Isolate* isolate) { 6141cb0ef41Sopenharmony_ci // This method invokes a finalizer. Updating the method name would require 6151cb0ef41Sopenharmony_ci // adjusting CFI blocklist as weak_callback_ is invoked on the wrong type. 6161cb0ef41Sopenharmony_ci CHECK(IsPendingFinalizer()); 6171cb0ef41Sopenharmony_ci set_state(NEAR_DEATH); 6181cb0ef41Sopenharmony_ci // Check that we are not passing a finalized external string to 6191cb0ef41Sopenharmony_ci // the callback. 6201cb0ef41Sopenharmony_ci DCHECK(!object().IsExternalOneByteString() || 6211cb0ef41Sopenharmony_ci ExternalOneByteString::cast(object()).resource() != nullptr); 6221cb0ef41Sopenharmony_ci DCHECK(!object().IsExternalTwoByteString() || 6231cb0ef41Sopenharmony_ci ExternalTwoByteString::cast(object()).resource() != nullptr); 6241cb0ef41Sopenharmony_ci // Leaving V8. 6251cb0ef41Sopenharmony_ci VMState<EXTERNAL> vmstate(isolate); 6261cb0ef41Sopenharmony_ci HandleScope handle_scope(isolate); 6271cb0ef41Sopenharmony_ci void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr, 6281cb0ef41Sopenharmony_ci nullptr}; 6291cb0ef41Sopenharmony_ci v8::WeakCallbackInfo<void> data(reinterpret_cast<v8::Isolate*>(isolate), 6301cb0ef41Sopenharmony_ci parameter(), embedder_fields, nullptr); 6311cb0ef41Sopenharmony_ci weak_callback_(data); 6321cb0ef41Sopenharmony_ci // For finalizers the handle must have either been reset or made strong. 6331cb0ef41Sopenharmony_ci // Both cases reset the state. 6341cb0ef41Sopenharmony_ci CHECK_NE(NEAR_DEATH, state()); 6351cb0ef41Sopenharmony_ci } 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_ci void MarkAsFree() { set_state(FREE); } 6381cb0ef41Sopenharmony_ci void MarkAsUsed() { set_state(NORMAL); } 6391cb0ef41Sopenharmony_ci 6401cb0ef41Sopenharmony_ci GlobalHandles* global_handles() { 6411cb0ef41Sopenharmony_ci return NodeBlock<Node>::From(this)->global_handles(); 6421cb0ef41Sopenharmony_ci } 6431cb0ef41Sopenharmony_ci 6441cb0ef41Sopenharmony_ci private: 6451cb0ef41Sopenharmony_ci // Fields that are not used for managing node memory. 6461cb0ef41Sopenharmony_ci void ClearImplFields() { weak_callback_ = nullptr; } 6471cb0ef41Sopenharmony_ci 6481cb0ef41Sopenharmony_ci void CheckImplFieldsAreCleared() { DCHECK_EQ(nullptr, weak_callback_); } 6491cb0ef41Sopenharmony_ci 6501cb0ef41Sopenharmony_ci // This stores three flags (independent, partially_dependent and 6511cb0ef41Sopenharmony_ci // in_young_list) and a State. 6521cb0ef41Sopenharmony_ci using NodeState = base::BitField8<State, 0, 3>; 6531cb0ef41Sopenharmony_ci using IsInYoungList = NodeState::Next<bool, 1>; 6541cb0ef41Sopenharmony_ci using NodeWeaknessType = IsInYoungList::Next<WeaknessType, 2>; 6551cb0ef41Sopenharmony_ci 6561cb0ef41Sopenharmony_ci // Handle specific callback - might be a weak reference in disguise. 6571cb0ef41Sopenharmony_ci WeakCallbackInfo<void>::Callback weak_callback_; 6581cb0ef41Sopenharmony_ci 6591cb0ef41Sopenharmony_ci friend class NodeBase<Node>; 6601cb0ef41Sopenharmony_ci}; 6611cb0ef41Sopenharmony_ci 6621cb0ef41Sopenharmony_ciclass GlobalHandles::TracedNode final 6631cb0ef41Sopenharmony_ci : public NodeBase<GlobalHandles::TracedNode> { 6641cb0ef41Sopenharmony_ci public: 6651cb0ef41Sopenharmony_ci TracedNode() { set_in_young_list(false); } 6661cb0ef41Sopenharmony_ci 6671cb0ef41Sopenharmony_ci // Copy and move ctors are used when constructing a TracedNode when recording 6681cb0ef41Sopenharmony_ci // a node for on-stack data structures. (Older compilers may refer to copy 6691cb0ef41Sopenharmony_ci // instead of move ctor.) 6701cb0ef41Sopenharmony_ci TracedNode(TracedNode&& other) V8_NOEXCEPT = default; 6711cb0ef41Sopenharmony_ci TracedNode(const TracedNode& other) V8_NOEXCEPT = default; 6721cb0ef41Sopenharmony_ci 6731cb0ef41Sopenharmony_ci enum State { FREE = 0, NORMAL, NEAR_DEATH }; 6741cb0ef41Sopenharmony_ci 6751cb0ef41Sopenharmony_ci State state() const { return NodeState::decode(flags_); } 6761cb0ef41Sopenharmony_ci void set_state(State state) { flags_ = NodeState::update(flags_, state); } 6771cb0ef41Sopenharmony_ci 6781cb0ef41Sopenharmony_ci void MarkAsFree() { set_state(FREE); } 6791cb0ef41Sopenharmony_ci void MarkAsUsed() { set_state(NORMAL); } 6801cb0ef41Sopenharmony_ci bool IsInUse() const { return state() != FREE; } 6811cb0ef41Sopenharmony_ci bool IsRetainer() const { return state() == NORMAL; } 6821cb0ef41Sopenharmony_ci 6831cb0ef41Sopenharmony_ci bool is_in_young_list() const { return IsInYoungList::decode(flags_); } 6841cb0ef41Sopenharmony_ci void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); } 6851cb0ef41Sopenharmony_ci 6861cb0ef41Sopenharmony_ci bool is_root() const { return IsRoot::decode(flags_); } 6871cb0ef41Sopenharmony_ci void set_root(bool v) { flags_ = IsRoot::update(flags_, v); } 6881cb0ef41Sopenharmony_ci 6891cb0ef41Sopenharmony_ci void set_markbit() { 6901cb0ef41Sopenharmony_ci NodeBlock<TracedNode>::From(this)->set_markbit(index()); 6911cb0ef41Sopenharmony_ci } 6921cb0ef41Sopenharmony_ci 6931cb0ef41Sopenharmony_ci bool markbit() const { 6941cb0ef41Sopenharmony_ci return NodeBlock<TracedNode>::From(this)->markbit(index()); 6951cb0ef41Sopenharmony_ci } 6961cb0ef41Sopenharmony_ci void clear_markbit() { 6971cb0ef41Sopenharmony_ci NodeBlock<TracedNode>::From(this)->clear_markbit(index()); 6981cb0ef41Sopenharmony_ci } 6991cb0ef41Sopenharmony_ci 7001cb0ef41Sopenharmony_ci bool is_on_stack() const { return IsOnStack::decode(flags_); } 7011cb0ef41Sopenharmony_ci void set_is_on_stack(bool v) { flags_ = IsOnStack::update(flags_, v); } 7021cb0ef41Sopenharmony_ci 7031cb0ef41Sopenharmony_ci void clear_object() { 7041cb0ef41Sopenharmony_ci reinterpret_cast<std::atomic<Address>*>(&object_)->store( 7051cb0ef41Sopenharmony_ci kNullAddress, std::memory_order_relaxed); 7061cb0ef41Sopenharmony_ci } 7071cb0ef41Sopenharmony_ci 7081cb0ef41Sopenharmony_ci void CopyObjectReference(const TracedNode& other) { 7091cb0ef41Sopenharmony_ci reinterpret_cast<std::atomic<Address>*>(&object_)->store( 7101cb0ef41Sopenharmony_ci other.object_, std::memory_order_relaxed); 7111cb0ef41Sopenharmony_ci } 7121cb0ef41Sopenharmony_ci 7131cb0ef41Sopenharmony_ci void ResetPhantomHandle() { 7141cb0ef41Sopenharmony_ci DCHECK(IsInUse()); 7151cb0ef41Sopenharmony_ci NodeSpace<TracedNode>::Release(this); 7161cb0ef41Sopenharmony_ci DCHECK(!IsInUse()); 7171cb0ef41Sopenharmony_ci } 7181cb0ef41Sopenharmony_ci 7191cb0ef41Sopenharmony_ci static void Verify(GlobalHandles* global_handles, const Address* const* slot); 7201cb0ef41Sopenharmony_ci 7211cb0ef41Sopenharmony_ci protected: 7221cb0ef41Sopenharmony_ci // Various state is managed in a bit field. Mark bits are used concurrently 7231cb0ef41Sopenharmony_ci // and held externally in a NodeBlock. 7241cb0ef41Sopenharmony_ci using NodeState = base::BitField8<State, 0, 2>; 7251cb0ef41Sopenharmony_ci using IsInYoungList = NodeState::Next<bool, 1>; 7261cb0ef41Sopenharmony_ci using IsRoot = IsInYoungList::Next<bool, 1>; 7271cb0ef41Sopenharmony_ci using IsOnStack = IsRoot::Next<bool, 1>; 7281cb0ef41Sopenharmony_ci void ClearImplFields() { 7291cb0ef41Sopenharmony_ci set_root(true); 7301cb0ef41Sopenharmony_ci set_is_on_stack(false); 7311cb0ef41Sopenharmony_ci } 7321cb0ef41Sopenharmony_ci 7331cb0ef41Sopenharmony_ci void CheckImplFieldsAreCleared() const { DCHECK(is_root()); } 7341cb0ef41Sopenharmony_ci 7351cb0ef41Sopenharmony_ci friend class NodeBase<GlobalHandles::TracedNode>; 7361cb0ef41Sopenharmony_ci}; 7371cb0ef41Sopenharmony_ci 7381cb0ef41Sopenharmony_ci// Space to keep track of on-stack handles (e.g. TracedReference). Such 7391cb0ef41Sopenharmony_ci// references are treated as root for any V8 garbage collection. The data 7401cb0ef41Sopenharmony_ci// structure is self healing and pessimistally filters outdated entries on 7411cb0ef41Sopenharmony_ci// insertion and iteration. 7421cb0ef41Sopenharmony_ci// 7431cb0ef41Sopenharmony_ci// Design doc: http://bit.ly/on-stack-traced-reference 7441cb0ef41Sopenharmony_ciclass GlobalHandles::OnStackTracedNodeSpace final { 7451cb0ef41Sopenharmony_ci public: 7461cb0ef41Sopenharmony_ci static GlobalHandles* GetGlobalHandles(const TracedNode* on_stack_node) { 7471cb0ef41Sopenharmony_ci DCHECK(on_stack_node->is_on_stack()); 7481cb0ef41Sopenharmony_ci return reinterpret_cast<const NodeEntry*>(on_stack_node)->global_handles; 7491cb0ef41Sopenharmony_ci } 7501cb0ef41Sopenharmony_ci 7511cb0ef41Sopenharmony_ci explicit OnStackTracedNodeSpace(GlobalHandles* global_handles) 7521cb0ef41Sopenharmony_ci : global_handles_(global_handles) {} 7531cb0ef41Sopenharmony_ci 7541cb0ef41Sopenharmony_ci void SetStackStart(void* stack_start) { 7551cb0ef41Sopenharmony_ci CHECK(on_stack_nodes_.empty()); 7561cb0ef41Sopenharmony_ci stack_.SetStackStart(base::Stack::GetRealStackAddressForSlot(stack_start)); 7571cb0ef41Sopenharmony_ci } 7581cb0ef41Sopenharmony_ci 7591cb0ef41Sopenharmony_ci V8_INLINE bool IsOnStack(uintptr_t slot) const; 7601cb0ef41Sopenharmony_ci 7611cb0ef41Sopenharmony_ci void Iterate(RootVisitor* v); 7621cb0ef41Sopenharmony_ci TracedNode* Acquire(Object value, uintptr_t address); 7631cb0ef41Sopenharmony_ci void CleanupBelowCurrentStackPosition(); 7641cb0ef41Sopenharmony_ci void NotifyEmptyEmbedderStack(); 7651cb0ef41Sopenharmony_ci 7661cb0ef41Sopenharmony_ci size_t NumberOfHandlesForTesting() const { return on_stack_nodes_.size(); } 7671cb0ef41Sopenharmony_ci 7681cb0ef41Sopenharmony_ci private: 7691cb0ef41Sopenharmony_ci struct NodeEntry { 7701cb0ef41Sopenharmony_ci TracedNode node; 7711cb0ef41Sopenharmony_ci // Used to find back to GlobalHandles from a Node on copy. Needs to follow 7721cb0ef41Sopenharmony_ci // node. 7731cb0ef41Sopenharmony_ci GlobalHandles* global_handles; 7741cb0ef41Sopenharmony_ci }; 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ci // Keeps track of registered handles. The data structure is cleaned on 7771cb0ef41Sopenharmony_ci // iteration and when adding new references using the current stack address. 7781cb0ef41Sopenharmony_ci // Cleaning is based on current stack address and the key of the map which is 7791cb0ef41Sopenharmony_ci // slightly different for ASAN configs -- see below. 7801cb0ef41Sopenharmony_ci#ifdef V8_USE_ADDRESS_SANITIZER 7811cb0ef41Sopenharmony_ci // Mapping from stack slots or real stack frames to the corresponding nodes. 7821cb0ef41Sopenharmony_ci // In case a reference is part of a fake frame, we map it to the real stack 7831cb0ef41Sopenharmony_ci // frame base instead of the actual stack slot. The list keeps all nodes for 7841cb0ef41Sopenharmony_ci // a particular real frame. 7851cb0ef41Sopenharmony_ci std::map<uintptr_t, std::list<NodeEntry>> on_stack_nodes_; 7861cb0ef41Sopenharmony_ci#else // !V8_USE_ADDRESS_SANITIZER 7871cb0ef41Sopenharmony_ci // Mapping from stack slots to the corresponding nodes. We don't expect 7881cb0ef41Sopenharmony_ci // aliasing with overlapping lifetimes of nodes. 7891cb0ef41Sopenharmony_ci std::map<uintptr_t, NodeEntry> on_stack_nodes_; 7901cb0ef41Sopenharmony_ci#endif // !V8_USE_ADDRESS_SANITIZER 7911cb0ef41Sopenharmony_ci 7921cb0ef41Sopenharmony_ci ::heap::base::Stack stack_; 7931cb0ef41Sopenharmony_ci GlobalHandles* global_handles_ = nullptr; 7941cb0ef41Sopenharmony_ci size_t acquire_count_ = 0; 7951cb0ef41Sopenharmony_ci}; 7961cb0ef41Sopenharmony_ci 7971cb0ef41Sopenharmony_cibool GlobalHandles::OnStackTracedNodeSpace::IsOnStack(uintptr_t slot) const { 7981cb0ef41Sopenharmony_ci // By the time this function is called, the stack start may not be set (i.e. 7991cb0ef41Sopenharmony_ci // SetStackStart() was not called). In that case, assume the slot is not on 8001cb0ef41Sopenharmony_ci // stack. 8011cb0ef41Sopenharmony_ci if (!stack_.stack_start()) return false; 8021cb0ef41Sopenharmony_ci return stack_.IsOnStack(reinterpret_cast<void*>(slot)); 8031cb0ef41Sopenharmony_ci} 8041cb0ef41Sopenharmony_ci 8051cb0ef41Sopenharmony_civoid GlobalHandles::OnStackTracedNodeSpace::NotifyEmptyEmbedderStack() { 8061cb0ef41Sopenharmony_ci on_stack_nodes_.clear(); 8071cb0ef41Sopenharmony_ci} 8081cb0ef41Sopenharmony_ci 8091cb0ef41Sopenharmony_civoid GlobalHandles::OnStackTracedNodeSpace::Iterate(RootVisitor* v) { 8101cb0ef41Sopenharmony_ci#ifdef V8_USE_ADDRESS_SANITIZER 8111cb0ef41Sopenharmony_ci for (auto& pair : on_stack_nodes_) { 8121cb0ef41Sopenharmony_ci for (auto& node_entry : pair.second) { 8131cb0ef41Sopenharmony_ci TracedNode& node = node_entry.node; 8141cb0ef41Sopenharmony_ci if (node.IsRetainer()) { 8151cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, "on-stack TracedReference", 8161cb0ef41Sopenharmony_ci node.location()); 8171cb0ef41Sopenharmony_ci } 8181cb0ef41Sopenharmony_ci } 8191cb0ef41Sopenharmony_ci } 8201cb0ef41Sopenharmony_ci#else // !V8_USE_ADDRESS_SANITIZER 8211cb0ef41Sopenharmony_ci // Handles have been cleaned from the GC entry point which is higher up the 8221cb0ef41Sopenharmony_ci // stack. 8231cb0ef41Sopenharmony_ci for (auto& pair : on_stack_nodes_) { 8241cb0ef41Sopenharmony_ci TracedNode& node = pair.second.node; 8251cb0ef41Sopenharmony_ci if (node.IsRetainer()) { 8261cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, "on-stack TracedReference", 8271cb0ef41Sopenharmony_ci node.location()); 8281cb0ef41Sopenharmony_ci } 8291cb0ef41Sopenharmony_ci } 8301cb0ef41Sopenharmony_ci#endif // !V8_USE_ADDRESS_SANITIZER 8311cb0ef41Sopenharmony_ci} 8321cb0ef41Sopenharmony_ci 8331cb0ef41Sopenharmony_ciGlobalHandles::TracedNode* GlobalHandles::OnStackTracedNodeSpace::Acquire( 8341cb0ef41Sopenharmony_ci Object value, uintptr_t slot) { 8351cb0ef41Sopenharmony_ci constexpr size_t kAcquireCleanupThresholdLog2 = 8; 8361cb0ef41Sopenharmony_ci constexpr size_t kAcquireCleanupThresholdMask = 8371cb0ef41Sopenharmony_ci (size_t{1} << kAcquireCleanupThresholdLog2) - 1; 8381cb0ef41Sopenharmony_ci DCHECK(IsOnStack(slot)); 8391cb0ef41Sopenharmony_ci if (((acquire_count_++) & kAcquireCleanupThresholdMask) == 0) { 8401cb0ef41Sopenharmony_ci CleanupBelowCurrentStackPosition(); 8411cb0ef41Sopenharmony_ci } 8421cb0ef41Sopenharmony_ci NodeEntry entry; 8431cb0ef41Sopenharmony_ci entry.node.Free(nullptr); 8441cb0ef41Sopenharmony_ci entry.global_handles = global_handles_; 8451cb0ef41Sopenharmony_ci#ifdef V8_USE_ADDRESS_SANITIZER 8461cb0ef41Sopenharmony_ci auto pair = on_stack_nodes_.insert( 8471cb0ef41Sopenharmony_ci {base::Stack::GetRealStackAddressForSlot(slot), {}}); 8481cb0ef41Sopenharmony_ci pair.first->second.push_back(std::move(entry)); 8491cb0ef41Sopenharmony_ci TracedNode* result = &(pair.first->second.back().node); 8501cb0ef41Sopenharmony_ci#else // !V8_USE_ADDRESS_SANITIZER 8511cb0ef41Sopenharmony_ci auto pair = on_stack_nodes_.insert( 8521cb0ef41Sopenharmony_ci {base::Stack::GetRealStackAddressForSlot(slot), std::move(entry)}); 8531cb0ef41Sopenharmony_ci if (!pair.second) { 8541cb0ef41Sopenharmony_ci // Insertion failed because there already was an entry present for that 8551cb0ef41Sopenharmony_ci // stack address. This can happen because cleanup is conservative in which 8561cb0ef41Sopenharmony_ci // stack limits it used. Reusing the entry is fine as there's no aliasing of 8571cb0ef41Sopenharmony_ci // different references with the same stack slot. 8581cb0ef41Sopenharmony_ci pair.first->second.node.Free(nullptr); 8591cb0ef41Sopenharmony_ci } 8601cb0ef41Sopenharmony_ci TracedNode* result = &(pair.first->second.node); 8611cb0ef41Sopenharmony_ci#endif // !V8_USE_ADDRESS_SANITIZER 8621cb0ef41Sopenharmony_ci result->Acquire(value); 8631cb0ef41Sopenharmony_ci result->set_is_on_stack(true); 8641cb0ef41Sopenharmony_ci return result; 8651cb0ef41Sopenharmony_ci} 8661cb0ef41Sopenharmony_ci 8671cb0ef41Sopenharmony_civoid GlobalHandles::OnStackTracedNodeSpace::CleanupBelowCurrentStackPosition() { 8681cb0ef41Sopenharmony_ci if (on_stack_nodes_.empty()) return; 8691cb0ef41Sopenharmony_ci const uintptr_t stack_ptr = reinterpret_cast<uintptr_t>( 8701cb0ef41Sopenharmony_ci ::heap::base::Stack::GetCurrentStackPointerForLocalVariables()); 8711cb0ef41Sopenharmony_ci const auto it = on_stack_nodes_.upper_bound(stack_ptr); 8721cb0ef41Sopenharmony_ci on_stack_nodes_.erase(on_stack_nodes_.begin(), it); 8731cb0ef41Sopenharmony_ci} 8741cb0ef41Sopenharmony_ci 8751cb0ef41Sopenharmony_ci// static 8761cb0ef41Sopenharmony_civoid GlobalHandles::EnableMarkingBarrier(Isolate* isolate) { 8771cb0ef41Sopenharmony_ci auto* global_handles = isolate->global_handles(); 8781cb0ef41Sopenharmony_ci DCHECK(!global_handles->is_marking_); 8791cb0ef41Sopenharmony_ci global_handles->is_marking_ = true; 8801cb0ef41Sopenharmony_ci} 8811cb0ef41Sopenharmony_ci 8821cb0ef41Sopenharmony_ci// static 8831cb0ef41Sopenharmony_civoid GlobalHandles::DisableMarkingBarrier(Isolate* isolate) { 8841cb0ef41Sopenharmony_ci auto* global_handles = isolate->global_handles(); 8851cb0ef41Sopenharmony_ci DCHECK(global_handles->is_marking_); 8861cb0ef41Sopenharmony_ci global_handles->is_marking_ = false; 8871cb0ef41Sopenharmony_ci} 8881cb0ef41Sopenharmony_ci 8891cb0ef41Sopenharmony_ci// static 8901cb0ef41Sopenharmony_civoid GlobalHandles::TracedNode::Verify(GlobalHandles* global_handles, 8911cb0ef41Sopenharmony_ci const Address* const* slot) { 8921cb0ef41Sopenharmony_ci#ifdef DEBUG 8931cb0ef41Sopenharmony_ci const TracedNode* node = FromLocation(*slot); 8941cb0ef41Sopenharmony_ci DCHECK(node->IsInUse()); 8951cb0ef41Sopenharmony_ci bool slot_on_stack = global_handles->on_stack_nodes_->IsOnStack( 8961cb0ef41Sopenharmony_ci reinterpret_cast<uintptr_t>(slot)); 8971cb0ef41Sopenharmony_ci DCHECK_EQ(slot_on_stack, node->is_on_stack()); 8981cb0ef41Sopenharmony_ci if (!node->is_on_stack()) { 8991cb0ef41Sopenharmony_ci // On-heap nodes have seprate lists for young generation processing. 9001cb0ef41Sopenharmony_ci bool is_young_gen_object = ObjectInYoungGeneration(node->object()); 9011cb0ef41Sopenharmony_ci DCHECK_IMPLIES(is_young_gen_object, node->is_in_young_list()); 9021cb0ef41Sopenharmony_ci } 9031cb0ef41Sopenharmony_ci bool in_young_list = 9041cb0ef41Sopenharmony_ci std::find(global_handles->traced_young_nodes_.begin(), 9051cb0ef41Sopenharmony_ci global_handles->traced_young_nodes_.end(), 9061cb0ef41Sopenharmony_ci node) != global_handles->traced_young_nodes_.end(); 9071cb0ef41Sopenharmony_ci DCHECK_EQ(in_young_list, node->is_in_young_list()); 9081cb0ef41Sopenharmony_ci#endif // DEBUG 9091cb0ef41Sopenharmony_ci} 9101cb0ef41Sopenharmony_ci 9111cb0ef41Sopenharmony_civoid GlobalHandles::CleanupOnStackReferencesBelowCurrentStackPosition() { 9121cb0ef41Sopenharmony_ci on_stack_nodes_->CleanupBelowCurrentStackPosition(); 9131cb0ef41Sopenharmony_ci} 9141cb0ef41Sopenharmony_ci 9151cb0ef41Sopenharmony_cisize_t GlobalHandles::NumberOfOnStackHandlesForTesting() { 9161cb0ef41Sopenharmony_ci return on_stack_nodes_->NumberOfHandlesForTesting(); 9171cb0ef41Sopenharmony_ci} 9181cb0ef41Sopenharmony_ci 9191cb0ef41Sopenharmony_cisize_t GlobalHandles::TotalSize() const { 9201cb0ef41Sopenharmony_ci return regular_nodes_->TotalSize() + traced_nodes_->TotalSize(); 9211cb0ef41Sopenharmony_ci} 9221cb0ef41Sopenharmony_ci 9231cb0ef41Sopenharmony_cisize_t GlobalHandles::UsedSize() const { 9241cb0ef41Sopenharmony_ci return regular_nodes_->handles_count() * sizeof(Node) + 9251cb0ef41Sopenharmony_ci traced_nodes_->handles_count() * sizeof(TracedNode); 9261cb0ef41Sopenharmony_ci} 9271cb0ef41Sopenharmony_ci 9281cb0ef41Sopenharmony_cisize_t GlobalHandles::handles_count() const { 9291cb0ef41Sopenharmony_ci return regular_nodes_->handles_count() + traced_nodes_->handles_count(); 9301cb0ef41Sopenharmony_ci} 9311cb0ef41Sopenharmony_ci 9321cb0ef41Sopenharmony_civoid GlobalHandles::SetStackStart(void* stack_start) { 9331cb0ef41Sopenharmony_ci on_stack_nodes_->SetStackStart(stack_start); 9341cb0ef41Sopenharmony_ci} 9351cb0ef41Sopenharmony_ci 9361cb0ef41Sopenharmony_civoid GlobalHandles::NotifyEmptyEmbedderStack() { 9371cb0ef41Sopenharmony_ci on_stack_nodes_->NotifyEmptyEmbedderStack(); 9381cb0ef41Sopenharmony_ci} 9391cb0ef41Sopenharmony_ci 9401cb0ef41Sopenharmony_ciGlobalHandles::GlobalHandles(Isolate* isolate) 9411cb0ef41Sopenharmony_ci : isolate_(isolate), 9421cb0ef41Sopenharmony_ci regular_nodes_(new NodeSpace<GlobalHandles::Node>(this)), 9431cb0ef41Sopenharmony_ci traced_nodes_(new NodeSpace<GlobalHandles::TracedNode>(this)), 9441cb0ef41Sopenharmony_ci on_stack_nodes_(new OnStackTracedNodeSpace(this)) {} 9451cb0ef41Sopenharmony_ci 9461cb0ef41Sopenharmony_ciGlobalHandles::~GlobalHandles() { regular_nodes_.reset(nullptr); } 9471cb0ef41Sopenharmony_ci 9481cb0ef41Sopenharmony_ciHandle<Object> GlobalHandles::Create(Object value) { 9491cb0ef41Sopenharmony_ci GlobalHandles::Node* result = regular_nodes_->Acquire(value); 9501cb0ef41Sopenharmony_ci if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) { 9511cb0ef41Sopenharmony_ci young_nodes_.push_back(result); 9521cb0ef41Sopenharmony_ci result->set_in_young_list(true); 9531cb0ef41Sopenharmony_ci } 9541cb0ef41Sopenharmony_ci return result->handle(); 9551cb0ef41Sopenharmony_ci} 9561cb0ef41Sopenharmony_ci 9571cb0ef41Sopenharmony_ciHandle<Object> GlobalHandles::Create(Address value) { 9581cb0ef41Sopenharmony_ci return Create(Object(value)); 9591cb0ef41Sopenharmony_ci} 9601cb0ef41Sopenharmony_ci 9611cb0ef41Sopenharmony_ciHandle<Object> GlobalHandles::CreateTraced(Object value, Address* slot, 9621cb0ef41Sopenharmony_ci GlobalHandleStoreMode store_mode) { 9631cb0ef41Sopenharmony_ci return CreateTraced( 9641cb0ef41Sopenharmony_ci value, slot, store_mode, 9651cb0ef41Sopenharmony_ci on_stack_nodes_->IsOnStack(reinterpret_cast<uintptr_t>(slot))); 9661cb0ef41Sopenharmony_ci} 9671cb0ef41Sopenharmony_ci 9681cb0ef41Sopenharmony_ciHandle<Object> GlobalHandles::CreateTraced(Object value, Address* slot, 9691cb0ef41Sopenharmony_ci GlobalHandleStoreMode store_mode, 9701cb0ef41Sopenharmony_ci bool is_on_stack) { 9711cb0ef41Sopenharmony_ci GlobalHandles::TracedNode* result; 9721cb0ef41Sopenharmony_ci if (is_on_stack) { 9731cb0ef41Sopenharmony_ci result = on_stack_nodes_->Acquire(value, reinterpret_cast<uintptr_t>(slot)); 9741cb0ef41Sopenharmony_ci } else { 9751cb0ef41Sopenharmony_ci result = traced_nodes_->Acquire(value); 9761cb0ef41Sopenharmony_ci if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) { 9771cb0ef41Sopenharmony_ci traced_young_nodes_.push_back(result); 9781cb0ef41Sopenharmony_ci result->set_in_young_list(true); 9791cb0ef41Sopenharmony_ci } 9801cb0ef41Sopenharmony_ci // Nodes are black allocated for simplicity. 9811cb0ef41Sopenharmony_ci result->set_markbit(); 9821cb0ef41Sopenharmony_ci if (store_mode != GlobalHandleStoreMode::kInitializingStore) { 9831cb0ef41Sopenharmony_ci WriteBarrier::MarkingFromGlobalHandle(value); 9841cb0ef41Sopenharmony_ci } 9851cb0ef41Sopenharmony_ci } 9861cb0ef41Sopenharmony_ci result->set_parameter(nullptr); 9871cb0ef41Sopenharmony_ci return result->handle(); 9881cb0ef41Sopenharmony_ci} 9891cb0ef41Sopenharmony_ci 9901cb0ef41Sopenharmony_ciHandle<Object> GlobalHandles::CreateTraced(Address value, Address* slot, 9911cb0ef41Sopenharmony_ci GlobalHandleStoreMode store_mode) { 9921cb0ef41Sopenharmony_ci return CreateTraced(Object(value), slot, store_mode); 9931cb0ef41Sopenharmony_ci} 9941cb0ef41Sopenharmony_ci 9951cb0ef41Sopenharmony_ciHandle<Object> GlobalHandles::CopyGlobal(Address* location) { 9961cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(location); 9971cb0ef41Sopenharmony_ci GlobalHandles* global_handles = 9981cb0ef41Sopenharmony_ci Node::FromLocation(location)->global_handles(); 9991cb0ef41Sopenharmony_ci#ifdef VERIFY_HEAP 10001cb0ef41Sopenharmony_ci if (i::FLAG_verify_heap) { 10011cb0ef41Sopenharmony_ci Object(*location).ObjectVerify(global_handles->isolate()); 10021cb0ef41Sopenharmony_ci } 10031cb0ef41Sopenharmony_ci#endif // VERIFY_HEAP 10041cb0ef41Sopenharmony_ci return global_handles->Create(*location); 10051cb0ef41Sopenharmony_ci} 10061cb0ef41Sopenharmony_ci 10071cb0ef41Sopenharmony_cinamespace { 10081cb0ef41Sopenharmony_civoid SetSlotThreadSafe(Address** slot, Address* val) { 10091cb0ef41Sopenharmony_ci reinterpret_cast<std::atomic<Address*>*>(slot)->store( 10101cb0ef41Sopenharmony_ci val, std::memory_order_relaxed); 10111cb0ef41Sopenharmony_ci} 10121cb0ef41Sopenharmony_ci} // namespace 10131cb0ef41Sopenharmony_ci 10141cb0ef41Sopenharmony_ci// static 10151cb0ef41Sopenharmony_civoid GlobalHandles::CopyTracedReference(const Address* const* from, 10161cb0ef41Sopenharmony_ci Address** to) { 10171cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(*from); 10181cb0ef41Sopenharmony_ci DCHECK_NULL(*to); 10191cb0ef41Sopenharmony_ci const TracedNode* node = TracedNode::FromLocation(*from); 10201cb0ef41Sopenharmony_ci GlobalHandles* global_handles = 10211cb0ef41Sopenharmony_ci GlobalHandles::From(const_cast<TracedNode*>(node)); 10221cb0ef41Sopenharmony_ci Handle<Object> o = global_handles->CreateTraced( 10231cb0ef41Sopenharmony_ci node->object(), reinterpret_cast<Address*>(to), 10241cb0ef41Sopenharmony_ci GlobalHandleStoreMode::kAssigningStore); 10251cb0ef41Sopenharmony_ci SetSlotThreadSafe(to, o.location()); 10261cb0ef41Sopenharmony_ci TracedNode::Verify(global_handles, from); 10271cb0ef41Sopenharmony_ci TracedNode::Verify(global_handles, to); 10281cb0ef41Sopenharmony_ci#ifdef VERIFY_HEAP 10291cb0ef41Sopenharmony_ci if (i::FLAG_verify_heap) { 10301cb0ef41Sopenharmony_ci Object(**to).ObjectVerify(global_handles->isolate()); 10311cb0ef41Sopenharmony_ci } 10321cb0ef41Sopenharmony_ci#endif // VERIFY_HEAP 10331cb0ef41Sopenharmony_ci} 10341cb0ef41Sopenharmony_ci 10351cb0ef41Sopenharmony_civoid GlobalHandles::MoveGlobal(Address** from, Address** to) { 10361cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(*from); 10371cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(*to); 10381cb0ef41Sopenharmony_ci DCHECK_EQ(*from, *to); 10391cb0ef41Sopenharmony_ci Node* node = Node::FromLocation(*from); 10401cb0ef41Sopenharmony_ci if (node->IsWeak() && node->IsPhantomResetHandle()) { 10411cb0ef41Sopenharmony_ci node->set_parameter(to); 10421cb0ef41Sopenharmony_ci } 10431cb0ef41Sopenharmony_ci 10441cb0ef41Sopenharmony_ci // - Strong handles do not require fixups. 10451cb0ef41Sopenharmony_ci // - Weak handles with finalizers and callbacks are too general to fix up. For 10461cb0ef41Sopenharmony_ci // those the callers need to ensure consistency. 10471cb0ef41Sopenharmony_ci} 10481cb0ef41Sopenharmony_ci 10491cb0ef41Sopenharmony_civoid GlobalHandles::MoveTracedReference(Address** from, Address** to) { 10501cb0ef41Sopenharmony_ci // Fast path for moving from an empty reference. 10511cb0ef41Sopenharmony_ci if (!*from) { 10521cb0ef41Sopenharmony_ci DestroyTracedReference(*to); 10531cb0ef41Sopenharmony_ci SetSlotThreadSafe(to, nullptr); 10541cb0ef41Sopenharmony_ci return; 10551cb0ef41Sopenharmony_ci } 10561cb0ef41Sopenharmony_ci 10571cb0ef41Sopenharmony_ci // Determining whether from or to are on stack. 10581cb0ef41Sopenharmony_ci TracedNode* from_node = TracedNode::FromLocation(*from); 10591cb0ef41Sopenharmony_ci DCHECK(from_node->IsInUse()); 10601cb0ef41Sopenharmony_ci TracedNode* to_node = TracedNode::FromLocation(*to); 10611cb0ef41Sopenharmony_ci GlobalHandles* global_handles = nullptr; 10621cb0ef41Sopenharmony_ci#ifdef DEBUG 10631cb0ef41Sopenharmony_ci global_handles = GlobalHandles::From(from_node); 10641cb0ef41Sopenharmony_ci#endif // DEBUG 10651cb0ef41Sopenharmony_ci bool from_on_stack = from_node->is_on_stack(); 10661cb0ef41Sopenharmony_ci bool to_on_stack = false; 10671cb0ef41Sopenharmony_ci if (!to_node) { 10681cb0ef41Sopenharmony_ci // Figure out whether stack or heap to allow fast path for heap->heap move. 10691cb0ef41Sopenharmony_ci global_handles = GlobalHandles::From(from_node); 10701cb0ef41Sopenharmony_ci to_on_stack = global_handles->on_stack_nodes_->IsOnStack( 10711cb0ef41Sopenharmony_ci reinterpret_cast<uintptr_t>(to)); 10721cb0ef41Sopenharmony_ci } else { 10731cb0ef41Sopenharmony_ci to_on_stack = to_node->is_on_stack(); 10741cb0ef41Sopenharmony_ci } 10751cb0ef41Sopenharmony_ci 10761cb0ef41Sopenharmony_ci // Moving. 10771cb0ef41Sopenharmony_ci if (from_on_stack || to_on_stack) { 10781cb0ef41Sopenharmony_ci // Move involving a stack slot. 10791cb0ef41Sopenharmony_ci if (!to_node) { 10801cb0ef41Sopenharmony_ci DCHECK(global_handles); 10811cb0ef41Sopenharmony_ci Handle<Object> o = global_handles->CreateTraced( 10821cb0ef41Sopenharmony_ci from_node->object(), reinterpret_cast<Address*>(to), 10831cb0ef41Sopenharmony_ci GlobalHandleStoreMode::kAssigningStore, to_on_stack); 10841cb0ef41Sopenharmony_ci SetSlotThreadSafe(to, o.location()); 10851cb0ef41Sopenharmony_ci to_node = TracedNode::FromLocation(*to); 10861cb0ef41Sopenharmony_ci DCHECK_IMPLIES(!to_node->is_on_stack(), to_node->markbit()); 10871cb0ef41Sopenharmony_ci } else { 10881cb0ef41Sopenharmony_ci DCHECK(to_node->IsInUse()); 10891cb0ef41Sopenharmony_ci to_node->CopyObjectReference(*from_node); 10901cb0ef41Sopenharmony_ci if (!to_node->is_on_stack() && !to_node->is_in_young_list() && 10911cb0ef41Sopenharmony_ci ObjectInYoungGeneration(to_node->object())) { 10921cb0ef41Sopenharmony_ci global_handles = GlobalHandles::From(from_node); 10931cb0ef41Sopenharmony_ci global_handles->traced_young_nodes_.push_back(to_node); 10941cb0ef41Sopenharmony_ci to_node->set_in_young_list(true); 10951cb0ef41Sopenharmony_ci } 10961cb0ef41Sopenharmony_ci if (!to_on_stack) { 10971cb0ef41Sopenharmony_ci WriteBarrier::MarkingFromGlobalHandle(to_node->object()); 10981cb0ef41Sopenharmony_ci } 10991cb0ef41Sopenharmony_ci } 11001cb0ef41Sopenharmony_ci DestroyTracedReference(*from); 11011cb0ef41Sopenharmony_ci SetSlotThreadSafe(from, nullptr); 11021cb0ef41Sopenharmony_ci } else { 11031cb0ef41Sopenharmony_ci // Pure heap move. 11041cb0ef41Sopenharmony_ci DestroyTracedReference(*to); 11051cb0ef41Sopenharmony_ci SetSlotThreadSafe(to, *from); 11061cb0ef41Sopenharmony_ci to_node = from_node; 11071cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(*from); 11081cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(*to); 11091cb0ef41Sopenharmony_ci DCHECK_EQ(*from, *to); 11101cb0ef41Sopenharmony_ci WriteBarrier::MarkingFromGlobalHandle(to_node->object()); 11111cb0ef41Sopenharmony_ci SetSlotThreadSafe(from, nullptr); 11121cb0ef41Sopenharmony_ci } 11131cb0ef41Sopenharmony_ci TracedNode::Verify(global_handles, to); 11141cb0ef41Sopenharmony_ci} 11151cb0ef41Sopenharmony_ci 11161cb0ef41Sopenharmony_ci// static 11171cb0ef41Sopenharmony_ciGlobalHandles* GlobalHandles::From(const TracedNode* node) { 11181cb0ef41Sopenharmony_ci return node->is_on_stack() 11191cb0ef41Sopenharmony_ci ? OnStackTracedNodeSpace::GetGlobalHandles(node) 11201cb0ef41Sopenharmony_ci : NodeBlock<TracedNode>::From(node)->global_handles(); 11211cb0ef41Sopenharmony_ci} 11221cb0ef41Sopenharmony_ci 11231cb0ef41Sopenharmony_civoid GlobalHandles::MarkTraced(Address* location) { 11241cb0ef41Sopenharmony_ci TracedNode* node = TracedNode::FromLocation(location); 11251cb0ef41Sopenharmony_ci DCHECK(node->IsInUse()); 11261cb0ef41Sopenharmony_ci if (node->is_on_stack()) return; 11271cb0ef41Sopenharmony_ci node->set_markbit(); 11281cb0ef41Sopenharmony_ci} 11291cb0ef41Sopenharmony_ci 11301cb0ef41Sopenharmony_civoid GlobalHandles::Destroy(Address* location) { 11311cb0ef41Sopenharmony_ci if (location != nullptr) { 11321cb0ef41Sopenharmony_ci NodeSpace<Node>::Release(Node::FromLocation(location)); 11331cb0ef41Sopenharmony_ci } 11341cb0ef41Sopenharmony_ci} 11351cb0ef41Sopenharmony_ci 11361cb0ef41Sopenharmony_ci// static 11371cb0ef41Sopenharmony_civoid GlobalHandles::DestroyTracedReference(Address* location) { 11381cb0ef41Sopenharmony_ci if (location != nullptr) { 11391cb0ef41Sopenharmony_ci TracedNode* node = TracedNode::FromLocation(location); 11401cb0ef41Sopenharmony_ci if (node->is_on_stack()) { 11411cb0ef41Sopenharmony_ci node->Release(nullptr); 11421cb0ef41Sopenharmony_ci return; 11431cb0ef41Sopenharmony_ci } 11441cb0ef41Sopenharmony_ci DCHECK(!node->is_on_stack()); 11451cb0ef41Sopenharmony_ci 11461cb0ef41Sopenharmony_ci auto* global_handles = GlobalHandles::From(node); 11471cb0ef41Sopenharmony_ci // When marking is off the handle may be freed immediately. Note that this 11481cb0ef41Sopenharmony_ci // includes also the case when invoking the first pass callbacks during the 11491cb0ef41Sopenharmony_ci // atomic pause which requires releasing a node fully. 11501cb0ef41Sopenharmony_ci if (!global_handles->is_marking_) { 11511cb0ef41Sopenharmony_ci NodeSpace<TracedNode>::Release(node); 11521cb0ef41Sopenharmony_ci return; 11531cb0ef41Sopenharmony_ci } 11541cb0ef41Sopenharmony_ci 11551cb0ef41Sopenharmony_ci // Incremental marking is on. This also covers the scavenge case which 11561cb0ef41Sopenharmony_ci // prohibits eagerly reclaiming nodes when marking is on during a scavenge. 11571cb0ef41Sopenharmony_ci // 11581cb0ef41Sopenharmony_ci // On-heap traced nodes are released in the atomic pause in 11591cb0ef41Sopenharmony_ci // `IterateWeakRootsForPhantomHandles()` when they are discovered as not 11601cb0ef41Sopenharmony_ci // marked. 11611cb0ef41Sopenharmony_ci // 11621cb0ef41Sopenharmony_ci // Eagerly clear out the object here to avoid needlessly marking it from 11631cb0ef41Sopenharmony_ci // this point on. Also clear out callback and backreference for the version 11641cb0ef41Sopenharmony_ci // with callbacks to avoid calling into possibly dead memory later. 11651cb0ef41Sopenharmony_ci // 11661cb0ef41Sopenharmony_ci // In the case this happens during incremental marking, the node may 11671cb0ef41Sopenharmony_ci // still be spuriously marked as live and is then only reclaimed on the 11681cb0ef41Sopenharmony_ci // next cycle. 11691cb0ef41Sopenharmony_ci node->clear_object(); 11701cb0ef41Sopenharmony_ci node->set_parameter(nullptr); 11711cb0ef41Sopenharmony_ci } 11721cb0ef41Sopenharmony_ci} 11731cb0ef41Sopenharmony_ci 11741cb0ef41Sopenharmony_ciusing GenericCallback = v8::WeakCallbackInfo<void>::Callback; 11751cb0ef41Sopenharmony_ci 11761cb0ef41Sopenharmony_civoid GlobalHandles::MakeWeak(Address* location, void* parameter, 11771cb0ef41Sopenharmony_ci GenericCallback phantom_callback, 11781cb0ef41Sopenharmony_ci v8::WeakCallbackType type) { 11791cb0ef41Sopenharmony_ci Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type); 11801cb0ef41Sopenharmony_ci} 11811cb0ef41Sopenharmony_ci 11821cb0ef41Sopenharmony_civoid GlobalHandles::MakeWeak(Address** location_addr) { 11831cb0ef41Sopenharmony_ci Node::FromLocation(*location_addr)->MakeWeak(location_addr); 11841cb0ef41Sopenharmony_ci} 11851cb0ef41Sopenharmony_ci 11861cb0ef41Sopenharmony_civoid* GlobalHandles::ClearWeakness(Address* location) { 11871cb0ef41Sopenharmony_ci return Node::FromLocation(location)->ClearWeakness(); 11881cb0ef41Sopenharmony_ci} 11891cb0ef41Sopenharmony_ci 11901cb0ef41Sopenharmony_civoid GlobalHandles::AnnotateStrongRetainer(Address* location, 11911cb0ef41Sopenharmony_ci const char* label) { 11921cb0ef41Sopenharmony_ci Node::FromLocation(location)->AnnotateStrongRetainer(label); 11931cb0ef41Sopenharmony_ci} 11941cb0ef41Sopenharmony_ci 11951cb0ef41Sopenharmony_cibool GlobalHandles::IsWeak(Address* location) { 11961cb0ef41Sopenharmony_ci return Node::FromLocation(location)->IsWeak(); 11971cb0ef41Sopenharmony_ci} 11981cb0ef41Sopenharmony_ci 11991cb0ef41Sopenharmony_ciDISABLE_CFI_PERF 12001cb0ef41Sopenharmony_civoid GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) { 12011cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 12021cb0ef41Sopenharmony_ci if (node->IsWeakRetainer() && node->state() == Node::PENDING) { 12031cb0ef41Sopenharmony_ci DCHECK(!node->IsPhantomCallback()); 12041cb0ef41Sopenharmony_ci DCHECK(!node->IsPhantomResetHandle()); 12051cb0ef41Sopenharmony_ci // Finalizers need to survive. 12061cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, node->label(), 12071cb0ef41Sopenharmony_ci node->location()); 12081cb0ef41Sopenharmony_ci } 12091cb0ef41Sopenharmony_ci } 12101cb0ef41Sopenharmony_ci} 12111cb0ef41Sopenharmony_ci 12121cb0ef41Sopenharmony_ciDISABLE_CFI_PERF 12131cb0ef41Sopenharmony_civoid GlobalHandles::IterateWeakRootsForPhantomHandles( 12141cb0ef41Sopenharmony_ci WeakSlotCallbackWithHeap should_reset_handle) { 12151cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 12161cb0ef41Sopenharmony_ci if (node->IsWeakRetainer() && 12171cb0ef41Sopenharmony_ci should_reset_handle(isolate()->heap(), node->location())) { 12181cb0ef41Sopenharmony_ci if (node->IsPhantomResetHandle()) { 12191cb0ef41Sopenharmony_ci node->MarkPending(); 12201cb0ef41Sopenharmony_ci node->ResetPhantomHandle(); 12211cb0ef41Sopenharmony_ci ++number_of_phantom_handle_resets_; 12221cb0ef41Sopenharmony_ci } else if (node->IsPhantomCallback()) { 12231cb0ef41Sopenharmony_ci node->MarkPending(); 12241cb0ef41Sopenharmony_ci node->CollectPhantomCallbackData(®ular_pending_phantom_callbacks_); 12251cb0ef41Sopenharmony_ci } 12261cb0ef41Sopenharmony_ci } 12271cb0ef41Sopenharmony_ci } 12281cb0ef41Sopenharmony_ci for (TracedNode* node : *traced_nodes_) { 12291cb0ef41Sopenharmony_ci if (!node->IsInUse()) continue; 12301cb0ef41Sopenharmony_ci // Detect unreachable nodes first. 12311cb0ef41Sopenharmony_ci if (!node->markbit()) { 12321cb0ef41Sopenharmony_ci // The handle itself is unreachable. We can clear it even if the target V8 12331cb0ef41Sopenharmony_ci // object is alive. 12341cb0ef41Sopenharmony_ci node->ResetPhantomHandle(); 12351cb0ef41Sopenharmony_ci ++number_of_phantom_handle_resets_; 12361cb0ef41Sopenharmony_ci continue; 12371cb0ef41Sopenharmony_ci } 12381cb0ef41Sopenharmony_ci // Clear the markbit for the next GC. 12391cb0ef41Sopenharmony_ci node->clear_markbit(); 12401cb0ef41Sopenharmony_ci DCHECK(node->IsInUse()); 12411cb0ef41Sopenharmony_ci // Detect nodes with unreachable target objects. 12421cb0ef41Sopenharmony_ci if (should_reset_handle(isolate()->heap(), node->location())) { 12431cb0ef41Sopenharmony_ci node->ResetPhantomHandle(); 12441cb0ef41Sopenharmony_ci ++number_of_phantom_handle_resets_; 12451cb0ef41Sopenharmony_ci } 12461cb0ef41Sopenharmony_ci } 12471cb0ef41Sopenharmony_ci} 12481cb0ef41Sopenharmony_ci 12491cb0ef41Sopenharmony_civoid GlobalHandles::IterateWeakRootsIdentifyFinalizers( 12501cb0ef41Sopenharmony_ci WeakSlotCallbackWithHeap should_reset_handle) { 12511cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 12521cb0ef41Sopenharmony_ci if (node->IsWeak() && 12531cb0ef41Sopenharmony_ci should_reset_handle(isolate()->heap(), node->location())) { 12541cb0ef41Sopenharmony_ci if (node->IsFinalizerHandle()) { 12551cb0ef41Sopenharmony_ci node->MarkPending(); 12561cb0ef41Sopenharmony_ci } 12571cb0ef41Sopenharmony_ci } 12581cb0ef41Sopenharmony_ci } 12591cb0ef41Sopenharmony_ci} 12601cb0ef41Sopenharmony_ci 12611cb0ef41Sopenharmony_civoid GlobalHandles::IdentifyWeakUnmodifiedObjects( 12621cb0ef41Sopenharmony_ci WeakSlotCallback is_unmodified) { 12631cb0ef41Sopenharmony_ci if (!FLAG_reclaim_unmodified_wrappers) return; 12641cb0ef41Sopenharmony_ci 12651cb0ef41Sopenharmony_ci // Treat all objects as roots during incremental marking to avoid corrupting 12661cb0ef41Sopenharmony_ci // marking worklists. 12671cb0ef41Sopenharmony_ci if (isolate()->heap()->incremental_marking()->IsMarking()) return; 12681cb0ef41Sopenharmony_ci 12691cb0ef41Sopenharmony_ci auto* const handler = isolate()->heap()->GetEmbedderRootsHandler(); 12701cb0ef41Sopenharmony_ci for (TracedNode* node : traced_young_nodes_) { 12711cb0ef41Sopenharmony_ci if (node->IsInUse()) { 12721cb0ef41Sopenharmony_ci DCHECK(node->is_root()); 12731cb0ef41Sopenharmony_ci if (is_unmodified(node->location())) { 12741cb0ef41Sopenharmony_ci v8::Value* value = ToApi<v8::Value>(node->handle()); 12751cb0ef41Sopenharmony_ci node->set_root(handler->IsRoot( 12761cb0ef41Sopenharmony_ci *reinterpret_cast<v8::TracedReference<v8::Value>*>(&value))); 12771cb0ef41Sopenharmony_ci } 12781cb0ef41Sopenharmony_ci } 12791cb0ef41Sopenharmony_ci } 12801cb0ef41Sopenharmony_ci} 12811cb0ef41Sopenharmony_ci 12821cb0ef41Sopenharmony_civoid GlobalHandles::IterateYoungStrongAndDependentRoots(RootVisitor* v) { 12831cb0ef41Sopenharmony_ci for (Node* node : young_nodes_) { 12841cb0ef41Sopenharmony_ci if (node->IsStrongRetainer()) { 12851cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, node->label(), 12861cb0ef41Sopenharmony_ci node->location()); 12871cb0ef41Sopenharmony_ci } 12881cb0ef41Sopenharmony_ci } 12891cb0ef41Sopenharmony_ci for (TracedNode* node : traced_young_nodes_) { 12901cb0ef41Sopenharmony_ci if (node->IsInUse() && node->is_root()) { 12911cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location()); 12921cb0ef41Sopenharmony_ci } 12931cb0ef41Sopenharmony_ci } 12941cb0ef41Sopenharmony_ci} 12951cb0ef41Sopenharmony_ci 12961cb0ef41Sopenharmony_civoid GlobalHandles::MarkYoungWeakDeadObjectsPending( 12971cb0ef41Sopenharmony_ci WeakSlotCallbackWithHeap is_dead) { 12981cb0ef41Sopenharmony_ci for (Node* node : young_nodes_) { 12991cb0ef41Sopenharmony_ci DCHECK(node->is_in_young_list()); 13001cb0ef41Sopenharmony_ci if (node->IsWeak() && is_dead(isolate_->heap(), node->location())) { 13011cb0ef41Sopenharmony_ci if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) { 13021cb0ef41Sopenharmony_ci node->MarkPending(); 13031cb0ef41Sopenharmony_ci } 13041cb0ef41Sopenharmony_ci } 13051cb0ef41Sopenharmony_ci } 13061cb0ef41Sopenharmony_ci} 13071cb0ef41Sopenharmony_ci 13081cb0ef41Sopenharmony_civoid GlobalHandles::IterateYoungWeakDeadObjectsForFinalizers(RootVisitor* v) { 13091cb0ef41Sopenharmony_ci for (Node* node : young_nodes_) { 13101cb0ef41Sopenharmony_ci DCHECK(node->is_in_young_list()); 13111cb0ef41Sopenharmony_ci if (node->IsWeakRetainer() && (node->state() == Node::PENDING)) { 13121cb0ef41Sopenharmony_ci DCHECK(!node->IsPhantomCallback()); 13131cb0ef41Sopenharmony_ci DCHECK(!node->IsPhantomResetHandle()); 13141cb0ef41Sopenharmony_ci // Finalizers need to survive. 13151cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, node->label(), 13161cb0ef41Sopenharmony_ci node->location()); 13171cb0ef41Sopenharmony_ci } 13181cb0ef41Sopenharmony_ci } 13191cb0ef41Sopenharmony_ci} 13201cb0ef41Sopenharmony_ci 13211cb0ef41Sopenharmony_civoid GlobalHandles::IterateYoungWeakObjectsForPhantomHandles( 13221cb0ef41Sopenharmony_ci RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle) { 13231cb0ef41Sopenharmony_ci for (Node* node : young_nodes_) { 13241cb0ef41Sopenharmony_ci DCHECK(node->is_in_young_list()); 13251cb0ef41Sopenharmony_ci if (node->IsWeakRetainer() && (node->state() != Node::PENDING)) { 13261cb0ef41Sopenharmony_ci if (should_reset_handle(isolate_->heap(), node->location())) { 13271cb0ef41Sopenharmony_ci DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback()); 13281cb0ef41Sopenharmony_ci if (node->IsPhantomResetHandle()) { 13291cb0ef41Sopenharmony_ci node->MarkPending(); 13301cb0ef41Sopenharmony_ci node->ResetPhantomHandle(); 13311cb0ef41Sopenharmony_ci ++number_of_phantom_handle_resets_; 13321cb0ef41Sopenharmony_ci } else if (node->IsPhantomCallback()) { 13331cb0ef41Sopenharmony_ci node->MarkPending(); 13341cb0ef41Sopenharmony_ci node->CollectPhantomCallbackData(®ular_pending_phantom_callbacks_); 13351cb0ef41Sopenharmony_ci } else { 13361cb0ef41Sopenharmony_ci UNREACHABLE(); 13371cb0ef41Sopenharmony_ci } 13381cb0ef41Sopenharmony_ci } else { 13391cb0ef41Sopenharmony_ci // Node survived and needs to be visited. 13401cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, node->label(), 13411cb0ef41Sopenharmony_ci node->location()); 13421cb0ef41Sopenharmony_ci } 13431cb0ef41Sopenharmony_ci } 13441cb0ef41Sopenharmony_ci } 13451cb0ef41Sopenharmony_ci 13461cb0ef41Sopenharmony_ci if (!FLAG_reclaim_unmodified_wrappers) return; 13471cb0ef41Sopenharmony_ci 13481cb0ef41Sopenharmony_ci auto* const handler = isolate()->heap()->GetEmbedderRootsHandler(); 13491cb0ef41Sopenharmony_ci for (TracedNode* node : traced_young_nodes_) { 13501cb0ef41Sopenharmony_ci if (!node->IsInUse()) continue; 13511cb0ef41Sopenharmony_ci 13521cb0ef41Sopenharmony_ci DCHECK_IMPLIES(node->is_root(), 13531cb0ef41Sopenharmony_ci !should_reset_handle(isolate_->heap(), node->location())); 13541cb0ef41Sopenharmony_ci if (should_reset_handle(isolate_->heap(), node->location())) { 13551cb0ef41Sopenharmony_ci v8::Value* value = ToApi<v8::Value>(node->handle()); 13561cb0ef41Sopenharmony_ci handler->ResetRoot( 13571cb0ef41Sopenharmony_ci *reinterpret_cast<v8::TracedReference<v8::Value>*>(&value)); 13581cb0ef41Sopenharmony_ci // We cannot check whether a node is in use here as the reset behavior 13591cb0ef41Sopenharmony_ci // depends on whether incremental marking is running when reclaiming 13601cb0ef41Sopenharmony_ci // young objects. 13611cb0ef41Sopenharmony_ci ++number_of_phantom_handle_resets_; 13621cb0ef41Sopenharmony_ci } else { 13631cb0ef41Sopenharmony_ci if (!node->is_root()) { 13641cb0ef41Sopenharmony_ci node->set_root(true); 13651cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location()); 13661cb0ef41Sopenharmony_ci } 13671cb0ef41Sopenharmony_ci } 13681cb0ef41Sopenharmony_ci } 13691cb0ef41Sopenharmony_ci} 13701cb0ef41Sopenharmony_ci 13711cb0ef41Sopenharmony_civoid GlobalHandles::InvokeSecondPassPhantomCallbacksFromTask() { 13721cb0ef41Sopenharmony_ci DCHECK(second_pass_callbacks_task_posted_); 13731cb0ef41Sopenharmony_ci second_pass_callbacks_task_posted_ = false; 13741cb0ef41Sopenharmony_ci Heap::DevToolsTraceEventScope devtools_trace_event_scope( 13751cb0ef41Sopenharmony_ci isolate()->heap(), "MajorGC", "invoke weak phantom callbacks"); 13761cb0ef41Sopenharmony_ci TRACE_EVENT0("v8", "V8.GCPhantomHandleProcessingCallback"); 13771cb0ef41Sopenharmony_ci isolate()->heap()->CallGCPrologueCallbacks( 13781cb0ef41Sopenharmony_ci GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags); 13791cb0ef41Sopenharmony_ci InvokeSecondPassPhantomCallbacks(); 13801cb0ef41Sopenharmony_ci isolate()->heap()->CallGCEpilogueCallbacks( 13811cb0ef41Sopenharmony_ci GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags); 13821cb0ef41Sopenharmony_ci} 13831cb0ef41Sopenharmony_ci 13841cb0ef41Sopenharmony_civoid GlobalHandles::InvokeSecondPassPhantomCallbacks() { 13851cb0ef41Sopenharmony_ci // The callbacks may execute JS, which in turn may lead to another GC run. 13861cb0ef41Sopenharmony_ci // If we are already processing the callbacks, we do not want to start over 13871cb0ef41Sopenharmony_ci // from within the inner GC. Newly added callbacks will always be run by the 13881cb0ef41Sopenharmony_ci // outermost GC run only. 13891cb0ef41Sopenharmony_ci if (running_second_pass_callbacks_) return; 13901cb0ef41Sopenharmony_ci running_second_pass_callbacks_ = true; 13911cb0ef41Sopenharmony_ci 13921cb0ef41Sopenharmony_ci AllowJavascriptExecution allow_js(isolate()); 13931cb0ef41Sopenharmony_ci while (!second_pass_callbacks_.empty()) { 13941cb0ef41Sopenharmony_ci auto callback = second_pass_callbacks_.back(); 13951cb0ef41Sopenharmony_ci second_pass_callbacks_.pop_back(); 13961cb0ef41Sopenharmony_ci callback.Invoke(isolate(), PendingPhantomCallback::kSecondPass); 13971cb0ef41Sopenharmony_ci } 13981cb0ef41Sopenharmony_ci running_second_pass_callbacks_ = false; 13991cb0ef41Sopenharmony_ci} 14001cb0ef41Sopenharmony_ci 14011cb0ef41Sopenharmony_cisize_t GlobalHandles::PostScavengeProcessing(unsigned post_processing_count) { 14021cb0ef41Sopenharmony_ci size_t freed_nodes = 0; 14031cb0ef41Sopenharmony_ci for (Node* node : young_nodes_) { 14041cb0ef41Sopenharmony_ci // Filter free nodes. 14051cb0ef41Sopenharmony_ci if (!node->IsRetainer()) continue; 14061cb0ef41Sopenharmony_ci 14071cb0ef41Sopenharmony_ci if (node->IsPending()) { 14081cb0ef41Sopenharmony_ci DCHECK(node->has_callback()); 14091cb0ef41Sopenharmony_ci DCHECK(node->IsPendingFinalizer()); 14101cb0ef41Sopenharmony_ci node->PostGarbageCollectionProcessing(isolate_); 14111cb0ef41Sopenharmony_ci } 14121cb0ef41Sopenharmony_ci if (InRecursiveGC(post_processing_count)) return freed_nodes; 14131cb0ef41Sopenharmony_ci 14141cb0ef41Sopenharmony_ci if (!node->IsRetainer()) freed_nodes++; 14151cb0ef41Sopenharmony_ci } 14161cb0ef41Sopenharmony_ci return freed_nodes; 14171cb0ef41Sopenharmony_ci} 14181cb0ef41Sopenharmony_ci 14191cb0ef41Sopenharmony_cisize_t GlobalHandles::PostMarkSweepProcessing(unsigned post_processing_count) { 14201cb0ef41Sopenharmony_ci size_t freed_nodes = 0; 14211cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 14221cb0ef41Sopenharmony_ci // Filter free nodes. 14231cb0ef41Sopenharmony_ci if (!node->IsRetainer()) continue; 14241cb0ef41Sopenharmony_ci 14251cb0ef41Sopenharmony_ci if (node->IsPending()) { 14261cb0ef41Sopenharmony_ci DCHECK(node->has_callback()); 14271cb0ef41Sopenharmony_ci DCHECK(node->IsPendingFinalizer()); 14281cb0ef41Sopenharmony_ci node->PostGarbageCollectionProcessing(isolate_); 14291cb0ef41Sopenharmony_ci } 14301cb0ef41Sopenharmony_ci if (InRecursiveGC(post_processing_count)) return freed_nodes; 14311cb0ef41Sopenharmony_ci 14321cb0ef41Sopenharmony_ci if (!node->IsRetainer()) freed_nodes++; 14331cb0ef41Sopenharmony_ci } 14341cb0ef41Sopenharmony_ci return freed_nodes; 14351cb0ef41Sopenharmony_ci} 14361cb0ef41Sopenharmony_ci 14371cb0ef41Sopenharmony_citemplate <typename T> 14381cb0ef41Sopenharmony_civoid GlobalHandles::UpdateAndCompactListOfYoungNode( 14391cb0ef41Sopenharmony_ci std::vector<T*>* node_list) { 14401cb0ef41Sopenharmony_ci size_t last = 0; 14411cb0ef41Sopenharmony_ci for (T* node : *node_list) { 14421cb0ef41Sopenharmony_ci DCHECK(node->is_in_young_list()); 14431cb0ef41Sopenharmony_ci if (node->IsInUse()) { 14441cb0ef41Sopenharmony_ci if (ObjectInYoungGeneration(node->object())) { 14451cb0ef41Sopenharmony_ci (*node_list)[last++] = node; 14461cb0ef41Sopenharmony_ci isolate_->heap()->IncrementNodesCopiedInNewSpace(); 14471cb0ef41Sopenharmony_ci } else { 14481cb0ef41Sopenharmony_ci node->set_in_young_list(false); 14491cb0ef41Sopenharmony_ci isolate_->heap()->IncrementNodesPromoted(); 14501cb0ef41Sopenharmony_ci } 14511cb0ef41Sopenharmony_ci } else { 14521cb0ef41Sopenharmony_ci node->set_in_young_list(false); 14531cb0ef41Sopenharmony_ci isolate_->heap()->IncrementNodesDiedInNewSpace(); 14541cb0ef41Sopenharmony_ci } 14551cb0ef41Sopenharmony_ci } 14561cb0ef41Sopenharmony_ci DCHECK_LE(last, node_list->size()); 14571cb0ef41Sopenharmony_ci node_list->resize(last); 14581cb0ef41Sopenharmony_ci node_list->shrink_to_fit(); 14591cb0ef41Sopenharmony_ci} 14601cb0ef41Sopenharmony_ci 14611cb0ef41Sopenharmony_civoid GlobalHandles::UpdateListOfYoungNodes() { 14621cb0ef41Sopenharmony_ci UpdateAndCompactListOfYoungNode(&young_nodes_); 14631cb0ef41Sopenharmony_ci UpdateAndCompactListOfYoungNode(&traced_young_nodes_); 14641cb0ef41Sopenharmony_ci} 14651cb0ef41Sopenharmony_ci 14661cb0ef41Sopenharmony_citemplate <typename T> 14671cb0ef41Sopenharmony_cisize_t GlobalHandles::InvokeFirstPassWeakCallbacks( 14681cb0ef41Sopenharmony_ci std::vector<std::pair<T*, PendingPhantomCallback>>* pending) { 14691cb0ef41Sopenharmony_ci size_t freed_nodes = 0; 14701cb0ef41Sopenharmony_ci std::vector<std::pair<T*, PendingPhantomCallback>> pending_phantom_callbacks; 14711cb0ef41Sopenharmony_ci pending_phantom_callbacks.swap(*pending); 14721cb0ef41Sopenharmony_ci { 14731cb0ef41Sopenharmony_ci // The initial pass callbacks must simply clear the nodes. 14741cb0ef41Sopenharmony_ci for (auto& pair : pending_phantom_callbacks) { 14751cb0ef41Sopenharmony_ci T* node = pair.first; 14761cb0ef41Sopenharmony_ci DCHECK_EQ(T::NEAR_DEATH, node->state()); 14771cb0ef41Sopenharmony_ci pair.second.Invoke(isolate(), PendingPhantomCallback::kFirstPass); 14781cb0ef41Sopenharmony_ci 14791cb0ef41Sopenharmony_ci // Transition to second pass. It is required that the first pass callback 14801cb0ef41Sopenharmony_ci // resets the handle using |v8::PersistentBase::Reset|. Also see comments 14811cb0ef41Sopenharmony_ci // on |v8::WeakCallbackInfo|. 14821cb0ef41Sopenharmony_ci CHECK_WITH_MSG(T::FREE == node->state(), 14831cb0ef41Sopenharmony_ci "Handle not reset in first callback. See comments on " 14841cb0ef41Sopenharmony_ci "|v8::WeakCallbackInfo|."); 14851cb0ef41Sopenharmony_ci 14861cb0ef41Sopenharmony_ci if (pair.second.callback()) second_pass_callbacks_.push_back(pair.second); 14871cb0ef41Sopenharmony_ci freed_nodes++; 14881cb0ef41Sopenharmony_ci } 14891cb0ef41Sopenharmony_ci } 14901cb0ef41Sopenharmony_ci return freed_nodes; 14911cb0ef41Sopenharmony_ci} 14921cb0ef41Sopenharmony_ci 14931cb0ef41Sopenharmony_cisize_t GlobalHandles::InvokeFirstPassWeakCallbacks() { 14941cb0ef41Sopenharmony_ci return InvokeFirstPassWeakCallbacks(®ular_pending_phantom_callbacks_) + 14951cb0ef41Sopenharmony_ci InvokeFirstPassWeakCallbacks(&traced_pending_phantom_callbacks_); 14961cb0ef41Sopenharmony_ci} 14971cb0ef41Sopenharmony_ci 14981cb0ef41Sopenharmony_civoid GlobalHandles::InvokeOrScheduleSecondPassPhantomCallbacks( 14991cb0ef41Sopenharmony_ci bool synchronous_second_pass) { 15001cb0ef41Sopenharmony_ci if (!second_pass_callbacks_.empty()) { 15011cb0ef41Sopenharmony_ci if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) { 15021cb0ef41Sopenharmony_ci Heap::DevToolsTraceEventScope devtools_trace_event_scope( 15031cb0ef41Sopenharmony_ci isolate()->heap(), "MajorGC", "invoke weak phantom callbacks"); 15041cb0ef41Sopenharmony_ci isolate()->heap()->CallGCPrologueCallbacks( 15051cb0ef41Sopenharmony_ci GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags); 15061cb0ef41Sopenharmony_ci InvokeSecondPassPhantomCallbacks(); 15071cb0ef41Sopenharmony_ci isolate()->heap()->CallGCEpilogueCallbacks( 15081cb0ef41Sopenharmony_ci GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags); 15091cb0ef41Sopenharmony_ci } else if (!second_pass_callbacks_task_posted_) { 15101cb0ef41Sopenharmony_ci second_pass_callbacks_task_posted_ = true; 15111cb0ef41Sopenharmony_ci auto taskrunner = V8::GetCurrentPlatform()->GetForegroundTaskRunner( 15121cb0ef41Sopenharmony_ci reinterpret_cast<v8::Isolate*>(isolate())); 15131cb0ef41Sopenharmony_ci taskrunner->PostTask(MakeCancelableTask( 15141cb0ef41Sopenharmony_ci isolate(), [this] { InvokeSecondPassPhantomCallbacksFromTask(); })); 15151cb0ef41Sopenharmony_ci } 15161cb0ef41Sopenharmony_ci } 15171cb0ef41Sopenharmony_ci} 15181cb0ef41Sopenharmony_ci 15191cb0ef41Sopenharmony_civoid GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate, 15201cb0ef41Sopenharmony_ci InvocationType type) { 15211cb0ef41Sopenharmony_ci Data::Callback* callback_addr = nullptr; 15221cb0ef41Sopenharmony_ci if (type == kFirstPass) { 15231cb0ef41Sopenharmony_ci callback_addr = &callback_; 15241cb0ef41Sopenharmony_ci } 15251cb0ef41Sopenharmony_ci Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_, 15261cb0ef41Sopenharmony_ci embedder_fields_, callback_addr); 15271cb0ef41Sopenharmony_ci Data::Callback callback = callback_; 15281cb0ef41Sopenharmony_ci callback_ = nullptr; 15291cb0ef41Sopenharmony_ci callback(data); 15301cb0ef41Sopenharmony_ci} 15311cb0ef41Sopenharmony_ci 15321cb0ef41Sopenharmony_cibool GlobalHandles::InRecursiveGC(unsigned gc_processing_counter) { 15331cb0ef41Sopenharmony_ci return gc_processing_counter != post_gc_processing_count_; 15341cb0ef41Sopenharmony_ci} 15351cb0ef41Sopenharmony_ci 15361cb0ef41Sopenharmony_cisize_t GlobalHandles::PostGarbageCollectionProcessing( 15371cb0ef41Sopenharmony_ci GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) { 15381cb0ef41Sopenharmony_ci // Process weak global handle callbacks. This must be done after the 15391cb0ef41Sopenharmony_ci // GC is completely done, because the callbacks may invoke arbitrary 15401cb0ef41Sopenharmony_ci // API functions. 15411cb0ef41Sopenharmony_ci DCHECK_EQ(Heap::NOT_IN_GC, isolate_->heap()->gc_state()); 15421cb0ef41Sopenharmony_ci const unsigned post_processing_count = ++post_gc_processing_count_; 15431cb0ef41Sopenharmony_ci size_t freed_nodes = 0; 15441cb0ef41Sopenharmony_ci bool synchronous_second_pass = 15451cb0ef41Sopenharmony_ci isolate_->heap()->IsTearingDown() || 15461cb0ef41Sopenharmony_ci (gc_callback_flags & 15471cb0ef41Sopenharmony_ci (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage | 15481cb0ef41Sopenharmony_ci kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0; 15491cb0ef41Sopenharmony_ci InvokeOrScheduleSecondPassPhantomCallbacks(synchronous_second_pass); 15501cb0ef41Sopenharmony_ci if (InRecursiveGC(post_processing_count)) return freed_nodes; 15511cb0ef41Sopenharmony_ci 15521cb0ef41Sopenharmony_ci freed_nodes += Heap::IsYoungGenerationCollector(collector) 15531cb0ef41Sopenharmony_ci ? PostScavengeProcessing(post_processing_count) 15541cb0ef41Sopenharmony_ci : PostMarkSweepProcessing(post_processing_count); 15551cb0ef41Sopenharmony_ci if (InRecursiveGC(post_processing_count)) return freed_nodes; 15561cb0ef41Sopenharmony_ci 15571cb0ef41Sopenharmony_ci UpdateListOfYoungNodes(); 15581cb0ef41Sopenharmony_ci return freed_nodes; 15591cb0ef41Sopenharmony_ci} 15601cb0ef41Sopenharmony_ci 15611cb0ef41Sopenharmony_civoid GlobalHandles::IterateStrongRoots(RootVisitor* v) { 15621cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 15631cb0ef41Sopenharmony_ci if (node->IsStrongRetainer()) { 15641cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, node->label(), 15651cb0ef41Sopenharmony_ci node->location()); 15661cb0ef41Sopenharmony_ci } 15671cb0ef41Sopenharmony_ci } 15681cb0ef41Sopenharmony_ci} 15691cb0ef41Sopenharmony_ci 15701cb0ef41Sopenharmony_civoid GlobalHandles::IterateStrongStackRoots(RootVisitor* v) { 15711cb0ef41Sopenharmony_ci on_stack_nodes_->Iterate(v); 15721cb0ef41Sopenharmony_ci} 15731cb0ef41Sopenharmony_ci 15741cb0ef41Sopenharmony_civoid GlobalHandles::IterateWeakRoots(RootVisitor* v) { 15751cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 15761cb0ef41Sopenharmony_ci if (node->IsWeak()) { 15771cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, node->label(), 15781cb0ef41Sopenharmony_ci node->location()); 15791cb0ef41Sopenharmony_ci } 15801cb0ef41Sopenharmony_ci } 15811cb0ef41Sopenharmony_ci for (TracedNode* node : *traced_nodes_) { 15821cb0ef41Sopenharmony_ci if (node->IsInUse()) { 15831cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location()); 15841cb0ef41Sopenharmony_ci } 15851cb0ef41Sopenharmony_ci } 15861cb0ef41Sopenharmony_ci} 15871cb0ef41Sopenharmony_ci 15881cb0ef41Sopenharmony_ciDISABLE_CFI_PERF 15891cb0ef41Sopenharmony_civoid GlobalHandles::IterateAllRoots(RootVisitor* v) { 15901cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 15911cb0ef41Sopenharmony_ci if (node->IsRetainer()) { 15921cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, node->label(), 15931cb0ef41Sopenharmony_ci node->location()); 15941cb0ef41Sopenharmony_ci } 15951cb0ef41Sopenharmony_ci } 15961cb0ef41Sopenharmony_ci for (TracedNode* node : *traced_nodes_) { 15971cb0ef41Sopenharmony_ci if (node->IsRetainer()) { 15981cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location()); 15991cb0ef41Sopenharmony_ci } 16001cb0ef41Sopenharmony_ci } 16011cb0ef41Sopenharmony_ci on_stack_nodes_->Iterate(v); 16021cb0ef41Sopenharmony_ci} 16031cb0ef41Sopenharmony_ci 16041cb0ef41Sopenharmony_ciDISABLE_CFI_PERF 16051cb0ef41Sopenharmony_civoid GlobalHandles::IterateAllYoungRoots(RootVisitor* v) { 16061cb0ef41Sopenharmony_ci for (Node* node : young_nodes_) { 16071cb0ef41Sopenharmony_ci if (node->IsRetainer()) { 16081cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, node->label(), 16091cb0ef41Sopenharmony_ci node->location()); 16101cb0ef41Sopenharmony_ci } 16111cb0ef41Sopenharmony_ci } 16121cb0ef41Sopenharmony_ci for (TracedNode* node : traced_young_nodes_) { 16131cb0ef41Sopenharmony_ci if (node->IsRetainer()) { 16141cb0ef41Sopenharmony_ci v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location()); 16151cb0ef41Sopenharmony_ci } 16161cb0ef41Sopenharmony_ci } 16171cb0ef41Sopenharmony_ci on_stack_nodes_->Iterate(v); 16181cb0ef41Sopenharmony_ci} 16191cb0ef41Sopenharmony_ci 16201cb0ef41Sopenharmony_ciDISABLE_CFI_PERF 16211cb0ef41Sopenharmony_civoid GlobalHandles::ApplyPersistentHandleVisitor( 16221cb0ef41Sopenharmony_ci v8::PersistentHandleVisitor* visitor, GlobalHandles::Node* node) { 16231cb0ef41Sopenharmony_ci v8::Value* value = ToApi<v8::Value>(node->handle()); 16241cb0ef41Sopenharmony_ci visitor->VisitPersistentHandle( 16251cb0ef41Sopenharmony_ci reinterpret_cast<v8::Persistent<v8::Value>*>(&value), 16261cb0ef41Sopenharmony_ci node->wrapper_class_id()); 16271cb0ef41Sopenharmony_ci} 16281cb0ef41Sopenharmony_ci 16291cb0ef41Sopenharmony_ciDISABLE_CFI_PERF 16301cb0ef41Sopenharmony_civoid GlobalHandles::IterateAllRootsWithClassIds( 16311cb0ef41Sopenharmony_ci v8::PersistentHandleVisitor* visitor) { 16321cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 16331cb0ef41Sopenharmony_ci if (node->IsRetainer() && node->has_wrapper_class_id()) { 16341cb0ef41Sopenharmony_ci ApplyPersistentHandleVisitor(visitor, node); 16351cb0ef41Sopenharmony_ci } 16361cb0ef41Sopenharmony_ci } 16371cb0ef41Sopenharmony_ci} 16381cb0ef41Sopenharmony_ci 16391cb0ef41Sopenharmony_ciDISABLE_CFI_PERF 16401cb0ef41Sopenharmony_civoid GlobalHandles::IterateTracedNodes( 16411cb0ef41Sopenharmony_ci v8::EmbedderHeapTracer::TracedGlobalHandleVisitor* visitor) { 16421cb0ef41Sopenharmony_ci for (TracedNode* node : *traced_nodes_) { 16431cb0ef41Sopenharmony_ci if (node->IsInUse()) { 16441cb0ef41Sopenharmony_ci v8::Value* value = ToApi<v8::Value>(node->handle()); 16451cb0ef41Sopenharmony_ci visitor->VisitTracedReference( 16461cb0ef41Sopenharmony_ci *reinterpret_cast<v8::TracedReference<v8::Value>*>(&value)); 16471cb0ef41Sopenharmony_ci } 16481cb0ef41Sopenharmony_ci } 16491cb0ef41Sopenharmony_ci} 16501cb0ef41Sopenharmony_ci 16511cb0ef41Sopenharmony_ciDISABLE_CFI_PERF 16521cb0ef41Sopenharmony_civoid GlobalHandles::IterateAllYoungRootsWithClassIds( 16531cb0ef41Sopenharmony_ci v8::PersistentHandleVisitor* visitor) { 16541cb0ef41Sopenharmony_ci for (Node* node : young_nodes_) { 16551cb0ef41Sopenharmony_ci if (node->IsRetainer() && node->has_wrapper_class_id()) { 16561cb0ef41Sopenharmony_ci ApplyPersistentHandleVisitor(visitor, node); 16571cb0ef41Sopenharmony_ci } 16581cb0ef41Sopenharmony_ci } 16591cb0ef41Sopenharmony_ci} 16601cb0ef41Sopenharmony_ci 16611cb0ef41Sopenharmony_ciDISABLE_CFI_PERF 16621cb0ef41Sopenharmony_civoid GlobalHandles::IterateYoungWeakRootsWithClassIds( 16631cb0ef41Sopenharmony_ci v8::PersistentHandleVisitor* visitor) { 16641cb0ef41Sopenharmony_ci for (Node* node : young_nodes_) { 16651cb0ef41Sopenharmony_ci if (node->has_wrapper_class_id() && node->IsWeak()) { 16661cb0ef41Sopenharmony_ci ApplyPersistentHandleVisitor(visitor, node); 16671cb0ef41Sopenharmony_ci } 16681cb0ef41Sopenharmony_ci } 16691cb0ef41Sopenharmony_ci} 16701cb0ef41Sopenharmony_ci 16711cb0ef41Sopenharmony_civoid GlobalHandles::RecordStats(HeapStats* stats) { 16721cb0ef41Sopenharmony_ci *stats->global_handle_count = 0; 16731cb0ef41Sopenharmony_ci *stats->weak_global_handle_count = 0; 16741cb0ef41Sopenharmony_ci *stats->pending_global_handle_count = 0; 16751cb0ef41Sopenharmony_ci *stats->near_death_global_handle_count = 0; 16761cb0ef41Sopenharmony_ci *stats->free_global_handle_count = 0; 16771cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 16781cb0ef41Sopenharmony_ci *stats->global_handle_count += 1; 16791cb0ef41Sopenharmony_ci if (node->state() == Node::WEAK) { 16801cb0ef41Sopenharmony_ci *stats->weak_global_handle_count += 1; 16811cb0ef41Sopenharmony_ci } else if (node->state() == Node::PENDING) { 16821cb0ef41Sopenharmony_ci *stats->pending_global_handle_count += 1; 16831cb0ef41Sopenharmony_ci } else if (node->state() == Node::NEAR_DEATH) { 16841cb0ef41Sopenharmony_ci *stats->near_death_global_handle_count += 1; 16851cb0ef41Sopenharmony_ci } else if (node->state() == Node::FREE) { 16861cb0ef41Sopenharmony_ci *stats->free_global_handle_count += 1; 16871cb0ef41Sopenharmony_ci } 16881cb0ef41Sopenharmony_ci } 16891cb0ef41Sopenharmony_ci} 16901cb0ef41Sopenharmony_ci 16911cb0ef41Sopenharmony_ci#ifdef DEBUG 16921cb0ef41Sopenharmony_ci 16931cb0ef41Sopenharmony_civoid GlobalHandles::PrintStats() { 16941cb0ef41Sopenharmony_ci int total = 0; 16951cb0ef41Sopenharmony_ci int weak = 0; 16961cb0ef41Sopenharmony_ci int pending = 0; 16971cb0ef41Sopenharmony_ci int near_death = 0; 16981cb0ef41Sopenharmony_ci int destroyed = 0; 16991cb0ef41Sopenharmony_ci 17001cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 17011cb0ef41Sopenharmony_ci total++; 17021cb0ef41Sopenharmony_ci if (node->state() == Node::WEAK) weak++; 17031cb0ef41Sopenharmony_ci if (node->state() == Node::PENDING) pending++; 17041cb0ef41Sopenharmony_ci if (node->state() == Node::NEAR_DEATH) near_death++; 17051cb0ef41Sopenharmony_ci if (node->state() == Node::FREE) destroyed++; 17061cb0ef41Sopenharmony_ci } 17071cb0ef41Sopenharmony_ci 17081cb0ef41Sopenharmony_ci PrintF("Global Handle Statistics:\n"); 17091cb0ef41Sopenharmony_ci PrintF(" allocated memory = %zuB\n", total * sizeof(Node)); 17101cb0ef41Sopenharmony_ci PrintF(" # weak = %d\n", weak); 17111cb0ef41Sopenharmony_ci PrintF(" # pending = %d\n", pending); 17121cb0ef41Sopenharmony_ci PrintF(" # near_death = %d\n", near_death); 17131cb0ef41Sopenharmony_ci PrintF(" # free = %d\n", destroyed); 17141cb0ef41Sopenharmony_ci PrintF(" # total = %d\n", total); 17151cb0ef41Sopenharmony_ci} 17161cb0ef41Sopenharmony_ci 17171cb0ef41Sopenharmony_civoid GlobalHandles::Print() { 17181cb0ef41Sopenharmony_ci PrintF("Global handles:\n"); 17191cb0ef41Sopenharmony_ci for (Node* node : *regular_nodes_) { 17201cb0ef41Sopenharmony_ci PrintF(" handle %p to %p%s\n", node->location().ToVoidPtr(), 17211cb0ef41Sopenharmony_ci reinterpret_cast<void*>(node->object().ptr()), 17221cb0ef41Sopenharmony_ci node->IsWeak() ? " (weak)" : ""); 17231cb0ef41Sopenharmony_ci } 17241cb0ef41Sopenharmony_ci} 17251cb0ef41Sopenharmony_ci 17261cb0ef41Sopenharmony_ci#endif 17271cb0ef41Sopenharmony_ci 17281cb0ef41Sopenharmony_ciEternalHandles::~EternalHandles() { 17291cb0ef41Sopenharmony_ci for (Address* block : blocks_) delete[] block; 17301cb0ef41Sopenharmony_ci} 17311cb0ef41Sopenharmony_ci 17321cb0ef41Sopenharmony_civoid EternalHandles::IterateAllRoots(RootVisitor* visitor) { 17331cb0ef41Sopenharmony_ci int limit = size_; 17341cb0ef41Sopenharmony_ci for (Address* block : blocks_) { 17351cb0ef41Sopenharmony_ci DCHECK_GT(limit, 0); 17361cb0ef41Sopenharmony_ci visitor->VisitRootPointers( 17371cb0ef41Sopenharmony_ci Root::kEternalHandles, nullptr, FullObjectSlot(block), 17381cb0ef41Sopenharmony_ci FullObjectSlot(block + std::min({limit, kSize}))); 17391cb0ef41Sopenharmony_ci limit -= kSize; 17401cb0ef41Sopenharmony_ci } 17411cb0ef41Sopenharmony_ci} 17421cb0ef41Sopenharmony_ci 17431cb0ef41Sopenharmony_civoid EternalHandles::IterateYoungRoots(RootVisitor* visitor) { 17441cb0ef41Sopenharmony_ci for (int index : young_node_indices_) { 17451cb0ef41Sopenharmony_ci visitor->VisitRootPointer(Root::kEternalHandles, nullptr, 17461cb0ef41Sopenharmony_ci FullObjectSlot(GetLocation(index))); 17471cb0ef41Sopenharmony_ci } 17481cb0ef41Sopenharmony_ci} 17491cb0ef41Sopenharmony_ci 17501cb0ef41Sopenharmony_civoid EternalHandles::PostGarbageCollectionProcessing() { 17511cb0ef41Sopenharmony_ci size_t last = 0; 17521cb0ef41Sopenharmony_ci for (int index : young_node_indices_) { 17531cb0ef41Sopenharmony_ci if (ObjectInYoungGeneration(Object(*GetLocation(index)))) { 17541cb0ef41Sopenharmony_ci young_node_indices_[last++] = index; 17551cb0ef41Sopenharmony_ci } 17561cb0ef41Sopenharmony_ci } 17571cb0ef41Sopenharmony_ci DCHECK_LE(last, young_node_indices_.size()); 17581cb0ef41Sopenharmony_ci young_node_indices_.resize(last); 17591cb0ef41Sopenharmony_ci} 17601cb0ef41Sopenharmony_ci 17611cb0ef41Sopenharmony_civoid EternalHandles::Create(Isolate* isolate, Object object, int* index) { 17621cb0ef41Sopenharmony_ci DCHECK_EQ(kInvalidIndex, *index); 17631cb0ef41Sopenharmony_ci if (object == Object()) return; 17641cb0ef41Sopenharmony_ci Object the_hole = ReadOnlyRoots(isolate).the_hole_value(); 17651cb0ef41Sopenharmony_ci DCHECK_NE(the_hole, object); 17661cb0ef41Sopenharmony_ci int block = size_ >> kShift; 17671cb0ef41Sopenharmony_ci int offset = size_ & kMask; 17681cb0ef41Sopenharmony_ci // Need to resize. 17691cb0ef41Sopenharmony_ci if (offset == 0) { 17701cb0ef41Sopenharmony_ci Address* next_block = new Address[kSize]; 17711cb0ef41Sopenharmony_ci MemsetPointer(FullObjectSlot(next_block), the_hole, kSize); 17721cb0ef41Sopenharmony_ci blocks_.push_back(next_block); 17731cb0ef41Sopenharmony_ci } 17741cb0ef41Sopenharmony_ci DCHECK_EQ(the_hole.ptr(), blocks_[block][offset]); 17751cb0ef41Sopenharmony_ci blocks_[block][offset] = object.ptr(); 17761cb0ef41Sopenharmony_ci if (ObjectInYoungGeneration(object)) { 17771cb0ef41Sopenharmony_ci young_node_indices_.push_back(size_); 17781cb0ef41Sopenharmony_ci } 17791cb0ef41Sopenharmony_ci *index = size_++; 17801cb0ef41Sopenharmony_ci} 17811cb0ef41Sopenharmony_ci 17821cb0ef41Sopenharmony_ci} // namespace internal 17831cb0ef41Sopenharmony_ci} // namespace v8 1784