1bf9a7730SZachary Turner //===-- ConstString.cpp -----------------------------------------*- C++ -*-===// 2bf9a7730SZachary Turner // 3bf9a7730SZachary Turner // The LLVM Compiler Infrastructure 4bf9a7730SZachary Turner // 5bf9a7730SZachary Turner // This file is distributed under the University of Illinois Open Source 6bf9a7730SZachary Turner // License. See LICENSE.TXT for details. 7bf9a7730SZachary Turner // 8bf9a7730SZachary Turner //===----------------------------------------------------------------------===// 9bf9a7730SZachary Turner 10bf9a7730SZachary Turner #include "lldb/Utility/ConstString.h" 11bf9a7730SZachary Turner 12bf9a7730SZachary Turner // C Includes 13bf9a7730SZachary Turner // C++ Includes 14bf9a7730SZachary Turner #include <array> 15bf9a7730SZachary Turner #include <mutex> 16bf9a7730SZachary Turner 17bf9a7730SZachary Turner // Other libraries and framework includes 18bf9a7730SZachary Turner #include "llvm/ADT/StringExtras.h" 19bf9a7730SZachary Turner #include "llvm/ADT/StringMap.h" 20bf9a7730SZachary Turner #include "llvm/Support/RWMutex.h" 21bf9a7730SZachary Turner 22bf9a7730SZachary Turner // Project includes 23*c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h" 24bf9a7730SZachary Turner #include "lldb/Utility/Stream.h" 25bf9a7730SZachary Turner 26bf9a7730SZachary Turner using namespace lldb_private; 27bf9a7730SZachary Turner 28bf9a7730SZachary Turner class Pool { 29bf9a7730SZachary Turner public: 30bf9a7730SZachary Turner typedef const char *StringPoolValueType; 31bf9a7730SZachary Turner typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator> 32bf9a7730SZachary Turner StringPool; 33bf9a7730SZachary Turner typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType; 34bf9a7730SZachary Turner 35bf9a7730SZachary Turner static StringPoolEntryType & 36bf9a7730SZachary Turner GetStringMapEntryFromKeyData(const char *keyData) { 37bf9a7730SZachary Turner char *ptr = const_cast<char *>(keyData) - sizeof(StringPoolEntryType); 38bf9a7730SZachary Turner return *reinterpret_cast<StringPoolEntryType *>(ptr); 39bf9a7730SZachary Turner } 40bf9a7730SZachary Turner 41bf9a7730SZachary Turner size_t GetConstCStringLength(const char *ccstr) const { 42bf9a7730SZachary Turner if (ccstr != nullptr) { 43bf9a7730SZachary Turner const uint8_t h = hash(llvm::StringRef(ccstr)); 44bf9a7730SZachary Turner llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex); 45bf9a7730SZachary Turner const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr); 46bf9a7730SZachary Turner return entry.getKey().size(); 47bf9a7730SZachary Turner } 48bf9a7730SZachary Turner return 0; 49bf9a7730SZachary Turner } 50bf9a7730SZachary Turner 51bf9a7730SZachary Turner StringPoolValueType GetMangledCounterpart(const char *ccstr) const { 52bf9a7730SZachary Turner if (ccstr != nullptr) { 53bf9a7730SZachary Turner const uint8_t h = hash(llvm::StringRef(ccstr)); 54bf9a7730SZachary Turner llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex); 55bf9a7730SZachary Turner return GetStringMapEntryFromKeyData(ccstr).getValue(); 56bf9a7730SZachary Turner } 57bf9a7730SZachary Turner return nullptr; 58bf9a7730SZachary Turner } 59bf9a7730SZachary Turner 60bf9a7730SZachary Turner bool SetMangledCounterparts(const char *key_ccstr, const char *value_ccstr) { 61bf9a7730SZachary Turner if (key_ccstr != nullptr && value_ccstr != nullptr) { 62bf9a7730SZachary Turner { 63bf9a7730SZachary Turner const uint8_t h = hash(llvm::StringRef(key_ccstr)); 64bf9a7730SZachary Turner llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); 65bf9a7730SZachary Turner GetStringMapEntryFromKeyData(key_ccstr).setValue(value_ccstr); 66bf9a7730SZachary Turner } 67bf9a7730SZachary Turner { 68bf9a7730SZachary Turner const uint8_t h = hash(llvm::StringRef(value_ccstr)); 69bf9a7730SZachary Turner llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); 70bf9a7730SZachary Turner GetStringMapEntryFromKeyData(value_ccstr).setValue(key_ccstr); 71bf9a7730SZachary Turner } 72bf9a7730SZachary Turner return true; 73bf9a7730SZachary Turner } 74bf9a7730SZachary Turner return false; 75bf9a7730SZachary Turner } 76bf9a7730SZachary Turner 77bf9a7730SZachary Turner const char *GetConstCString(const char *cstr) { 78bf9a7730SZachary Turner if (cstr != nullptr) 79bf9a7730SZachary Turner return GetConstCStringWithLength(cstr, strlen(cstr)); 80bf9a7730SZachary Turner return nullptr; 81bf9a7730SZachary Turner } 82bf9a7730SZachary Turner 83bf9a7730SZachary Turner const char *GetConstCStringWithLength(const char *cstr, size_t cstr_len) { 84bf9a7730SZachary Turner if (cstr != nullptr) 85bf9a7730SZachary Turner return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len)); 86bf9a7730SZachary Turner return nullptr; 87bf9a7730SZachary Turner } 88bf9a7730SZachary Turner 89bf9a7730SZachary Turner const char *GetConstCStringWithStringRef(const llvm::StringRef &string_ref) { 90bf9a7730SZachary Turner if (string_ref.data()) { 91bf9a7730SZachary Turner const uint8_t h = hash(string_ref); 92bf9a7730SZachary Turner 93bf9a7730SZachary Turner { 94bf9a7730SZachary Turner llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex); 95bf9a7730SZachary Turner auto it = m_string_pools[h].m_string_map.find(string_ref); 96bf9a7730SZachary Turner if (it != m_string_pools[h].m_string_map.end()) 97bf9a7730SZachary Turner return it->getKeyData(); 98bf9a7730SZachary Turner } 99bf9a7730SZachary Turner 100bf9a7730SZachary Turner llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); 101bf9a7730SZachary Turner StringPoolEntryType &entry = 102bf9a7730SZachary Turner *m_string_pools[h] 103bf9a7730SZachary Turner .m_string_map.insert(std::make_pair(string_ref, nullptr)) 104bf9a7730SZachary Turner .first; 105bf9a7730SZachary Turner return entry.getKeyData(); 106bf9a7730SZachary Turner } 107bf9a7730SZachary Turner return nullptr; 108bf9a7730SZachary Turner } 109bf9a7730SZachary Turner 110bf9a7730SZachary Turner const char * 111bf9a7730SZachary Turner GetConstCStringAndSetMangledCounterPart(const char *demangled_cstr, 112bf9a7730SZachary Turner const char *mangled_ccstr) { 113bf9a7730SZachary Turner if (demangled_cstr != nullptr) { 114bf9a7730SZachary Turner const char *demangled_ccstr = nullptr; 115bf9a7730SZachary Turner 116bf9a7730SZachary Turner { 117bf9a7730SZachary Turner llvm::StringRef string_ref(demangled_cstr); 118bf9a7730SZachary Turner const uint8_t h = hash(string_ref); 119bf9a7730SZachary Turner llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); 120bf9a7730SZachary Turner 121bf9a7730SZachary Turner // Make string pool entry with the mangled counterpart already set 122bf9a7730SZachary Turner StringPoolEntryType &entry = 123bf9a7730SZachary Turner *m_string_pools[h] 124bf9a7730SZachary Turner .m_string_map.insert(std::make_pair(string_ref, mangled_ccstr)) 125bf9a7730SZachary Turner .first; 126bf9a7730SZachary Turner 127bf9a7730SZachary Turner // Extract the const version of the demangled_cstr 128bf9a7730SZachary Turner demangled_ccstr = entry.getKeyData(); 129bf9a7730SZachary Turner } 130bf9a7730SZachary Turner 131bf9a7730SZachary Turner { 132bf9a7730SZachary Turner // Now assign the demangled const string as the counterpart of the 133bf9a7730SZachary Turner // mangled const string... 134bf9a7730SZachary Turner const uint8_t h = hash(llvm::StringRef(mangled_ccstr)); 135bf9a7730SZachary Turner llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); 136bf9a7730SZachary Turner GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr); 137bf9a7730SZachary Turner } 138bf9a7730SZachary Turner 139bf9a7730SZachary Turner // Return the constant demangled C string 140bf9a7730SZachary Turner return demangled_ccstr; 141bf9a7730SZachary Turner } 142bf9a7730SZachary Turner return nullptr; 143bf9a7730SZachary Turner } 144bf9a7730SZachary Turner 145bf9a7730SZachary Turner const char *GetConstTrimmedCStringWithLength(const char *cstr, 146bf9a7730SZachary Turner size_t cstr_len) { 147bf9a7730SZachary Turner if (cstr != nullptr) { 148bf9a7730SZachary Turner const size_t trimmed_len = std::min<size_t>(strlen(cstr), cstr_len); 149bf9a7730SZachary Turner return GetConstCStringWithLength(cstr, trimmed_len); 150bf9a7730SZachary Turner } 151bf9a7730SZachary Turner return nullptr; 152bf9a7730SZachary Turner } 153bf9a7730SZachary Turner 154bf9a7730SZachary Turner //------------------------------------------------------------------ 155bf9a7730SZachary Turner // Return the size in bytes that this object and any items in its 156bf9a7730SZachary Turner // collection of uniqued strings + data count values takes in 157bf9a7730SZachary Turner // memory. 158bf9a7730SZachary Turner //------------------------------------------------------------------ 159bf9a7730SZachary Turner size_t MemorySize() const { 160bf9a7730SZachary Turner size_t mem_size = sizeof(Pool); 161bf9a7730SZachary Turner for (const auto &pool : m_string_pools) { 162bf9a7730SZachary Turner llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex); 163bf9a7730SZachary Turner for (const auto &entry : pool.m_string_map) 164bf9a7730SZachary Turner mem_size += sizeof(StringPoolEntryType) + entry.getKey().size(); 165bf9a7730SZachary Turner } 166bf9a7730SZachary Turner return mem_size; 167bf9a7730SZachary Turner } 168bf9a7730SZachary Turner 169bf9a7730SZachary Turner protected: 170bf9a7730SZachary Turner uint8_t hash(const llvm::StringRef &s) const { 171bf9a7730SZachary Turner uint32_t h = llvm::HashString(s); 172bf9a7730SZachary Turner return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff; 173bf9a7730SZachary Turner } 174bf9a7730SZachary Turner 175bf9a7730SZachary Turner struct PoolEntry { 176bf9a7730SZachary Turner mutable llvm::sys::SmartRWMutex<false> m_mutex; 177bf9a7730SZachary Turner StringPool m_string_map; 178bf9a7730SZachary Turner }; 179bf9a7730SZachary Turner 180bf9a7730SZachary Turner std::array<PoolEntry, 256> m_string_pools; 181bf9a7730SZachary Turner }; 182bf9a7730SZachary Turner 183bf9a7730SZachary Turner //---------------------------------------------------------------------- 184bf9a7730SZachary Turner // Frameworks and dylibs aren't supposed to have global C++ 185bf9a7730SZachary Turner // initializers so we hide the string pool in a static function so 186bf9a7730SZachary Turner // that it will get initialized on the first call to this static 187bf9a7730SZachary Turner // function. 188bf9a7730SZachary Turner // 189bf9a7730SZachary Turner // Note, for now we make the string pool a pointer to the pool, because 190bf9a7730SZachary Turner // we can't guarantee that some objects won't get destroyed after the 191bf9a7730SZachary Turner // global destructor chain is run, and trying to make sure no destructors 192bf9a7730SZachary Turner // touch ConstStrings is difficult. So we leak the pool instead. 193bf9a7730SZachary Turner //---------------------------------------------------------------------- 194bf9a7730SZachary Turner static Pool &StringPool() { 195*c5f28e2aSKamil Rytarowski static llvm::once_flag g_pool_initialization_flag; 196bf9a7730SZachary Turner static Pool *g_string_pool = nullptr; 197bf9a7730SZachary Turner 198*c5f28e2aSKamil Rytarowski llvm::call_once(g_pool_initialization_flag, 199bf9a7730SZachary Turner []() { g_string_pool = new Pool(); }); 200bf9a7730SZachary Turner 201bf9a7730SZachary Turner return *g_string_pool; 202bf9a7730SZachary Turner } 203bf9a7730SZachary Turner 204bf9a7730SZachary Turner ConstString::ConstString(const char *cstr) 205bf9a7730SZachary Turner : m_string(StringPool().GetConstCString(cstr)) {} 206bf9a7730SZachary Turner 207bf9a7730SZachary Turner ConstString::ConstString(const char *cstr, size_t cstr_len) 208bf9a7730SZachary Turner : m_string(StringPool().GetConstCStringWithLength(cstr, cstr_len)) {} 209bf9a7730SZachary Turner 210bf9a7730SZachary Turner ConstString::ConstString(const llvm::StringRef &s) 211bf9a7730SZachary Turner : m_string(StringPool().GetConstCStringWithLength(s.data(), s.size())) {} 212bf9a7730SZachary Turner 213bf9a7730SZachary Turner bool ConstString::operator<(const ConstString &rhs) const { 214bf9a7730SZachary Turner if (m_string == rhs.m_string) 215bf9a7730SZachary Turner return false; 216bf9a7730SZachary Turner 217bf9a7730SZachary Turner llvm::StringRef lhs_string_ref(m_string, 218bf9a7730SZachary Turner StringPool().GetConstCStringLength(m_string)); 219bf9a7730SZachary Turner llvm::StringRef rhs_string_ref( 220bf9a7730SZachary Turner rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string)); 221bf9a7730SZachary Turner 222bf9a7730SZachary Turner // If both have valid C strings, then return the comparison 223bf9a7730SZachary Turner if (lhs_string_ref.data() && rhs_string_ref.data()) 224bf9a7730SZachary Turner return lhs_string_ref < rhs_string_ref; 225bf9a7730SZachary Turner 226bf9a7730SZachary Turner // Else one of them was nullptr, so if LHS is nullptr then it is less than 227bf9a7730SZachary Turner return lhs_string_ref.data() == nullptr; 228bf9a7730SZachary Turner } 229bf9a7730SZachary Turner 230bf9a7730SZachary Turner Stream &lldb_private::operator<<(Stream &s, const ConstString &str) { 231bf9a7730SZachary Turner const char *cstr = str.GetCString(); 232bf9a7730SZachary Turner if (cstr != nullptr) 233bf9a7730SZachary Turner s << cstr; 234bf9a7730SZachary Turner 235bf9a7730SZachary Turner return s; 236bf9a7730SZachary Turner } 237bf9a7730SZachary Turner 238bf9a7730SZachary Turner size_t ConstString::GetLength() const { 239bf9a7730SZachary Turner return StringPool().GetConstCStringLength(m_string); 240bf9a7730SZachary Turner } 241bf9a7730SZachary Turner 242bf9a7730SZachary Turner bool ConstString::Equals(const ConstString &lhs, const ConstString &rhs, 243bf9a7730SZachary Turner const bool case_sensitive) { 244bf9a7730SZachary Turner if (lhs.m_string == rhs.m_string) 245bf9a7730SZachary Turner return true; 246bf9a7730SZachary Turner 247bf9a7730SZachary Turner // Since the pointers weren't equal, and identical ConstStrings always have 248bf9a7730SZachary Turner // identical pointers, 249bf9a7730SZachary Turner // the result must be false for case sensitive equality test. 250bf9a7730SZachary Turner if (case_sensitive) 251bf9a7730SZachary Turner return false; 252bf9a7730SZachary Turner 253bf9a7730SZachary Turner // perform case insensitive equality test 254bf9a7730SZachary Turner llvm::StringRef lhs_string_ref( 255bf9a7730SZachary Turner lhs.m_string, StringPool().GetConstCStringLength(lhs.m_string)); 256bf9a7730SZachary Turner llvm::StringRef rhs_string_ref( 257bf9a7730SZachary Turner rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string)); 258bf9a7730SZachary Turner return lhs_string_ref.equals_lower(rhs_string_ref); 259bf9a7730SZachary Turner } 260bf9a7730SZachary Turner 261bf9a7730SZachary Turner int ConstString::Compare(const ConstString &lhs, const ConstString &rhs, 262bf9a7730SZachary Turner const bool case_sensitive) { 263bf9a7730SZachary Turner // If the iterators are the same, this is the same string 264bf9a7730SZachary Turner const char *lhs_cstr = lhs.m_string; 265bf9a7730SZachary Turner const char *rhs_cstr = rhs.m_string; 266bf9a7730SZachary Turner if (lhs_cstr == rhs_cstr) 267bf9a7730SZachary Turner return 0; 268bf9a7730SZachary Turner if (lhs_cstr && rhs_cstr) { 269bf9a7730SZachary Turner llvm::StringRef lhs_string_ref( 270bf9a7730SZachary Turner lhs_cstr, StringPool().GetConstCStringLength(lhs_cstr)); 271bf9a7730SZachary Turner llvm::StringRef rhs_string_ref( 272bf9a7730SZachary Turner rhs_cstr, StringPool().GetConstCStringLength(rhs_cstr)); 273bf9a7730SZachary Turner 274bf9a7730SZachary Turner if (case_sensitive) { 275bf9a7730SZachary Turner return lhs_string_ref.compare(rhs_string_ref); 276bf9a7730SZachary Turner } else { 277bf9a7730SZachary Turner return lhs_string_ref.compare_lower(rhs_string_ref); 278bf9a7730SZachary Turner } 279bf9a7730SZachary Turner } 280bf9a7730SZachary Turner 281bf9a7730SZachary Turner if (lhs_cstr) 282bf9a7730SZachary Turner return +1; // LHS isn't nullptr but RHS is 283bf9a7730SZachary Turner else 284bf9a7730SZachary Turner return -1; // LHS is nullptr but RHS isn't 285bf9a7730SZachary Turner } 286bf9a7730SZachary Turner 287bf9a7730SZachary Turner void ConstString::Dump(Stream *s, const char *fail_value) const { 288bf9a7730SZachary Turner if (s != nullptr) { 289bf9a7730SZachary Turner const char *cstr = AsCString(fail_value); 290bf9a7730SZachary Turner if (cstr != nullptr) 291bf9a7730SZachary Turner s->PutCString(cstr); 292bf9a7730SZachary Turner } 293bf9a7730SZachary Turner } 294bf9a7730SZachary Turner 295bf9a7730SZachary Turner void ConstString::DumpDebug(Stream *s) const { 296bf9a7730SZachary Turner const char *cstr = GetCString(); 297bf9a7730SZachary Turner size_t cstr_len = GetLength(); 298bf9a7730SZachary Turner // Only print the parens if we have a non-nullptr string 299bf9a7730SZachary Turner const char *parens = cstr ? "\"" : ""; 300bf9a7730SZachary Turner s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, 301bf9a7730SZachary Turner static_cast<int>(sizeof(void *) * 2), 302bf9a7730SZachary Turner static_cast<const void *>(this), parens, cstr, parens, 303bf9a7730SZachary Turner static_cast<uint64_t>(cstr_len)); 304bf9a7730SZachary Turner } 305bf9a7730SZachary Turner 306bf9a7730SZachary Turner void ConstString::SetCString(const char *cstr) { 307bf9a7730SZachary Turner m_string = StringPool().GetConstCString(cstr); 308bf9a7730SZachary Turner } 309bf9a7730SZachary Turner 310bf9a7730SZachary Turner void ConstString::SetString(const llvm::StringRef &s) { 311bf9a7730SZachary Turner m_string = StringPool().GetConstCStringWithLength(s.data(), s.size()); 312bf9a7730SZachary Turner } 313bf9a7730SZachary Turner 314bf9a7730SZachary Turner void ConstString::SetCStringWithMangledCounterpart(const char *demangled, 315bf9a7730SZachary Turner const ConstString &mangled) { 316bf9a7730SZachary Turner m_string = StringPool().GetConstCStringAndSetMangledCounterPart( 317bf9a7730SZachary Turner demangled, mangled.m_string); 318bf9a7730SZachary Turner } 319bf9a7730SZachary Turner 320bf9a7730SZachary Turner bool ConstString::GetMangledCounterpart(ConstString &counterpart) const { 321bf9a7730SZachary Turner counterpart.m_string = StringPool().GetMangledCounterpart(m_string); 322bf9a7730SZachary Turner return (bool)counterpart; 323bf9a7730SZachary Turner } 324bf9a7730SZachary Turner 325bf9a7730SZachary Turner void ConstString::SetCStringWithLength(const char *cstr, size_t cstr_len) { 326bf9a7730SZachary Turner m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len); 327bf9a7730SZachary Turner } 328bf9a7730SZachary Turner 329bf9a7730SZachary Turner void ConstString::SetTrimmedCStringWithLength(const char *cstr, 330bf9a7730SZachary Turner size_t cstr_len) { 331bf9a7730SZachary Turner m_string = StringPool().GetConstTrimmedCStringWithLength(cstr, cstr_len); 332bf9a7730SZachary Turner } 333bf9a7730SZachary Turner 334bf9a7730SZachary Turner size_t ConstString::StaticMemorySize() { 335bf9a7730SZachary Turner // Get the size of the static string pool 336bf9a7730SZachary Turner return StringPool().MemorySize(); 337bf9a7730SZachary Turner } 3383b7e1981SPavel Labath 3393b7e1981SPavel Labath void llvm::format_provider<ConstString>::format(const ConstString &CS, 3403b7e1981SPavel Labath llvm::raw_ostream &OS, 3413b7e1981SPavel Labath llvm::StringRef Options) { 3423b7e1981SPavel Labath format_provider<StringRef>::format(CS.AsCString(), OS, Options); 3433b7e1981SPavel Labath } 344