1 | //===- SymbolStringPool.h - Multi-threaded pool for JIT symbols -*- C++ -*-===// |
2 | // |
3 | // The LLVM Compiler Infrastructure |
4 | // |
5 | // This file is distributed under the University of Illinois Open Source |
6 | // License. See LICENSE.TXT for details. |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | // |
10 | // Contains a multi-threaded string pool suitable for use with ORC. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H |
15 | #define LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H |
16 | |
17 | #include "llvm/ADT/DenseMap.h" |
18 | #include "llvm/ADT/StringMap.h" |
19 | #include <atomic> |
20 | #include <mutex> |
21 | |
22 | namespace llvm { |
23 | namespace orc { |
24 | |
25 | class SymbolStringPtr; |
26 | |
27 | /// String pool for symbol names used by the JIT. |
28 | class SymbolStringPool { |
29 | friend class SymbolStringPtr; |
30 | public: |
31 | /// Destroy a SymbolStringPool. |
32 | ~SymbolStringPool(); |
33 | |
34 | /// Create a symbol string pointer from the given string. |
35 | SymbolStringPtr intern(StringRef S); |
36 | |
37 | /// Remove from the pool any entries that are no longer referenced. |
38 | void clearDeadEntries(); |
39 | |
40 | /// Returns true if the pool is empty. |
41 | bool empty() const; |
42 | private: |
43 | using RefCountType = std::atomic<size_t>; |
44 | using PoolMap = StringMap<RefCountType>; |
45 | using PoolMapEntry = StringMapEntry<RefCountType>; |
46 | mutable std::mutex PoolMutex; |
47 | PoolMap Pool; |
48 | }; |
49 | |
50 | /// Pointer to a pooled string representing a symbol name. |
51 | class SymbolStringPtr { |
52 | friend class SymbolStringPool; |
53 | friend struct DenseMapInfo<SymbolStringPtr>; |
54 | friend bool operator==(const SymbolStringPtr &LHS, |
55 | const SymbolStringPtr &RHS); |
56 | friend bool operator<(const SymbolStringPtr &LHS, const SymbolStringPtr &RHS); |
57 | |
58 | static SymbolStringPool::PoolMapEntry Tombstone; |
59 | |
60 | public: |
61 | SymbolStringPtr() = default; |
62 | SymbolStringPtr(const SymbolStringPtr &Other) |
63 | : S(Other.S) { |
64 | if (S) |
65 | ++S->getValue(); |
66 | } |
67 | |
68 | SymbolStringPtr& operator=(const SymbolStringPtr &Other) { |
69 | if (S) |
70 | --S->getValue(); |
71 | S = Other.S; |
72 | if (S) |
73 | ++S->getValue(); |
74 | return *this; |
75 | } |
76 | |
77 | SymbolStringPtr(SymbolStringPtr &&Other) : S(nullptr) { |
78 | std::swap(S, Other.S); |
79 | } |
80 | |
81 | SymbolStringPtr& operator=(SymbolStringPtr &&Other) { |
82 | if (S) |
83 | --S->getValue(); |
84 | S = nullptr; |
85 | std::swap(S, Other.S); |
86 | return *this; |
87 | } |
88 | |
89 | ~SymbolStringPtr() { |
90 | if (S) |
91 | --S->getValue(); |
92 | } |
93 | |
94 | StringRef operator*() const { return S->first(); } |
95 | |
96 | private: |
97 | |
98 | SymbolStringPtr(SymbolStringPool::PoolMapEntry *S) |
99 | : S(S) { |
100 | if (S) |
101 | ++S->getValue(); |
102 | } |
103 | |
104 | SymbolStringPool::PoolMapEntry *S = nullptr; |
105 | }; |
106 | |
107 | inline bool operator==(const SymbolStringPtr &LHS, const SymbolStringPtr &RHS) { |
108 | return LHS.S == RHS.S; |
109 | } |
110 | |
111 | inline bool operator!=(const SymbolStringPtr &LHS, const SymbolStringPtr &RHS) { |
112 | return !(LHS == RHS); |
113 | } |
114 | |
115 | inline bool operator<(const SymbolStringPtr &LHS, const SymbolStringPtr &RHS) { |
116 | return LHS.S < RHS.S; |
117 | } |
118 | |
119 | inline SymbolStringPool::~SymbolStringPool() { |
120 | #ifndef NDEBUG |
121 | clearDeadEntries(); |
122 | assert(Pool.empty() && "Dangling references at pool destruction time" ); |
123 | #endif // NDEBUG |
124 | } |
125 | |
126 | inline SymbolStringPtr SymbolStringPool::intern(StringRef S) { |
127 | std::lock_guard<std::mutex> Lock(PoolMutex); |
128 | PoolMap::iterator I; |
129 | bool Added; |
130 | std::tie(I, Added) = Pool.try_emplace(S, 0); |
131 | return SymbolStringPtr(&*I); |
132 | } |
133 | |
134 | inline void SymbolStringPool::clearDeadEntries() { |
135 | std::lock_guard<std::mutex> Lock(PoolMutex); |
136 | for (auto I = Pool.begin(), E = Pool.end(); I != E;) { |
137 | auto Tmp = I++; |
138 | if (Tmp->second == 0) |
139 | Pool.erase(Tmp); |
140 | } |
141 | } |
142 | |
143 | inline bool SymbolStringPool::empty() const { |
144 | std::lock_guard<std::mutex> Lock(PoolMutex); |
145 | return Pool.empty(); |
146 | } |
147 | |
148 | } // end namespace orc |
149 | |
150 | template <> |
151 | struct DenseMapInfo<orc::SymbolStringPtr> { |
152 | |
153 | static orc::SymbolStringPtr getEmptyKey() { |
154 | return orc::SymbolStringPtr(); |
155 | } |
156 | |
157 | static orc::SymbolStringPtr getTombstoneKey() { |
158 | return orc::SymbolStringPtr(&orc::SymbolStringPtr::Tombstone); |
159 | } |
160 | |
161 | static unsigned getHashValue(orc::SymbolStringPtr V) { |
162 | uintptr_t IV = reinterpret_cast<uintptr_t>(V.S); |
163 | return unsigned(IV) ^ unsigned(IV >> 9); |
164 | } |
165 | |
166 | static bool isEqual(const orc::SymbolStringPtr &LHS, |
167 | const orc::SymbolStringPtr &RHS) { |
168 | return LHS.S == RHS.S; |
169 | } |
170 | }; |
171 | |
172 | } // end namespace llvm |
173 | |
174 | #endif // LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H |
175 | |