blob: c354f6c3559cc0ae9861e25bd0b0d56cae4e5b65 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- SymbolStringPool.h - Multi-threaded pool for JIT symbols -*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8//
9// Contains a multi-threaded string pool suitable for use with ORC.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
14#define LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
15
Andrew Walbran16937d02019-10-22 13:54:20 +010016#include "llvm/ADT/DenseMap.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010017#include "llvm/ADT/StringMap.h"
18#include <atomic>
19#include <mutex>
20
21namespace llvm {
22namespace orc {
23
24class SymbolStringPtr;
25
Andrew Scullcdfcccc2018-10-05 20:58:37 +010026/// String pool for symbol names used by the JIT.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010027class SymbolStringPool {
28 friend class SymbolStringPtr;
29public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +010030 /// Destroy a SymbolStringPool.
31 ~SymbolStringPool();
32
33 /// Create a symbol string pointer from the given string.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010034 SymbolStringPtr intern(StringRef S);
35
Andrew Scullcdfcccc2018-10-05 20:58:37 +010036 /// Remove from the pool any entries that are no longer referenced.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010037 void clearDeadEntries();
38
Andrew Scullcdfcccc2018-10-05 20:58:37 +010039 /// Returns true if the pool is empty.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010040 bool empty() const;
41private:
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
Andrew Scullcdfcccc2018-10-05 20:58:37 +010049/// Pointer to a pooled string representing a symbol name.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010050class SymbolStringPtr {
51 friend class SymbolStringPool;
Andrew Walbran16937d02019-10-22 13:54:20 +010052 friend struct DenseMapInfo<SymbolStringPtr>;
Andrew Walbran16937d02019-10-22 13:54:20 +010053
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010054public:
55 SymbolStringPtr() = default;
56 SymbolStringPtr(const SymbolStringPtr &Other)
57 : S(Other.S) {
Andrew Walbran3d2c1972020-04-07 12:24:26 +010058 if (isRealPoolEntry(S))
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010059 ++S->getValue();
60 }
61
62 SymbolStringPtr& operator=(const SymbolStringPtr &Other) {
Andrew Walbran3d2c1972020-04-07 12:24:26 +010063 if (isRealPoolEntry(S))
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010064 --S->getValue();
65 S = Other.S;
Andrew Walbran3d2c1972020-04-07 12:24:26 +010066 if (isRealPoolEntry(S))
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010067 ++S->getValue();
68 return *this;
69 }
70
71 SymbolStringPtr(SymbolStringPtr &&Other) : S(nullptr) {
72 std::swap(S, Other.S);
73 }
74
75 SymbolStringPtr& operator=(SymbolStringPtr &&Other) {
Andrew Walbran3d2c1972020-04-07 12:24:26 +010076 if (isRealPoolEntry(S))
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010077 --S->getValue();
78 S = nullptr;
79 std::swap(S, Other.S);
80 return *this;
81 }
82
83 ~SymbolStringPtr() {
Andrew Walbran3d2c1972020-04-07 12:24:26 +010084 if (isRealPoolEntry(S))
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010085 --S->getValue();
86 }
87
88 StringRef operator*() const { return S->first(); }
89
Andrew Walbran3d2c1972020-04-07 12:24:26 +010090 friend bool operator==(const SymbolStringPtr &LHS,
91 const SymbolStringPtr &RHS) {
92 return LHS.S == RHS.S;
93 }
94
95 friend bool operator!=(const SymbolStringPtr &LHS,
96 const SymbolStringPtr &RHS) {
97 return !(LHS == RHS);
98 }
99
100 friend bool operator<(const SymbolStringPtr &LHS,
101 const SymbolStringPtr &RHS) {
102 return LHS.S < RHS.S;
103 }
104
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100105private:
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100106 using PoolEntryPtr = SymbolStringPool::PoolMapEntry *;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100107
108 SymbolStringPtr(SymbolStringPool::PoolMapEntry *S)
109 : S(S) {
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100110 if (isRealPoolEntry(S))
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100111 ++S->getValue();
112 }
113
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100114 // Returns false for null, empty, and tombstone values, true otherwise.
115 bool isRealPoolEntry(PoolEntryPtr P) {
116 return ((reinterpret_cast<uintptr_t>(P) - 1) & InvalidPtrMask) !=
117 InvalidPtrMask;
118 }
119
120 static SymbolStringPtr getEmptyVal() {
121 return SymbolStringPtr(reinterpret_cast<PoolEntryPtr>(EmptyBitPattern));
122 }
123
124 static SymbolStringPtr getTombstoneVal() {
125 return SymbolStringPtr(reinterpret_cast<PoolEntryPtr>(TombstoneBitPattern));
126 }
127
128 constexpr static uintptr_t EmptyBitPattern =
129 std::numeric_limits<uintptr_t>::max()
130 << PointerLikeTypeTraits<PoolEntryPtr>::NumLowBitsAvailable;
131
132 constexpr static uintptr_t TombstoneBitPattern =
133 (std::numeric_limits<uintptr_t>::max() - 1)
134 << PointerLikeTypeTraits<PoolEntryPtr>::NumLowBitsAvailable;
135
136 constexpr static uintptr_t InvalidPtrMask =
137 (std::numeric_limits<uintptr_t>::max() - 3)
138 << PointerLikeTypeTraits<PoolEntryPtr>::NumLowBitsAvailable;
139
140 PoolEntryPtr S = nullptr;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100141};
142
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100143inline SymbolStringPool::~SymbolStringPool() {
144#ifndef NDEBUG
145 clearDeadEntries();
146 assert(Pool.empty() && "Dangling references at pool destruction time");
147#endif // NDEBUG
148}
149
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100150inline SymbolStringPtr SymbolStringPool::intern(StringRef S) {
151 std::lock_guard<std::mutex> Lock(PoolMutex);
152 PoolMap::iterator I;
153 bool Added;
154 std::tie(I, Added) = Pool.try_emplace(S, 0);
155 return SymbolStringPtr(&*I);
156}
157
158inline void SymbolStringPool::clearDeadEntries() {
159 std::lock_guard<std::mutex> Lock(PoolMutex);
160 for (auto I = Pool.begin(), E = Pool.end(); I != E;) {
161 auto Tmp = I++;
162 if (Tmp->second == 0)
163 Pool.erase(Tmp);
164 }
165}
166
167inline bool SymbolStringPool::empty() const {
168 std::lock_guard<std::mutex> Lock(PoolMutex);
169 return Pool.empty();
170}
171
172} // end namespace orc
Andrew Walbran16937d02019-10-22 13:54:20 +0100173
174template <>
175struct DenseMapInfo<orc::SymbolStringPtr> {
176
177 static orc::SymbolStringPtr getEmptyKey() {
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100178 return orc::SymbolStringPtr::getEmptyVal();
Andrew Walbran16937d02019-10-22 13:54:20 +0100179 }
180
181 static orc::SymbolStringPtr getTombstoneKey() {
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100182 return orc::SymbolStringPtr::getTombstoneVal();
Andrew Walbran16937d02019-10-22 13:54:20 +0100183 }
184
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100185 static unsigned getHashValue(const orc::SymbolStringPtr &V) {
186 return DenseMapInfo<orc::SymbolStringPtr::PoolEntryPtr>::getHashValue(V.S);
Andrew Walbran16937d02019-10-22 13:54:20 +0100187 }
188
189 static bool isEqual(const orc::SymbolStringPtr &LHS,
190 const orc::SymbolStringPtr &RHS) {
191 return LHS.S == RHS.S;
192 }
193};
194
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100195} // end namespace llvm
196
197#endif // LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H