Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:54

0001 //===-- SymbolStringPool.h -- Thread-safe pool for JIT symbols --*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Contains a thread-safe string pool suitable for use with ORC.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
0014 #define LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
0015 
0016 #include "llvm/ADT/DenseMap.h"
0017 #include "llvm/ADT/StringMap.h"
0018 #include <atomic>
0019 #include <mutex>
0020 
0021 namespace llvm {
0022 
0023 class raw_ostream;
0024 
0025 namespace orc {
0026 
0027 class SymbolStringPtrBase;
0028 class SymbolStringPtr;
0029 class NonOwningSymbolStringPtr;
0030 
0031 /// String pool for symbol names used by the JIT.
0032 class SymbolStringPool {
0033   friend class SymbolStringPoolTest;
0034   friend class SymbolStringPtrBase;
0035   friend class SymbolStringPoolEntryUnsafe;
0036 
0037   // Implemented in DebugUtils.h.
0038   friend raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPool &SSP);
0039 
0040 public:
0041   /// Destroy a SymbolStringPool.
0042   ~SymbolStringPool();
0043 
0044   /// Create a symbol string pointer from the given string.
0045   SymbolStringPtr intern(StringRef S);
0046 
0047   /// Remove from the pool any entries that are no longer referenced.
0048   void clearDeadEntries();
0049 
0050   /// Returns true if the pool is empty.
0051   bool empty() const;
0052 
0053 private:
0054   size_t getRefCount(const SymbolStringPtrBase &S) const;
0055 
0056   using RefCountType = std::atomic<size_t>;
0057   using PoolMap = StringMap<RefCountType>;
0058   using PoolMapEntry = StringMapEntry<RefCountType>;
0059   mutable std::mutex PoolMutex;
0060   PoolMap Pool;
0061 };
0062 
0063 /// Base class for both owning and non-owning symbol-string ptrs.
0064 ///
0065 /// All symbol-string ptrs are convertible to bool, dereferenceable and
0066 /// comparable.
0067 ///
0068 /// SymbolStringPtrBases are default-constructible and constructible
0069 /// from nullptr to enable comparison with these values.
0070 class SymbolStringPtrBase {
0071   friend class SymbolStringPool;
0072   friend struct DenseMapInfo<SymbolStringPtr>;
0073   friend struct DenseMapInfo<NonOwningSymbolStringPtr>;
0074 
0075 public:
0076   SymbolStringPtrBase() = default;
0077   SymbolStringPtrBase(std::nullptr_t) {}
0078 
0079   explicit operator bool() const { return S; }
0080 
0081   StringRef operator*() const { return S->first(); }
0082 
0083   friend bool operator==(SymbolStringPtrBase LHS, SymbolStringPtrBase RHS) {
0084     return LHS.S == RHS.S;
0085   }
0086 
0087   friend bool operator!=(SymbolStringPtrBase LHS, SymbolStringPtrBase RHS) {
0088     return !(LHS == RHS);
0089   }
0090 
0091   friend bool operator<(SymbolStringPtrBase LHS, SymbolStringPtrBase RHS) {
0092     return LHS.S < RHS.S;
0093   }
0094 
0095   friend raw_ostream &operator<<(raw_ostream &OS,
0096                                  const SymbolStringPtrBase &Sym);
0097 
0098 #ifndef NDEBUG
0099   // Returns true if the pool entry's ref count is above zero (or if the entry
0100   // is an empty or tombstone value). Useful for debugging and testing -- this
0101   // method can be used to identify SymbolStringPtrs and
0102   // NonOwningSymbolStringPtrs that are pointing to abandoned pool entries.
0103   bool poolEntryIsAlive() const {
0104     return isRealPoolEntry(S) ? S->getValue() != 0 : true;
0105   }
0106 #endif
0107 
0108 protected:
0109   using PoolEntry = SymbolStringPool::PoolMapEntry;
0110   using PoolEntryPtr = PoolEntry *;
0111 
0112   SymbolStringPtrBase(PoolEntryPtr S) : S(S) {}
0113 
0114   constexpr static uintptr_t EmptyBitPattern =
0115       std::numeric_limits<uintptr_t>::max()
0116       << PointerLikeTypeTraits<PoolEntryPtr>::NumLowBitsAvailable;
0117 
0118   constexpr static uintptr_t TombstoneBitPattern =
0119       (std::numeric_limits<uintptr_t>::max() - 1)
0120       << PointerLikeTypeTraits<PoolEntryPtr>::NumLowBitsAvailable;
0121 
0122   constexpr static uintptr_t InvalidPtrMask =
0123       (std::numeric_limits<uintptr_t>::max() - 3)
0124       << PointerLikeTypeTraits<PoolEntryPtr>::NumLowBitsAvailable;
0125 
0126   // Returns false for null, empty, and tombstone values, true otherwise.
0127   static bool isRealPoolEntry(PoolEntryPtr P) {
0128     return ((reinterpret_cast<uintptr_t>(P) - 1) & InvalidPtrMask) !=
0129            InvalidPtrMask;
0130   }
0131 
0132   size_t getRefCount() const {
0133     return isRealPoolEntry(S) ? size_t(S->getValue()) : size_t(0);
0134   }
0135 
0136   PoolEntryPtr S = nullptr;
0137 };
0138 
0139 /// Pointer to a pooled string representing a symbol name.
0140 class SymbolStringPtr : public SymbolStringPtrBase {
0141   friend class SymbolStringPool;
0142   friend class SymbolStringPoolEntryUnsafe;
0143   friend struct DenseMapInfo<SymbolStringPtr>;
0144 
0145 public:
0146   SymbolStringPtr() = default;
0147   SymbolStringPtr(std::nullptr_t) {}
0148   SymbolStringPtr(const SymbolStringPtr &Other) : SymbolStringPtrBase(Other.S) {
0149     incRef();
0150   }
0151 
0152   explicit SymbolStringPtr(NonOwningSymbolStringPtr Other);
0153 
0154   SymbolStringPtr& operator=(const SymbolStringPtr &Other) {
0155     decRef();
0156     S = Other.S;
0157     incRef();
0158     return *this;
0159   }
0160 
0161   SymbolStringPtr(SymbolStringPtr &&Other) { std::swap(S, Other.S); }
0162 
0163   SymbolStringPtr& operator=(SymbolStringPtr &&Other) {
0164     decRef();
0165     S = nullptr;
0166     std::swap(S, Other.S);
0167     return *this;
0168   }
0169 
0170   ~SymbolStringPtr() { decRef(); }
0171 
0172 private:
0173   SymbolStringPtr(PoolEntryPtr S) : SymbolStringPtrBase(S) { incRef(); }
0174 
0175   void incRef() {
0176     if (isRealPoolEntry(S))
0177       ++S->getValue();
0178   }
0179 
0180   void decRef() {
0181     if (isRealPoolEntry(S)) {
0182       assert(S->getValue() && "Releasing SymbolStringPtr with zero ref count");
0183       --S->getValue();
0184     }
0185   }
0186 
0187   static SymbolStringPtr getEmptyVal() {
0188     return SymbolStringPtr(reinterpret_cast<PoolEntryPtr>(EmptyBitPattern));
0189   }
0190 
0191   static SymbolStringPtr getTombstoneVal() {
0192     return SymbolStringPtr(reinterpret_cast<PoolEntryPtr>(TombstoneBitPattern));
0193   }
0194 };
0195 
0196 /// Provides unsafe access to ownership operations on SymbolStringPtr.
0197 /// This class can be used to manage SymbolStringPtr instances from C.
0198 class SymbolStringPoolEntryUnsafe {
0199 public:
0200   using PoolEntry = SymbolStringPool::PoolMapEntry;
0201 
0202   SymbolStringPoolEntryUnsafe(PoolEntry *E) : E(E) {}
0203 
0204   /// Create an unsafe pool entry ref without changing the ref-count.
0205   static SymbolStringPoolEntryUnsafe from(const SymbolStringPtr &S) {
0206     return S.S;
0207   }
0208 
0209   /// Consumes the given SymbolStringPtr without releasing the pool entry.
0210   static SymbolStringPoolEntryUnsafe take(SymbolStringPtr &&S) {
0211     PoolEntry *E = nullptr;
0212     std::swap(E, S.S);
0213     return E;
0214   }
0215 
0216   PoolEntry *rawPtr() { return E; }
0217 
0218   /// Creates a SymbolStringPtr for this entry, with the SymbolStringPtr
0219   /// retaining the entry as usual.
0220   SymbolStringPtr copyToSymbolStringPtr() { return SymbolStringPtr(E); }
0221 
0222   /// Creates a SymbolStringPtr for this entry *without* performing a retain
0223   /// operation during construction.
0224   SymbolStringPtr moveToSymbolStringPtr() {
0225     SymbolStringPtr S;
0226     std::swap(S.S, E);
0227     return S;
0228   }
0229 
0230   void retain() { ++E->getValue(); }
0231   void release() { --E->getValue(); }
0232 
0233 private:
0234   PoolEntry *E = nullptr;
0235 };
0236 
0237 /// Non-owning SymbolStringPool entry pointer. Instances are comparable with
0238 /// SymbolStringPtr instances and guaranteed to have the same hash, but do not
0239 /// affect the ref-count of the pooled string (and are therefore cheaper to
0240 /// copy).
0241 ///
0242 /// NonOwningSymbolStringPtrs are silently invalidated if the pool entry's
0243 /// ref-count drops to zero, so they should only be used in contexts where a
0244 /// corresponding SymbolStringPtr is known to exist (which will guarantee that
0245 /// the ref-count stays above zero). E.g. in a graph where nodes are
0246 /// represented by SymbolStringPtrs the edges can be represented by pairs of
0247 /// NonOwningSymbolStringPtrs and this will make the introduction of deletion
0248 /// of edges cheaper.
0249 class NonOwningSymbolStringPtr : public SymbolStringPtrBase {
0250   friend struct DenseMapInfo<orc::NonOwningSymbolStringPtr>;
0251 
0252 public:
0253   NonOwningSymbolStringPtr() = default;
0254   explicit NonOwningSymbolStringPtr(const SymbolStringPtr &S)
0255       : SymbolStringPtrBase(S) {}
0256 
0257   using SymbolStringPtrBase::operator=;
0258 
0259 private:
0260   NonOwningSymbolStringPtr(PoolEntryPtr S) : SymbolStringPtrBase(S) {}
0261 
0262   static NonOwningSymbolStringPtr getEmptyVal() {
0263     return NonOwningSymbolStringPtr(
0264         reinterpret_cast<PoolEntryPtr>(EmptyBitPattern));
0265   }
0266 
0267   static NonOwningSymbolStringPtr getTombstoneVal() {
0268     return NonOwningSymbolStringPtr(
0269         reinterpret_cast<PoolEntryPtr>(TombstoneBitPattern));
0270   }
0271 };
0272 
0273 inline SymbolStringPtr::SymbolStringPtr(NonOwningSymbolStringPtr Other)
0274     : SymbolStringPtrBase(Other) {
0275   assert(poolEntryIsAlive() &&
0276          "SymbolStringPtr constructed from invalid non-owning pointer.");
0277 
0278   if (isRealPoolEntry(S))
0279     ++S->getValue();
0280 }
0281 
0282 inline SymbolStringPool::~SymbolStringPool() {
0283 #ifndef NDEBUG
0284   clearDeadEntries();
0285   assert(Pool.empty() && "Dangling references at pool destruction time");
0286 #endif // NDEBUG
0287 }
0288 
0289 inline SymbolStringPtr SymbolStringPool::intern(StringRef S) {
0290   std::lock_guard<std::mutex> Lock(PoolMutex);
0291   PoolMap::iterator I;
0292   bool Added;
0293   std::tie(I, Added) = Pool.try_emplace(S, 0);
0294   return SymbolStringPtr(&*I);
0295 }
0296 
0297 inline void SymbolStringPool::clearDeadEntries() {
0298   std::lock_guard<std::mutex> Lock(PoolMutex);
0299   for (auto I = Pool.begin(), E = Pool.end(); I != E;) {
0300     auto Tmp = I++;
0301     if (Tmp->second == 0)
0302       Pool.erase(Tmp);
0303   }
0304 }
0305 
0306 inline bool SymbolStringPool::empty() const {
0307   std::lock_guard<std::mutex> Lock(PoolMutex);
0308   return Pool.empty();
0309 }
0310 
0311 inline size_t
0312 SymbolStringPool::getRefCount(const SymbolStringPtrBase &S) const {
0313   return S.getRefCount();
0314 }
0315 
0316 } // end namespace orc
0317 
0318 template <>
0319 struct DenseMapInfo<orc::SymbolStringPtr> {
0320 
0321   static orc::SymbolStringPtr getEmptyKey() {
0322     return orc::SymbolStringPtr::getEmptyVal();
0323   }
0324 
0325   static orc::SymbolStringPtr getTombstoneKey() {
0326     return orc::SymbolStringPtr::getTombstoneVal();
0327   }
0328 
0329   static unsigned getHashValue(const orc::SymbolStringPtrBase &V) {
0330     return DenseMapInfo<orc::SymbolStringPtr::PoolEntryPtr>::getHashValue(V.S);
0331   }
0332 
0333   static bool isEqual(const orc::SymbolStringPtrBase &LHS,
0334                       const orc::SymbolStringPtrBase &RHS) {
0335     return LHS.S == RHS.S;
0336   }
0337 };
0338 
0339 template <> struct DenseMapInfo<orc::NonOwningSymbolStringPtr> {
0340 
0341   static orc::NonOwningSymbolStringPtr getEmptyKey() {
0342     return orc::NonOwningSymbolStringPtr::getEmptyVal();
0343   }
0344 
0345   static orc::NonOwningSymbolStringPtr getTombstoneKey() {
0346     return orc::NonOwningSymbolStringPtr::getTombstoneVal();
0347   }
0348 
0349   static unsigned getHashValue(const orc::SymbolStringPtrBase &V) {
0350     return DenseMapInfo<
0351         orc::NonOwningSymbolStringPtr::PoolEntryPtr>::getHashValue(V.S);
0352   }
0353 
0354   static bool isEqual(const orc::SymbolStringPtrBase &LHS,
0355                       const orc::SymbolStringPtrBase &RHS) {
0356     return LHS.S == RHS.S;
0357   }
0358 };
0359 
0360 } // end namespace llvm
0361 
0362 #endif // LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H