1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ 6 #define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ 7 8 #include <array> 9 #include <memory> 10 #include <vector> 11 12 #include "cppgc/internal/logging.h" 13 #include "cppgc/trace-trait.h" 14 #include "v8config.h" // NOLINT(build/include_directory) 15 16 namespace cppgc { 17 18 class Visitor; 19 20 namespace internal { 21 22 // PersistentNode represents a variant of two states: 23 // 1) traceable node with a back pointer to the Persistent object; 24 // 2) freelist entry. 25 class PersistentNode final { 26 public: 27 PersistentNode() = default; 28 29 PersistentNode(const PersistentNode&) = delete; 30 PersistentNode& operator=(const PersistentNode&) = delete; 31 InitializeAsUsedNode(void * owner,TraceCallback trace)32 void InitializeAsUsedNode(void* owner, TraceCallback trace) { 33 owner_ = owner; 34 trace_ = trace; 35 } 36 InitializeAsFreeNode(PersistentNode * next)37 void InitializeAsFreeNode(PersistentNode* next) { 38 next_ = next; 39 trace_ = nullptr; 40 } 41 UpdateOwner(void * owner)42 void UpdateOwner(void* owner) { 43 CPPGC_DCHECK(IsUsed()); 44 owner_ = owner; 45 } 46 FreeListNext()47 PersistentNode* FreeListNext() const { 48 CPPGC_DCHECK(!IsUsed()); 49 return next_; 50 } 51 Trace(Visitor * visitor)52 void Trace(Visitor* visitor) const { 53 CPPGC_DCHECK(IsUsed()); 54 trace_(visitor, owner_); 55 } 56 IsUsed()57 bool IsUsed() const { return trace_; } 58 owner()59 void* owner() const { 60 CPPGC_DCHECK(IsUsed()); 61 return owner_; 62 } 63 64 private: 65 // PersistentNode acts as a designated union: 66 // If trace_ != nullptr, owner_ points to the corresponding Persistent handle. 67 // Otherwise, next_ points to the next freed PersistentNode. 68 union { 69 void* owner_ = nullptr; 70 PersistentNode* next_; 71 }; 72 TraceCallback trace_ = nullptr; 73 }; 74 75 class V8_EXPORT PersistentRegion final { 76 using PersistentNodeSlots = std::array<PersistentNode, 256u>; 77 78 public: 79 PersistentRegion() = default; 80 // Clears Persistent fields to avoid stale pointers after heap teardown. 81 ~PersistentRegion(); 82 83 PersistentRegion(const PersistentRegion&) = delete; 84 PersistentRegion& operator=(const PersistentRegion&) = delete; 85 AllocateNode(void * owner,TraceCallback trace)86 PersistentNode* AllocateNode(void* owner, TraceCallback trace) { 87 if (!free_list_head_) { 88 EnsureNodeSlots(); 89 } 90 PersistentNode* node = free_list_head_; 91 free_list_head_ = free_list_head_->FreeListNext(); 92 node->InitializeAsUsedNode(owner, trace); 93 return node; 94 } 95 FreeNode(PersistentNode * node)96 void FreeNode(PersistentNode* node) { 97 node->InitializeAsFreeNode(free_list_head_); 98 free_list_head_ = node; 99 } 100 101 void Trace(Visitor*); 102 103 size_t NodesInUse() const; 104 105 private: 106 void EnsureNodeSlots(); 107 108 std::vector<std::unique_ptr<PersistentNodeSlots>> nodes_; 109 PersistentNode* free_list_head_ = nullptr; 110 }; 111 112 // CrossThreadPersistent uses PersistentRegion but protects it using this lock 113 // when needed. 114 class V8_EXPORT PersistentRegionLock final { 115 public: 116 PersistentRegionLock(); 117 ~PersistentRegionLock(); 118 }; 119 120 } // namespace internal 121 122 } // namespace cppgc 123 124 #endif // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ 125