SymbolStringPool.h 5.8 KB

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