1 //===-- 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" 11 #include "lldb/Host/Mutex.h" 12 #include "llvm/ADT/StringMap.h" 13 14 using namespace lldb_private; 15 16 17 class Pool 18 { 19 public: 20 typedef const char * StringPoolValueType; 21 typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator> StringPool; 22 typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType; 23 24 //------------------------------------------------------------------ 25 // Default constructor 26 // 27 // Initialize the member variables and create the empty string. 28 //------------------------------------------------------------------ 29 Pool () : 30 m_mutex (Mutex::eMutexTypeRecursive), 31 m_string_map () 32 { 33 } 34 35 //------------------------------------------------------------------ 36 // Destructor 37 //------------------------------------------------------------------ 38 ~Pool () 39 { 40 } 41 42 43 static StringPoolEntryType & 44 GetStringMapEntryFromKeyData (const char *keyData) 45 { 46 char *ptr = const_cast<char*>(keyData) - sizeof (StringPoolEntryType); 47 return *reinterpret_cast<StringPoolEntryType*>(ptr); 48 } 49 50 size_t 51 GetConstCStringLength (const char *ccstr) const 52 { 53 if (ccstr) 54 { 55 const StringPoolEntryType&entry = GetStringMapEntryFromKeyData (ccstr); 56 return entry.getKey().size(); 57 } 58 return 0; 59 } 60 61 StringPoolValueType 62 GetMangledCounterpart (const char *ccstr) const 63 { 64 if (ccstr) 65 return GetStringMapEntryFromKeyData (ccstr).getValue(); 66 return 0; 67 } 68 69 bool 70 SetMangledCounterparts (const char *key_ccstr, const char *value_ccstr) 71 { 72 if (key_ccstr && value_ccstr) 73 { 74 GetStringMapEntryFromKeyData (key_ccstr).setValue(value_ccstr); 75 GetStringMapEntryFromKeyData (value_ccstr).setValue(key_ccstr); 76 return true; 77 } 78 return false; 79 } 80 81 const char * 82 GetConstCString (const char *cstr) 83 { 84 if (cstr) 85 return GetConstCStringWithLength (cstr, strlen (cstr)); 86 return NULL; 87 } 88 89 const char * 90 GetConstCStringWithLength (const char *cstr, size_t cstr_len) 91 { 92 if (cstr) 93 { 94 Mutex::Locker locker (m_mutex); 95 llvm::StringRef string_ref (cstr, cstr_len); 96 StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL); 97 return entry.getKeyData(); 98 } 99 return NULL; 100 } 101 102 const char * 103 GetConstCStringWithStringRef (const llvm::StringRef &string_ref) 104 { 105 if (string_ref.data()) 106 { 107 Mutex::Locker locker (m_mutex); 108 StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL); 109 return entry.getKeyData(); 110 } 111 return NULL; 112 } 113 114 const char * 115 GetConstCStringAndSetMangledCounterPart (const char *demangled_cstr, const char *mangled_ccstr) 116 { 117 if (demangled_cstr) 118 { 119 Mutex::Locker locker (m_mutex); 120 // Make string pool entry with the mangled counterpart already set 121 StringPoolEntryType& entry = m_string_map.GetOrCreateValue (llvm::StringRef (demangled_cstr), mangled_ccstr); 122 123 // Extract the const version of the demangled_cstr 124 const char *demangled_ccstr = entry.getKeyData(); 125 // Now assign the demangled const string as the counterpart of the 126 // mangled const string... 127 GetStringMapEntryFromKeyData (mangled_ccstr).setValue(demangled_ccstr); 128 // Return the constant demangled C string 129 return demangled_ccstr; 130 } 131 return NULL; 132 } 133 134 const char * 135 GetConstTrimmedCStringWithLength (const char *cstr, size_t cstr_len) 136 { 137 if (cstr) 138 { 139 const size_t trimmed_len = std::min<size_t> (strlen (cstr), cstr_len); 140 return GetConstCStringWithLength (cstr, trimmed_len); 141 } 142 return NULL; 143 } 144 145 //------------------------------------------------------------------ 146 // Return the size in bytes that this object and any items in its 147 // collection of uniqued strings + data count values takes in 148 // memory. 149 //------------------------------------------------------------------ 150 size_t 151 MemorySize() const 152 { 153 Mutex::Locker locker (m_mutex); 154 size_t mem_size = sizeof(Pool); 155 const_iterator end = m_string_map.end(); 156 for (const_iterator pos = m_string_map.begin(); pos != end; ++pos) 157 { 158 mem_size += sizeof(StringPoolEntryType) + pos->getKey().size(); 159 } 160 return mem_size; 161 } 162 163 protected: 164 //------------------------------------------------------------------ 165 // Typedefs 166 //------------------------------------------------------------------ 167 typedef StringPool::iterator iterator; 168 typedef StringPool::const_iterator const_iterator; 169 170 //------------------------------------------------------------------ 171 // Member variables 172 //------------------------------------------------------------------ 173 mutable Mutex m_mutex; 174 StringPool m_string_map; 175 }; 176 177 //---------------------------------------------------------------------- 178 // Frameworks and dylibs aren't supposed to have global C++ 179 // initializers so we hide the string pool in a static function so 180 // that it will get initialized on the first call to this static 181 // function. 182 // 183 // Note, for now we make the string pool a pointer to the pool, because 184 // we can't guarantee that some objects won't get destroyed after the 185 // global destructor chain is run, and trying to make sure no destructors 186 // touch ConstStrings is difficult. So we leak the pool instead. 187 // 188 // FIXME: If we are going to keep it this way we should come up with some 189 // abstraction to "pthread_once" so we don't have to check the pointer 190 // every time. 191 //---------------------------------------------------------------------- 192 static Pool & 193 StringPool() 194 { 195 static Mutex g_pool_initialization_mutex; 196 static Pool *g_string_pool = NULL; 197 198 if (g_string_pool == NULL) 199 { 200 Mutex::Locker initialization_locker(g_pool_initialization_mutex); 201 if (g_string_pool == NULL) 202 { 203 g_string_pool = new Pool(); 204 } 205 } 206 207 return *g_string_pool; 208 } 209 210 ConstString::ConstString (const char *cstr) : 211 m_string (StringPool().GetConstCString (cstr)) 212 { 213 } 214 215 ConstString::ConstString (const char *cstr, size_t cstr_len) : 216 m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len)) 217 { 218 } 219 220 ConstString::ConstString (const llvm::StringRef &s) : 221 m_string (StringPool().GetConstCStringWithLength (s.data(), s.size())) 222 { 223 } 224 225 bool 226 ConstString::operator < (const ConstString& rhs) const 227 { 228 if (m_string == rhs.m_string) 229 return false; 230 231 llvm::StringRef lhs_string_ref (m_string, StringPool().GetConstCStringLength (m_string)); 232 llvm::StringRef rhs_string_ref (rhs.m_string, StringPool().GetConstCStringLength (rhs.m_string)); 233 234 // If both have valid C strings, then return the comparison 235 if (lhs_string_ref.data() && rhs_string_ref.data()) 236 return lhs_string_ref < rhs_string_ref; 237 238 // Else one of them was NULL, so if LHS is NULL then it is less than 239 return lhs_string_ref.data() == NULL; 240 } 241 242 Stream& 243 lldb_private::operator << (Stream& s, const ConstString& str) 244 { 245 const char *cstr = str.GetCString(); 246 if (cstr) 247 s << cstr; 248 249 return s; 250 } 251 252 size_t 253 ConstString::GetLength () const 254 { 255 return StringPool().GetConstCStringLength (m_string); 256 } 257 258 int 259 ConstString::Compare (const ConstString& lhs, const ConstString& rhs) 260 { 261 // If the iterators are the same, this is the same string 262 register const char *lhs_cstr = lhs.m_string; 263 register const char *rhs_cstr = rhs.m_string; 264 if (lhs_cstr == rhs_cstr) 265 return 0; 266 if (lhs_cstr && rhs_cstr) 267 { 268 llvm::StringRef lhs_string_ref (lhs_cstr, StringPool().GetConstCStringLength (lhs_cstr)); 269 llvm::StringRef rhs_string_ref (rhs_cstr, StringPool().GetConstCStringLength (rhs_cstr)); 270 return lhs_string_ref.compare(rhs_string_ref); 271 } 272 273 if (lhs_cstr) 274 return +1; // LHS isn't NULL but RHS is 275 else 276 return -1; // LHS is NULL but RHS isn't 277 } 278 279 void 280 ConstString::Dump(Stream *s, const char *fail_value) const 281 { 282 if (s) 283 { 284 const char *cstr = AsCString (fail_value); 285 if (cstr) 286 s->PutCString (cstr); 287 } 288 } 289 290 void 291 ConstString::DumpDebug(Stream *s) const 292 { 293 const char *cstr = GetCString (); 294 size_t cstr_len = GetLength(); 295 // Only print the parens if we have a non-NULL string 296 const char *parens = cstr ? "\"" : ""; 297 s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, (int)sizeof(void*) * 2, this, parens, cstr, parens, (uint64_t)cstr_len); 298 } 299 300 void 301 ConstString::SetCString (const char *cstr) 302 { 303 m_string = StringPool().GetConstCString (cstr); 304 } 305 306 void 307 ConstString::SetString (const llvm::StringRef &s) 308 { 309 m_string = StringPool().GetConstCStringWithLength (s.data(), s.size()); 310 } 311 312 void 313 ConstString::SetCStringWithMangledCounterpart (const char *demangled, const ConstString &mangled) 314 { 315 m_string = StringPool().GetConstCStringAndSetMangledCounterPart (demangled, mangled.m_string); 316 } 317 318 bool 319 ConstString::GetMangledCounterpart (ConstString &counterpart) const 320 { 321 counterpart.m_string = StringPool().GetMangledCounterpart(m_string); 322 return counterpart; 323 } 324 325 void 326 ConstString::SetCStringWithLength (const char *cstr, size_t cstr_len) 327 { 328 m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len); 329 } 330 331 void 332 ConstString::SetTrimmedCStringWithLength (const char *cstr, size_t cstr_len) 333 { 334 m_string = StringPool().GetConstTrimmedCStringWithLength (cstr, cstr_len); 335 } 336 337 size_t 338 ConstString::StaticMemorySize() 339 { 340 // Get the size of the static string pool 341 return StringPool().MemorySize(); 342 } 343