blob: c2e95d801723c5f4b45e341a5d1dc79bf8fb1241 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- ConstString.cpp -----------------------------------------*- 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#include "lldb/Core/ConstString.h"
10#include "lldb/Core/Stream.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000011#include "llvm/ADT/StringMap.h"
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +000012#include "llvm/ADT/StringExtras.h"
13#include "llvm/Support/RWMutex.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000014
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +000015#include <array>
16#include <mutex>
Enrico Granata3cfc49f2014-12-16 02:34:13 +000017
Chris Lattner30fdc8d2010-06-08 16:52:24 +000018using namespace lldb_private;
19
Chris Lattner30fdc8d2010-06-08 16:52:24 +000020class Pool
21{
22public:
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000023 typedef const char * StringPoolValueType;
24 typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator> StringPool;
25 typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000027 static StringPoolEntryType &
Chris Lattner30fdc8d2010-06-08 16:52:24 +000028 GetStringMapEntryFromKeyData (const char *keyData)
29 {
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000030 char *ptr = const_cast<char*>(keyData) - sizeof (StringPoolEntryType);
31 return *reinterpret_cast<StringPoolEntryType*>(ptr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000032 }
33
34 size_t
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000035 GetConstCStringLength (const char *ccstr) const
Chris Lattner30fdc8d2010-06-08 16:52:24 +000036 {
37 if (ccstr)
38 {
Tamas Berghammerac47b6e2015-10-22 11:14:31 +000039 const uint8_t h = hash (llvm::StringRef(ccstr));
40 llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
41 const StringPoolEntryType& entry = GetStringMapEntryFromKeyData (ccstr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000042 return entry.getKey().size();
43 }
44 return 0;
45 }
46
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000047 StringPoolValueType
48 GetMangledCounterpart (const char *ccstr) const
49 {
50 if (ccstr)
Tamas Berghammerac47b6e2015-10-22 11:14:31 +000051 {
52 const uint8_t h = hash (llvm::StringRef(ccstr));
53 llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000054 return GetStringMapEntryFromKeyData (ccstr).getValue();
Tamas Berghammerac47b6e2015-10-22 11:14:31 +000055 }
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000056 return 0;
57 }
58
59 bool
60 SetMangledCounterparts (const char *key_ccstr, const char *value_ccstr)
61 {
62 if (key_ccstr && value_ccstr)
63 {
Tamas Berghammerac47b6e2015-10-22 11:14:31 +000064 {
65 const uint8_t h = hash (llvm::StringRef(key_ccstr));
66 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
67 GetStringMapEntryFromKeyData (key_ccstr).setValue(value_ccstr);
68 }
69 {
70 const uint8_t h = hash (llvm::StringRef(value_ccstr));
71 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
72 GetStringMapEntryFromKeyData (value_ccstr).setValue(key_ccstr);
73 }
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000074 return true;
75 }
76 return false;
77 }
78
Chris Lattner30fdc8d2010-06-08 16:52:24 +000079 const char *
80 GetConstCString (const char *cstr)
81 {
82 if (cstr)
Benjamin Kramereb9165c2010-06-22 15:28:34 +000083 return GetConstCStringWithLength (cstr, strlen (cstr));
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +000084 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000085 }
86
87 const char *
Greg Claytonc7bece562013-01-25 18:06:21 +000088 GetConstCStringWithLength (const char *cstr, size_t cstr_len)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000089 {
90 if (cstr)
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +000091 return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len));
92 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000093 }
94
95 const char *
Greg Clayton1f746072012-08-29 21:13:06 +000096 GetConstCStringWithStringRef (const llvm::StringRef &string_ref)
97 {
98 if (string_ref.data())
99 {
Tamas Berghammerac47b6e2015-10-22 11:14:31 +0000100 const uint8_t h = hash (string_ref);
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000101
102 {
103 llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
104 auto it = m_string_pools[h].m_string_map.find (string_ref);
105 if (it != m_string_pools[h].m_string_map.end())
106 return it->getKeyData();
107 }
108
109 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
110 StringPoolEntryType& entry = *m_string_pools[h].m_string_map.insert (std::make_pair (string_ref, nullptr)).first;
Greg Clayton1f746072012-08-29 21:13:06 +0000111 return entry.getKeyData();
112 }
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000113 return nullptr;
Greg Clayton1f746072012-08-29 21:13:06 +0000114 }
115
116 const char *
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000117 GetConstCStringAndSetMangledCounterPart (const char *demangled_cstr, const char *mangled_ccstr)
118 {
119 if (demangled_cstr)
120 {
Tamas Berghammerac47b6e2015-10-22 11:14:31 +0000121 const char *demangled_ccstr = nullptr;
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000122
Tamas Berghammerac47b6e2015-10-22 11:14:31 +0000123 {
124 llvm::StringRef string_ref (demangled_cstr);
125 const uint8_t h = hash (string_ref);
126 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000127
Tamas Berghammerac47b6e2015-10-22 11:14:31 +0000128 // Make string pool entry with the mangled counterpart already set
129 StringPoolEntryType& entry = *m_string_pools[h].m_string_map.insert (
130 std::make_pair (string_ref, mangled_ccstr)).first;
131
132 // Extract the const version of the demangled_cstr
133 demangled_ccstr = entry.getKeyData();
134 }
135
136 {
137 // Now assign the demangled const string as the counterpart of the
138 // mangled const string...
139 const uint8_t h = hash (llvm::StringRef(mangled_ccstr));
140 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
141 GetStringMapEntryFromKeyData (mangled_ccstr).setValue(demangled_ccstr);
142 }
143
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000144 // Return the constant demangled C string
145 return demangled_ccstr;
146 }
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000147 return nullptr;
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000148 }
149
150 const char *
Greg Claytonc7bece562013-01-25 18:06:21 +0000151 GetConstTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000152 {
153 if (cstr)
154 {
Greg Claytonc7bece562013-01-25 18:06:21 +0000155 const size_t trimmed_len = std::min<size_t> (strlen (cstr), cstr_len);
Benjamin Kramereb9165c2010-06-22 15:28:34 +0000156 return GetConstCStringWithLength (cstr, trimmed_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000157 }
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000158 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000159 }
160
161 //------------------------------------------------------------------
162 // Return the size in bytes that this object and any items in its
Greg Clayton24756642011-09-12 03:55:58 +0000163 // collection of uniqued strings + data count values takes in
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000164 // memory.
165 //------------------------------------------------------------------
166 size_t
167 MemorySize() const
168 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000169 size_t mem_size = sizeof(Pool);
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000170 for (const auto& pool : m_string_pools)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000171 {
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000172 llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
173 for (const auto& entry : pool.m_string_map)
174 mem_size += sizeof(StringPoolEntryType) + entry.getKey().size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000175 }
176 return mem_size;
177 }
178
179protected:
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000180 uint8_t
Tamas Berghammerac47b6e2015-10-22 11:14:31 +0000181 hash(const llvm::StringRef &s) const
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000182 {
183 uint32_t h = llvm::HashString(s);
184 return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff;
185 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000186
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000187 struct PoolEntry
188 {
189 mutable llvm::sys::SmartRWMutex<false> m_mutex;
190 StringPool m_string_map;
191 };
192
193 std::array<PoolEntry, 256> m_string_pools;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000194};
195
196//----------------------------------------------------------------------
197// Frameworks and dylibs aren't supposed to have global C++
198// initializers so we hide the string pool in a static function so
199// that it will get initialized on the first call to this static
200// function.
Jim Ingham5ce45fd2012-05-09 18:37:10 +0000201//
202// Note, for now we make the string pool a pointer to the pool, because
203// we can't guarantee that some objects won't get destroyed after the
204// global destructor chain is run, and trying to make sure no destructors
205// touch ConstStrings is difficult. So we leak the pool instead.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000206//----------------------------------------------------------------------
207static Pool &
208StringPool()
209{
Enrico Granata3cfc49f2014-12-16 02:34:13 +0000210 static std::once_flag g_pool_initialization_flag;
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000211 static Pool *g_string_pool = nullptr;
Jim Ingham5ce45fd2012-05-09 18:37:10 +0000212
Enrico Granata3cfc49f2014-12-16 02:34:13 +0000213 std::call_once(g_pool_initialization_flag, [] () {
214 g_string_pool = new Pool();
215 });
Jim Ingham5ce45fd2012-05-09 18:37:10 +0000216
217 return *g_string_pool;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000218}
219
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000220ConstString::ConstString (const char *cstr) :
221 m_string (StringPool().GetConstCString (cstr))
222{
223}
224
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000225ConstString::ConstString (const char *cstr, size_t cstr_len) :
226 m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
227{
228}
229
Greg Clayton67cc0632012-08-22 17:17:09 +0000230ConstString::ConstString (const llvm::StringRef &s) :
231 m_string (StringPool().GetConstCStringWithLength (s.data(), s.size()))
232{
233}
234
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000235bool
236ConstString::operator < (const ConstString& rhs) const
237{
238 if (m_string == rhs.m_string)
239 return false;
240
241 llvm::StringRef lhs_string_ref (m_string, StringPool().GetConstCStringLength (m_string));
242 llvm::StringRef rhs_string_ref (rhs.m_string, StringPool().GetConstCStringLength (rhs.m_string));
243
244 // If both have valid C strings, then return the comparison
245 if (lhs_string_ref.data() && rhs_string_ref.data())
246 return lhs_string_ref < rhs_string_ref;
247
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000248 // Else one of them was nullptr, so if LHS is nullptr then it is less than
249 return lhs_string_ref.data() == nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000250}
251
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000252Stream&
253lldb_private::operator << (Stream& s, const ConstString& str)
254{
255 const char *cstr = str.GetCString();
256 if (cstr)
257 s << cstr;
258
259 return s;
260}
261
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000262size_t
263ConstString::GetLength () const
264{
265 return StringPool().GetConstCStringLength (m_string);
266}
267
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000268int
269ConstString::Compare (const ConstString& lhs, const ConstString& rhs)
270{
271 // If the iterators are the same, this is the same string
Eric Christopher2490f5c2013-08-30 17:50:57 +0000272 const char *lhs_cstr = lhs.m_string;
273 const char *rhs_cstr = rhs.m_string;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000274 if (lhs_cstr == rhs_cstr)
275 return 0;
276 if (lhs_cstr && rhs_cstr)
277 {
278 llvm::StringRef lhs_string_ref (lhs_cstr, StringPool().GetConstCStringLength (lhs_cstr));
279 llvm::StringRef rhs_string_ref (rhs_cstr, StringPool().GetConstCStringLength (rhs_cstr));
280 return lhs_string_ref.compare(rhs_string_ref);
281 }
282
283 if (lhs_cstr)
284 return +1; // LHS isn't NULL but RHS is
285 else
286 return -1; // LHS is NULL but RHS isn't
287}
288
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000289void
290ConstString::Dump(Stream *s, const char *fail_value) const
291{
Enrico Granata80fcdd42012-11-03 00:09:46 +0000292 if (s)
293 {
294 const char *cstr = AsCString (fail_value);
295 if (cstr)
296 s->PutCString (cstr);
297 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000298}
299
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000300void
301ConstString::DumpDebug(Stream *s) const
302{
303 const char *cstr = GetCString ();
304 size_t cstr_len = GetLength();
305 // Only print the parens if we have a non-NULL string
306 const char *parens = cstr ? "\"" : "";
Saleem Abdulrasool324a1032014-04-04 04:06:10 +0000307 s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64,
308 static_cast<int>(sizeof(void*) * 2),
309 static_cast<const void*>(this), parens, cstr, parens,
310 static_cast<uint64_t>(cstr_len));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000311}
312
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000313void
314ConstString::SetCString (const char *cstr)
315{
316 m_string = StringPool().GetConstCString (cstr);
317}
318
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000319void
Greg Clayton67cc0632012-08-22 17:17:09 +0000320ConstString::SetString (const llvm::StringRef &s)
321{
322 m_string = StringPool().GetConstCStringWithLength (s.data(), s.size());
323}
324
325void
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000326ConstString::SetCStringWithMangledCounterpart (const char *demangled, const ConstString &mangled)
327{
328 m_string = StringPool().GetConstCStringAndSetMangledCounterPart (demangled, mangled.m_string);
329}
330
331bool
332ConstString::GetMangledCounterpart (ConstString &counterpart) const
333{
334 counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
Sean Callananddd7a2a2013-10-03 22:27:29 +0000335 return (bool)counterpart;
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000336}
337
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000338void
339ConstString::SetCStringWithLength (const char *cstr, size_t cstr_len)
340{
341 m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
342}
343
344void
345ConstString::SetTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
346{
347 m_string = StringPool().GetConstTrimmedCStringWithLength (cstr, cstr_len);
348}
349
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000350size_t
351ConstString::StaticMemorySize()
352{
353 // Get the size of the static string pool
354 return StringPool().MemorySize();
355}