//===- SymbolStringPool.h - Multi-threaded pool for JIT symbols -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Contains a multi-threaded string pool suitable for use with ORC. // //===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H #define LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include <atomic> #include <mutex> namespace llvm { namespace orc { class SymbolStringPtr; /// String pool for symbol names used by the JIT. class SymbolStringPool { friend class SymbolStringPtr; public: /// Destroy a SymbolStringPool. ~SymbolStringPool(); /// Create a symbol string pointer from the given string. SymbolStringPtr intern(StringRef S); /// Remove from the pool any entries that are no longer referenced. void clearDeadEntries(); /// Returns true if the pool is empty. bool empty() const; private: using RefCountType = std::atomic<size_t>; using PoolMap = StringMap<RefCountType>; using PoolMapEntry = StringMapEntry<RefCountType>; mutable std::mutex PoolMutex; PoolMap Pool; }; /// Pointer to a pooled string representing a symbol name. class SymbolStringPtr { friend class SymbolStringPool; friend struct DenseMapInfo<SymbolStringPtr>; friend bool operator==(const SymbolStringPtr &LHS, const SymbolStringPtr &RHS); friend bool operator<(const SymbolStringPtr &LHS, const SymbolStringPtr &RHS); static SymbolStringPool::PoolMapEntry Tombstone; public: SymbolStringPtr() = default; SymbolStringPtr(const SymbolStringPtr &Other) : S(Other.S) { if (S) ++S->getValue(); } SymbolStringPtr& operator=(const SymbolStringPtr &Other) { if (S) --S->getValue(); S = Other.S; if (S) ++S->getValue(); return *this; } SymbolStringPtr(SymbolStringPtr &&Other) : S(nullptr) { std::swap(S, Other.S); } SymbolStringPtr& operator=(SymbolStringPtr &&Other) { if (S) --S->getValue(); S = nullptr; std::swap(S, Other.S); return *this; } ~SymbolStringPtr() { if (S) --S->getValue(); } StringRef operator*() const { return S->first(); } private: SymbolStringPtr(SymbolStringPool::PoolMapEntry *S) : S(S) { if (S) ++S->getValue(); } SymbolStringPool::PoolMapEntry *S = nullptr; }; inline bool operator==(const SymbolStringPtr &LHS, const SymbolStringPtr &RHS) { return LHS.S == RHS.S; } inline bool operator!=(const SymbolStringPtr &LHS, const SymbolStringPtr &RHS) { return !(LHS == RHS); } inline bool operator<(const SymbolStringPtr &LHS, const SymbolStringPtr &RHS) { return LHS.S < RHS.S; } inline SymbolStringPool::~SymbolStringPool() { #ifndef NDEBUG clearDeadEntries(); assert(Pool.empty() && "Dangling references at pool destruction time"); #endif // NDEBUG } inline SymbolStringPtr SymbolStringPool::intern(StringRef S) { std::lock_guard<std::mutex> Lock(PoolMutex); PoolMap::iterator I; bool Added; std::tie(I, Added) = Pool.try_emplace(S, 0); return SymbolStringPtr(&*I); } inline void SymbolStringPool::clearDeadEntries() { std::lock_guard<std::mutex> Lock(PoolMutex); for (auto I = Pool.begin(), E = Pool.end(); I != E;) { auto Tmp = I++; if (Tmp->second == 0) Pool.erase(Tmp); } } inline bool SymbolStringPool::empty() const { std::lock_guard<std::mutex> Lock(PoolMutex); return Pool.empty(); } } // end namespace orc template <> struct DenseMapInfo<orc::SymbolStringPtr> { static orc::SymbolStringPtr getEmptyKey() { return orc::SymbolStringPtr(); } static orc::SymbolStringPtr getTombstoneKey() { return orc::SymbolStringPtr(&orc::SymbolStringPtr::Tombstone); } static unsigned getHashValue(orc::SymbolStringPtr V) { uintptr_t IV = reinterpret_cast<uintptr_t>(V.S); return unsigned(IV) ^ unsigned(IV >> 9); } static bool isEqual(const orc::SymbolStringPtr &LHS, const orc::SymbolStringPtr &RHS) { return LHS.S == RHS.S; } }; } // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H