blob: 21a1e5f907007636812d15b04da163e3daeb2c09 [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 {
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000039 const StringPoolEntryType&entry = GetStringMapEntryFromKeyData (ccstr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000040 return entry.getKey().size();
41 }
42 return 0;
43 }
44
Greg Claytonc3ae1ce2011-06-09 22:34:34 +000045 StringPoolValueType
46 GetMangledCounterpart (const char *ccstr) const
47 {
48 if (ccstr)
49 return GetStringMapEntryFromKeyData (ccstr).getValue();
50 return 0;
51 }
52
53 bool
54 SetMangledCounterparts (const char *key_ccstr, const char *value_ccstr)
55 {
56 if (key_ccstr && value_ccstr)
57 {
58 GetStringMapEntryFromKeyData (key_ccstr).setValue(value_ccstr);
59 GetStringMapEntryFromKeyData (value_ccstr).setValue(key_ccstr);
60 return true;
61 }
62 return false;
63 }
64
Chris Lattner30fdc8d2010-06-08 16:52:24 +000065 const char *
66 GetConstCString (const char *cstr)
67 {
68 if (cstr)
Benjamin Kramereb9165c2010-06-22 15:28:34 +000069 return GetConstCStringWithLength (cstr, strlen (cstr));
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +000070 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000071 }
72
73 const char *
Greg Claytonc7bece562013-01-25 18:06:21 +000074 GetConstCStringWithLength (const char *cstr, size_t cstr_len)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000075 {
76 if (cstr)
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +000077 return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len));
78 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000079 }
80
81 const char *
Greg Clayton1f746072012-08-29 21:13:06 +000082 GetConstCStringWithStringRef (const llvm::StringRef &string_ref)
83 {
84 if (string_ref.data())
85 {
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +000086 uint8_t h = hash (string_ref);
87
88 {
89 llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
90 auto it = m_string_pools[h].m_string_map.find (string_ref);
91 if (it != m_string_pools[h].m_string_map.end())
92 return it->getKeyData();
93 }
94
95 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
96 StringPoolEntryType& entry = *m_string_pools[h].m_string_map.insert (std::make_pair (string_ref, nullptr)).first;
Greg Clayton1f746072012-08-29 21:13:06 +000097 return entry.getKeyData();
98 }
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +000099 return nullptr;
Greg Clayton1f746072012-08-29 21:13:06 +0000100 }
101
102 const char *
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000103 GetConstCStringAndSetMangledCounterPart (const char *demangled_cstr, const char *mangled_ccstr)
104 {
105 if (demangled_cstr)
106 {
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000107 llvm::StringRef string_ref (demangled_cstr);
108 uint8_t h = hash (string_ref);
109 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
110
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000111 // Make string pool entry with the mangled counterpart already set
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000112 StringPoolEntryType& entry = *m_string_pools[h].m_string_map.insert (std::make_pair (string_ref, mangled_ccstr)).first;
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000113
114 // Extract the const version of the demangled_cstr
115 const char *demangled_ccstr = entry.getKeyData();
116 // Now assign the demangled const string as the counterpart of the
117 // mangled const string...
118 GetStringMapEntryFromKeyData (mangled_ccstr).setValue(demangled_ccstr);
119 // Return the constant demangled C string
120 return demangled_ccstr;
121 }
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000122 return nullptr;
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000123 }
124
125 const char *
Greg Claytonc7bece562013-01-25 18:06:21 +0000126 GetConstTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000127 {
128 if (cstr)
129 {
Greg Claytonc7bece562013-01-25 18:06:21 +0000130 const size_t trimmed_len = std::min<size_t> (strlen (cstr), cstr_len);
Benjamin Kramereb9165c2010-06-22 15:28:34 +0000131 return GetConstCStringWithLength (cstr, trimmed_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000132 }
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000133 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000134 }
135
136 //------------------------------------------------------------------
137 // Return the size in bytes that this object and any items in its
Greg Clayton24756642011-09-12 03:55:58 +0000138 // collection of uniqued strings + data count values takes in
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000139 // memory.
140 //------------------------------------------------------------------
141 size_t
142 MemorySize() const
143 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000144 size_t mem_size = sizeof(Pool);
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000145 for (const auto& pool : m_string_pools)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000146 {
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000147 llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
148 for (const auto& entry : pool.m_string_map)
149 mem_size += sizeof(StringPoolEntryType) + entry.getKey().size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000150 }
151 return mem_size;
152 }
153
154protected:
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000155 uint8_t
156 hash(const llvm::StringRef &s)
157 {
158 uint32_t h = llvm::HashString(s);
159 return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff;
160 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000161
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000162 struct PoolEntry
163 {
164 mutable llvm::sys::SmartRWMutex<false> m_mutex;
165 StringPool m_string_map;
166 };
167
168 std::array<PoolEntry, 256> m_string_pools;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000169};
170
171//----------------------------------------------------------------------
172// Frameworks and dylibs aren't supposed to have global C++
173// initializers so we hide the string pool in a static function so
174// that it will get initialized on the first call to this static
175// function.
Jim Ingham5ce45fd2012-05-09 18:37:10 +0000176//
177// Note, for now we make the string pool a pointer to the pool, because
178// we can't guarantee that some objects won't get destroyed after the
179// global destructor chain is run, and trying to make sure no destructors
180// touch ConstStrings is difficult. So we leak the pool instead.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000181//----------------------------------------------------------------------
182static Pool &
183StringPool()
184{
Enrico Granata3cfc49f2014-12-16 02:34:13 +0000185 static std::once_flag g_pool_initialization_flag;
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000186 static Pool *g_string_pool = nullptr;
Jim Ingham5ce45fd2012-05-09 18:37:10 +0000187
Enrico Granata3cfc49f2014-12-16 02:34:13 +0000188 std::call_once(g_pool_initialization_flag, [] () {
189 g_string_pool = new Pool();
190 });
Jim Ingham5ce45fd2012-05-09 18:37:10 +0000191
192 return *g_string_pool;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000193}
194
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000195ConstString::ConstString (const char *cstr) :
196 m_string (StringPool().GetConstCString (cstr))
197{
198}
199
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000200ConstString::ConstString (const char *cstr, size_t cstr_len) :
201 m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
202{
203}
204
Greg Clayton67cc0632012-08-22 17:17:09 +0000205ConstString::ConstString (const llvm::StringRef &s) :
206 m_string (StringPool().GetConstCStringWithLength (s.data(), s.size()))
207{
208}
209
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000210bool
211ConstString::operator < (const ConstString& rhs) const
212{
213 if (m_string == rhs.m_string)
214 return false;
215
216 llvm::StringRef lhs_string_ref (m_string, StringPool().GetConstCStringLength (m_string));
217 llvm::StringRef rhs_string_ref (rhs.m_string, StringPool().GetConstCStringLength (rhs.m_string));
218
219 // If both have valid C strings, then return the comparison
220 if (lhs_string_ref.data() && rhs_string_ref.data())
221 return lhs_string_ref < rhs_string_ref;
222
Tamas Berghammer3fe5ce02015-10-14 10:38:22 +0000223 // Else one of them was nullptr, so if LHS is nullptr then it is less than
224 return lhs_string_ref.data() == nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000225}
226
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000227Stream&
228lldb_private::operator << (Stream& s, const ConstString& str)
229{
230 const char *cstr = str.GetCString();
231 if (cstr)
232 s << cstr;
233
234 return s;
235}
236
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000237size_t
238ConstString::GetLength () const
239{
240 return StringPool().GetConstCStringLength (m_string);
241}
242
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000243int
244ConstString::Compare (const ConstString& lhs, const ConstString& rhs)
245{
246 // If the iterators are the same, this is the same string
Eric Christopher2490f5c2013-08-30 17:50:57 +0000247 const char *lhs_cstr = lhs.m_string;
248 const char *rhs_cstr = rhs.m_string;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000249 if (lhs_cstr == rhs_cstr)
250 return 0;
251 if (lhs_cstr && rhs_cstr)
252 {
253 llvm::StringRef lhs_string_ref (lhs_cstr, StringPool().GetConstCStringLength (lhs_cstr));
254 llvm::StringRef rhs_string_ref (rhs_cstr, StringPool().GetConstCStringLength (rhs_cstr));
255 return lhs_string_ref.compare(rhs_string_ref);
256 }
257
258 if (lhs_cstr)
259 return +1; // LHS isn't NULL but RHS is
260 else
261 return -1; // LHS is NULL but RHS isn't
262}
263
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000264void
265ConstString::Dump(Stream *s, const char *fail_value) const
266{
Enrico Granata80fcdd42012-11-03 00:09:46 +0000267 if (s)
268 {
269 const char *cstr = AsCString (fail_value);
270 if (cstr)
271 s->PutCString (cstr);
272 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000273}
274
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000275void
276ConstString::DumpDebug(Stream *s) const
277{
278 const char *cstr = GetCString ();
279 size_t cstr_len = GetLength();
280 // Only print the parens if we have a non-NULL string
281 const char *parens = cstr ? "\"" : "";
Saleem Abdulrasool324a1032014-04-04 04:06:10 +0000282 s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64,
283 static_cast<int>(sizeof(void*) * 2),
284 static_cast<const void*>(this), parens, cstr, parens,
285 static_cast<uint64_t>(cstr_len));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000286}
287
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000288void
289ConstString::SetCString (const char *cstr)
290{
291 m_string = StringPool().GetConstCString (cstr);
292}
293
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000294void
Greg Clayton67cc0632012-08-22 17:17:09 +0000295ConstString::SetString (const llvm::StringRef &s)
296{
297 m_string = StringPool().GetConstCStringWithLength (s.data(), s.size());
298}
299
300void
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000301ConstString::SetCStringWithMangledCounterpart (const char *demangled, const ConstString &mangled)
302{
303 m_string = StringPool().GetConstCStringAndSetMangledCounterPart (demangled, mangled.m_string);
304}
305
306bool
307ConstString::GetMangledCounterpart (ConstString &counterpart) const
308{
309 counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
Sean Callananddd7a2a2013-10-03 22:27:29 +0000310 return (bool)counterpart;
Greg Claytonc3ae1ce2011-06-09 22:34:34 +0000311}
312
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000313void
314ConstString::SetCStringWithLength (const char *cstr, size_t cstr_len)
315{
316 m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
317}
318
319void
320ConstString::SetTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
321{
322 m_string = StringPool().GetConstTrimmedCStringWithLength (cstr, cstr_len);
323}
324
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000325size_t
326ConstString::StaticMemorySize()
327{
328 // Get the size of the static string pool
329 return StringPool().MemorySize();
330}