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