Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-23 10:08:50

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 RootVisitor;
0022 
0023 // PersistentNode represents a variant of two states:
0024 // 1) traceable node with a back pointer to the Persistent object;
0025 // 2) freelist entry.
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   // PersistentNode acts as a designated union:
0068   // If trace_ != nullptr, owner_ points to the corresponding Persistent handle.
0069   // Otherwise, next_ points to the next freed PersistentNode.
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   // Clears Persistent fields to avoid stale pointers after heap teardown.
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 // Variant of PersistentRegionBase that checks whether the allocation and
0136 // freeing happens only on the thread that created the region.
0137 class V8_EXPORT PersistentRegion final : public PersistentRegionBase {
0138  public:
0139   explicit PersistentRegion(const FatalOutOfMemoryHandler&);
0140   // Clears Persistent fields to avoid stale pointers after heap teardown.
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     // Slow path allocation allows for checking thread correspondence.
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 // CrossThreadPersistent uses PersistentRegionBase but protects it using this
0168 // lock when needed.
0169 class V8_EXPORT PersistentRegionLock final {
0170  public:
0171   PersistentRegionLock();
0172   ~PersistentRegionLock();
0173 
0174   static void AssertLocked();
0175 };
0176 
0177 // Variant of PersistentRegionBase that checks whether the PersistentRegionLock
0178 // is locked.
0179 class V8_EXPORT CrossThreadPersistentRegion final
0180     : protected PersistentRegionBase {
0181  public:
0182   explicit CrossThreadPersistentRegion(const FatalOutOfMemoryHandler&);
0183   // Clears Persistent fields to avoid stale pointers after heap teardown.
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 }  // namespace internal
0211 
0212 }  // namespace cppgc
0213 
0214 #endif  // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_