File indexing completed on 2026-08-25 09:12:01
0001
0002
0003
0004
0005 #ifndef INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
0006 #define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
0007
0008 #include <array>
0009 #include <memory>
0010 #include <vector>
0011
0012 #include "cppgc/internal/logging.h"
0013 #include "cppgc/trace-trait.h"
0014 #include "v8config.h" // NOLINT(build/include_directory)
0015
0016 namespace cppgc {
0017 namespace internal {
0018
0019 class CrossThreadPersistentRegion;
0020 class FatalOutOfMemoryHandler;
0021 class HeapBase;
0022 class RootVisitor;
0023
0024
0025
0026
0027 class PersistentNode final {
0028 public:
0029 PersistentNode() = default;
0030
0031 PersistentNode(const PersistentNode&) = delete;
0032 PersistentNode& operator=(const PersistentNode&) = delete;
0033
0034 void InitializeAsUsedNode(void* owner, TraceRootCallback trace) {
0035 CPPGC_DCHECK(trace);
0036 owner_ = owner;
0037 trace_ = trace;
0038 }
0039
0040 void InitializeAsFreeNode(PersistentNode* next) {
0041 next_ = next;
0042 trace_ = nullptr;
0043 }
0044
0045 void UpdateOwner(void* owner) {
0046 CPPGC_DCHECK(IsUsed());
0047 owner_ = owner;
0048 }
0049
0050 PersistentNode* FreeListNext() const {
0051 CPPGC_DCHECK(!IsUsed());
0052 return next_;
0053 }
0054
0055 void Trace(RootVisitor& root_visitor) const {
0056 CPPGC_DCHECK(IsUsed());
0057 trace_(root_visitor, owner_);
0058 }
0059
0060 bool IsUsed() const { return trace_; }
0061
0062 void* owner() const {
0063 CPPGC_DCHECK(IsUsed());
0064 return owner_;
0065 }
0066
0067 private:
0068
0069
0070
0071 union {
0072 void* owner_ = nullptr;
0073 PersistentNode* next_;
0074 };
0075 TraceRootCallback trace_ = nullptr;
0076 };
0077
0078 class V8_EXPORT PersistentRegionBase {
0079 using PersistentNodeSlots = std::array<PersistentNode, 256u>;
0080
0081 public:
0082
0083 ~PersistentRegionBase();
0084
0085 PersistentRegionBase(const PersistentRegionBase&) = delete;
0086 PersistentRegionBase& operator=(const PersistentRegionBase&) = delete;
0087
0088 void Iterate(RootVisitor&);
0089
0090 size_t NodesInUse() const;
0091
0092 void ClearAllUsedNodes();
0093
0094 protected:
0095 explicit PersistentRegionBase(const FatalOutOfMemoryHandler& oom_handler);
0096
0097 PersistentNode* TryAllocateNodeFromFreeList(void* owner,
0098 TraceRootCallback trace) {
0099 PersistentNode* node = nullptr;
0100 if (V8_LIKELY(free_list_head_)) {
0101 node = free_list_head_;
0102 free_list_head_ = free_list_head_->FreeListNext();
0103 CPPGC_DCHECK(!node->IsUsed());
0104 node->InitializeAsUsedNode(owner, trace);
0105 nodes_in_use_++;
0106 }
0107 return node;
0108 }
0109
0110 void FreeNode(PersistentNode* node) {
0111 CPPGC_DCHECK(node);
0112 CPPGC_DCHECK(node->IsUsed());
0113 node->InitializeAsFreeNode(free_list_head_);
0114 free_list_head_ = node;
0115 CPPGC_DCHECK(nodes_in_use_ > 0);
0116 nodes_in_use_--;
0117 }
0118
0119 PersistentNode* RefillFreeListAndAllocateNode(void* owner,
0120 TraceRootCallback trace);
0121
0122 private:
0123 template <typename PersistentBaseClass>
0124 void ClearAllUsedNodes();
0125
0126 void RefillFreeList();
0127
0128 std::vector<std::unique_ptr<PersistentNodeSlots>> nodes_;
0129 PersistentNode* free_list_head_ = nullptr;
0130 size_t nodes_in_use_ = 0;
0131 const FatalOutOfMemoryHandler& oom_handler_;
0132
0133 friend class CrossThreadPersistentRegion;
0134 };
0135
0136
0137
0138 class V8_EXPORT PersistentRegion final : public PersistentRegionBase {
0139 public:
0140 V8_INLINE PersistentRegion(const HeapBase& heap,
0141 const FatalOutOfMemoryHandler& oom_handler)
0142 : PersistentRegionBase(oom_handler), heap_(heap) {
0143 CPPGC_DCHECK(IsCreationThread());
0144 }
0145
0146 ~PersistentRegion() = default;
0147
0148 PersistentRegion(const PersistentRegion&) = delete;
0149 PersistentRegion& operator=(const PersistentRegion&) = delete;
0150
0151 V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) {
0152 CPPGC_DCHECK(IsCreationThread());
0153 auto* node = TryAllocateNodeFromFreeList(owner, trace);
0154 if (V8_LIKELY(node)) return node;
0155
0156
0157 CPPGC_CHECK(IsCreationThread());
0158 return RefillFreeListAndAllocateNode(owner, trace);
0159 }
0160
0161 V8_INLINE void FreeNode(PersistentNode* node) {
0162 CPPGC_DCHECK(IsCreationThread());
0163 PersistentRegionBase::FreeNode(node);
0164 }
0165
0166 private:
0167 bool IsCreationThread();
0168
0169 const HeapBase& heap_;
0170 };
0171
0172
0173
0174 class V8_EXPORT PersistentRegionLock final {
0175 public:
0176 PersistentRegionLock();
0177 ~PersistentRegionLock();
0178
0179 static void AssertLocked();
0180 };
0181
0182
0183
0184 class V8_EXPORT CrossThreadPersistentRegion final
0185 : protected PersistentRegionBase {
0186 public:
0187 explicit CrossThreadPersistentRegion(const FatalOutOfMemoryHandler&);
0188
0189 ~CrossThreadPersistentRegion();
0190
0191 CrossThreadPersistentRegion(const CrossThreadPersistentRegion&) = delete;
0192 CrossThreadPersistentRegion& operator=(const CrossThreadPersistentRegion&) =
0193 delete;
0194
0195 V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) {
0196 PersistentRegionLock::AssertLocked();
0197 auto* node = TryAllocateNodeFromFreeList(owner, trace);
0198 if (V8_LIKELY(node)) return node;
0199
0200 return RefillFreeListAndAllocateNode(owner, trace);
0201 }
0202
0203 V8_INLINE void FreeNode(PersistentNode* node) {
0204 PersistentRegionLock::AssertLocked();
0205 PersistentRegionBase::FreeNode(node);
0206 }
0207
0208 void Iterate(RootVisitor&);
0209
0210 size_t NodesInUse() const;
0211
0212 void ClearAllUsedNodes();
0213 };
0214
0215 }
0216
0217 }
0218
0219 #endif