SymbolStringPool.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- SymbolStringPool.h -- Thread-safe pool for JIT symbols --*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // Contains a thread-safe string pool suitable for use with ORC.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
  18. #define LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
  19. #include "llvm/ADT/DenseMap.h"
  20. #include "llvm/ADT/StringMap.h"
  21. #include <atomic>
  22. #include <mutex>
  23. namespace llvm {
  24. class raw_ostream;
  25. namespace orc {
  26. class SymbolStringPtr;
  27. /// String pool for symbol names used by the JIT.
  28. class SymbolStringPool {
  29. friend class SymbolStringPtr;
  30. // Implemented in DebugUtils.h.
  31. friend raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPool &SSP);
  32. public:
  33. /// Destroy a SymbolStringPool.
  34. ~SymbolStringPool();
  35. /// Create a symbol string pointer from the given string.
  36. SymbolStringPtr intern(StringRef S);
  37. /// Remove from the pool any entries that are no longer referenced.
  38. void clearDeadEntries();
  39. /// Returns true if the pool is empty.
  40. bool empty() const;
  41. private:
  42. using RefCountType = std::atomic<size_t>;
  43. using PoolMap = StringMap<RefCountType>;
  44. using PoolMapEntry = StringMapEntry<RefCountType>;
  45. mutable std::mutex PoolMutex;
  46. PoolMap Pool;
  47. };
  48. /// Pointer to a pooled string representing a symbol name.
  49. class SymbolStringPtr {
  50. friend class OrcV2CAPIHelper;
  51. friend class SymbolStringPool;
  52. friend struct DenseMapInfo<SymbolStringPtr>;
  53. public:
  54. SymbolStringPtr() = default;
  55. SymbolStringPtr(std::nullptr_t) {}
  56. SymbolStringPtr(const SymbolStringPtr &Other)
  57. : S(Other.S) {
  58. if (isRealPoolEntry(S))
  59. ++S->getValue();
  60. }
  61. SymbolStringPtr& operator=(const SymbolStringPtr &Other) {
  62. if (isRealPoolEntry(S)) {
  63. assert(S->getValue() && "Releasing SymbolStringPtr with zero ref count");
  64. --S->getValue();
  65. }
  66. S = Other.S;
  67. if (isRealPoolEntry(S))
  68. ++S->getValue();
  69. return *this;
  70. }
  71. SymbolStringPtr(SymbolStringPtr &&Other) : S(nullptr) {
  72. std::swap(S, Other.S);
  73. }
  74. SymbolStringPtr& operator=(SymbolStringPtr &&Other) {
  75. if (isRealPoolEntry(S)) {
  76. assert(S->getValue() && "Releasing SymbolStringPtr with zero ref count");
  77. --S->getValue();
  78. }
  79. S = nullptr;
  80. std::swap(S, Other.S);
  81. return *this;
  82. }
  83. ~SymbolStringPtr() {
  84. if (isRealPoolEntry(S)) {
  85. assert(S->getValue() && "Releasing SymbolStringPtr with zero ref count");
  86. --S->getValue();
  87. }
  88. }
  89. explicit operator bool() const { return S; }
  90. StringRef operator*() const { return S->first(); }
  91. friend bool operator==(const SymbolStringPtr &LHS,
  92. const SymbolStringPtr &RHS) {
  93. return LHS.S == RHS.S;
  94. }
  95. friend bool operator!=(const SymbolStringPtr &LHS,
  96. const SymbolStringPtr &RHS) {
  97. return !(LHS == RHS);
  98. }
  99. friend bool operator<(const SymbolStringPtr &LHS,
  100. const SymbolStringPtr &RHS) {
  101. return LHS.S < RHS.S;
  102. }
  103. private:
  104. using PoolEntry = SymbolStringPool::PoolMapEntry;
  105. using PoolEntryPtr = PoolEntry *;
  106. SymbolStringPtr(SymbolStringPool::PoolMapEntry *S)
  107. : S(S) {
  108. if (isRealPoolEntry(S))
  109. ++S->getValue();
  110. }
  111. // Returns false for null, empty, and tombstone values, true otherwise.
  112. bool isRealPoolEntry(PoolEntryPtr P) {
  113. return ((reinterpret_cast<uintptr_t>(P) - 1) & InvalidPtrMask) !=
  114. InvalidPtrMask;
  115. }
  116. static SymbolStringPtr getEmptyVal() {
  117. return SymbolStringPtr(reinterpret_cast<PoolEntryPtr>(EmptyBitPattern));
  118. }
  119. static SymbolStringPtr getTombstoneVal() {
  120. return SymbolStringPtr(reinterpret_cast<PoolEntryPtr>(TombstoneBitPattern));
  121. }
  122. constexpr static uintptr_t EmptyBitPattern =
  123. std::numeric_limits<uintptr_t>::max()
  124. << PointerLikeTypeTraits<PoolEntryPtr>::NumLowBitsAvailable;
  125. constexpr static uintptr_t TombstoneBitPattern =
  126. (std::numeric_limits<uintptr_t>::max() - 1)
  127. << PointerLikeTypeTraits<PoolEntryPtr>::NumLowBitsAvailable;
  128. constexpr static uintptr_t InvalidPtrMask =
  129. (std::numeric_limits<uintptr_t>::max() - 3)
  130. << PointerLikeTypeTraits<PoolEntryPtr>::NumLowBitsAvailable;
  131. PoolEntryPtr S = nullptr;
  132. };
  133. inline SymbolStringPool::~SymbolStringPool() {
  134. #ifndef NDEBUG
  135. clearDeadEntries();
  136. assert(Pool.empty() && "Dangling references at pool destruction time");
  137. #endif // NDEBUG
  138. }
  139. inline SymbolStringPtr SymbolStringPool::intern(StringRef S) {
  140. std::lock_guard<std::mutex> Lock(PoolMutex);
  141. PoolMap::iterator I;
  142. bool Added;
  143. std::tie(I, Added) = Pool.try_emplace(S, 0);
  144. return SymbolStringPtr(&*I);
  145. }
  146. inline void SymbolStringPool::clearDeadEntries() {
  147. std::lock_guard<std::mutex> Lock(PoolMutex);
  148. for (auto I = Pool.begin(), E = Pool.end(); I != E;) {
  149. auto Tmp = I++;
  150. if (Tmp->second == 0)
  151. Pool.erase(Tmp);
  152. }
  153. }
  154. inline bool SymbolStringPool::empty() const {
  155. std::lock_guard<std::mutex> Lock(PoolMutex);
  156. return Pool.empty();
  157. }
  158. } // end namespace orc
  159. template <>
  160. struct DenseMapInfo<orc::SymbolStringPtr> {
  161. static orc::SymbolStringPtr getEmptyKey() {
  162. return orc::SymbolStringPtr::getEmptyVal();
  163. }
  164. static orc::SymbolStringPtr getTombstoneKey() {
  165. return orc::SymbolStringPtr::getTombstoneVal();
  166. }
  167. static unsigned getHashValue(const orc::SymbolStringPtr &V) {
  168. return DenseMapInfo<orc::SymbolStringPtr::PoolEntryPtr>::getHashValue(V.S);
  169. }
  170. static bool isEqual(const orc::SymbolStringPtr &LHS,
  171. const orc::SymbolStringPtr &RHS) {
  172. return LHS.S == RHS.S;
  173. }
  174. };
  175. } // end namespace llvm
  176. #endif // LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
  177. #ifdef __GNUC__
  178. #pragma GCC diagnostic pop
  179. #endif