Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-25 09:12:01

0001 // Copyright 2020 the V8 project authors. All rights reserved.
0002 // Use of this source code is governed by a BSD-style license that can be
0003 // found in the LICENSE file.
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 // PersistentNode represents a variant of two states:
0025 // 1) traceable node with a back pointer to the Persistent object;
0026 // 2) freelist entry.
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   // PersistentNode acts as a designated union:
0069   // If trace_ != nullptr, owner_ points to the corresponding Persistent handle.
0070   // Otherwise, next_ points to the next freed PersistentNode.
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   // Clears Persistent fields to avoid stale pointers after heap teardown.
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 // Variant of PersistentRegionBase that checks whether the allocation and
0137 // freeing happens only on the thread that created the heap.
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   // Clears Persistent fields to avoid stale pointers after heap teardown.
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     // Slow path allocation allows for checking thread correspondence.
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 // CrossThreadPersistent uses PersistentRegionBase but protects it using this
0173 // lock when needed.
0174 class V8_EXPORT PersistentRegionLock final {
0175  public:
0176   PersistentRegionLock();
0177   ~PersistentRegionLock();
0178 
0179   static void AssertLocked();
0180 };
0181 
0182 // Variant of PersistentRegionBase that checks whether the PersistentRegionLock
0183 // is locked.
0184 class V8_EXPORT CrossThreadPersistentRegion final
0185     : protected PersistentRegionBase {
0186  public:
0187   explicit CrossThreadPersistentRegion(const FatalOutOfMemoryHandler&);
0188   // Clears Persistent fields to avoid stale pointers after heap teardown.
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 }  // namespace internal
0216 
0217 }  // namespace cppgc
0218 
0219 #endif  // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_