180814287SRaphael Isemann //===-- ConstString.cpp ---------------------------------------------------===//
2bf9a7730SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bf9a7730SZachary Turner //
7bf9a7730SZachary Turner //===----------------------------------------------------------------------===//
8bf9a7730SZachary Turner 
9bf9a7730SZachary Turner #include "lldb/Utility/ConstString.h"
10bf9a7730SZachary Turner 
114479ac15SZachary Turner #include "lldb/Utility/Stream.h"
12bf9a7730SZachary Turner 
13bf9a7730SZachary Turner #include "llvm/ADT/StringMap.h"
14672d2c12SJonas Devlieghere #include "llvm/ADT/iterator.h"
15672d2c12SJonas Devlieghere #include "llvm/Support/Allocator.h"
16672d2c12SJonas Devlieghere #include "llvm/Support/DJB.h"
17672d2c12SJonas Devlieghere #include "llvm/Support/FormatProviders.h"
18bf9a7730SZachary Turner #include "llvm/Support/RWMutex.h"
19c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h"
204479ac15SZachary Turner 
214479ac15SZachary Turner #include <array>
22672d2c12SJonas Devlieghere #include <utility>
234479ac15SZachary Turner 
2476e47d48SRaphael Isemann #include <cinttypes>
2576e47d48SRaphael Isemann #include <cstdint>
2676e47d48SRaphael Isemann #include <cstring>
27bf9a7730SZachary Turner 
28bf9a7730SZachary Turner using namespace lldb_private;
29bf9a7730SZachary Turner 
30bf9a7730SZachary Turner class Pool {
31bf9a7730SZachary Turner public:
32fad012bcSRaphael Isemann   /// The default BumpPtrAllocatorImpl slab size.
33fad012bcSRaphael Isemann   static const size_t AllocatorSlabSize = 4096;
34fad012bcSRaphael Isemann   static const size_t SizeThreshold = AllocatorSlabSize;
35fad012bcSRaphael Isemann   /// Every Pool has its own allocator which receives an equal share of
36fad012bcSRaphael Isemann   /// the ConstString allocations. This means that when allocating many
37fad012bcSRaphael Isemann   /// ConstStrings, every allocator sees only its small share of allocations and
38fad012bcSRaphael Isemann   /// assumes LLDB only allocated a small amount of memory so far. In reality
39fad012bcSRaphael Isemann   /// LLDB allocated a total memory that is N times as large as what the
40fad012bcSRaphael Isemann   /// allocator sees (where N is the number of string pools). This causes that
41fad012bcSRaphael Isemann   /// the BumpPtrAllocator continues a long time to allocate memory in small
42fad012bcSRaphael Isemann   /// chunks which only makes sense when allocating a small amount of memory
43fad012bcSRaphael Isemann   /// (which is true from the perspective of a single allocator). On some
44fad012bcSRaphael Isemann   /// systems doing all these small memory allocations causes LLDB to spend
45fad012bcSRaphael Isemann   /// a lot of time in malloc, so we need to force all these allocators to
46fad012bcSRaphael Isemann   /// behave like one allocator in terms of scaling their memory allocations
47fad012bcSRaphael Isemann   /// with increased demand. To do this we set the growth delay for each single
48fad012bcSRaphael Isemann   /// allocator to a rate so that our pool of allocators scales their memory
49fad012bcSRaphael Isemann   /// allocations similar to a single BumpPtrAllocatorImpl.
50fad012bcSRaphael Isemann   ///
51fad012bcSRaphael Isemann   /// Currently we have 256 string pools and the normal growth delay of the
52fad012bcSRaphael Isemann   /// BumpPtrAllocatorImpl is 128 (i.e., the memory allocation size increases
53fad012bcSRaphael Isemann   /// every 128 full chunks), so by changing the delay to 1 we get a
54fad012bcSRaphael Isemann   /// total growth delay in our allocator collection of 256/1 = 256. This is
55fad012bcSRaphael Isemann   /// still only half as fast as a normal allocator but we can't go any faster
56fad012bcSRaphael Isemann   /// without decreasing the number of string pools.
57fad012bcSRaphael Isemann   static const size_t AllocatorGrowthDelay = 1;
58fad012bcSRaphael Isemann   typedef llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, AllocatorSlabSize,
59fad012bcSRaphael Isemann                                      SizeThreshold, AllocatorGrowthDelay>
60fad012bcSRaphael Isemann       Allocator;
61bf9a7730SZachary Turner   typedef const char *StringPoolValueType;
62fad012bcSRaphael Isemann   typedef llvm::StringMap<StringPoolValueType, Allocator> StringPool;
63bf9a7730SZachary Turner   typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
64bf9a7730SZachary Turner 
65bf9a7730SZachary Turner   static StringPoolEntryType &
66bf9a7730SZachary Turner   GetStringMapEntryFromKeyData(const char *keyData) {
678070bf0aSPavel Labath     return StringPoolEntryType::GetStringMapEntryFromKeyData(keyData);
68bf9a7730SZachary Turner   }
69bf9a7730SZachary Turner 
708070bf0aSPavel Labath   static size_t GetConstCStringLength(const char *ccstr) {
71bf9a7730SZachary Turner     if (ccstr != nullptr) {
7205097246SAdrian Prantl       // Since the entry is read only, and we derive the entry entirely from
7305097246SAdrian Prantl       // the pointer, we don't need the lock.
74bf9a7730SZachary Turner       const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr);
75bf9a7730SZachary Turner       return entry.getKey().size();
76bf9a7730SZachary Turner     }
77bf9a7730SZachary Turner     return 0;
78bf9a7730SZachary Turner   }
79bf9a7730SZachary Turner 
80bf9a7730SZachary Turner   StringPoolValueType GetMangledCounterpart(const char *ccstr) const {
81bf9a7730SZachary Turner     if (ccstr != nullptr) {
82bf9a7730SZachary Turner       const uint8_t h = hash(llvm::StringRef(ccstr));
83bf9a7730SZachary Turner       llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
84bf9a7730SZachary Turner       return GetStringMapEntryFromKeyData(ccstr).getValue();
85bf9a7730SZachary Turner     }
86bf9a7730SZachary Turner     return nullptr;
87bf9a7730SZachary Turner   }
88bf9a7730SZachary Turner 
89bf9a7730SZachary Turner   const char *GetConstCString(const char *cstr) {
90bf9a7730SZachary Turner     if (cstr != nullptr)
91bf9a7730SZachary Turner       return GetConstCStringWithLength(cstr, strlen(cstr));
92bf9a7730SZachary Turner     return nullptr;
93bf9a7730SZachary Turner   }
94bf9a7730SZachary Turner 
95bf9a7730SZachary Turner   const char *GetConstCStringWithLength(const char *cstr, size_t cstr_len) {
96bf9a7730SZachary Turner     if (cstr != nullptr)
97bf9a7730SZachary Turner       return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len));
98bf9a7730SZachary Turner     return nullptr;
99bf9a7730SZachary Turner   }
100bf9a7730SZachary Turner 
101bf9a7730SZachary Turner   const char *GetConstCStringWithStringRef(const llvm::StringRef &string_ref) {
102bf9a7730SZachary Turner     if (string_ref.data()) {
103bf9a7730SZachary Turner       const uint8_t h = hash(string_ref);
104bf9a7730SZachary Turner 
105bf9a7730SZachary Turner       {
106bf9a7730SZachary Turner         llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
107bf9a7730SZachary Turner         auto it = m_string_pools[h].m_string_map.find(string_ref);
108bf9a7730SZachary Turner         if (it != m_string_pools[h].m_string_map.end())
109bf9a7730SZachary Turner           return it->getKeyData();
110bf9a7730SZachary Turner       }
111bf9a7730SZachary Turner 
112bf9a7730SZachary Turner       llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
113bf9a7730SZachary Turner       StringPoolEntryType &entry =
114bf9a7730SZachary Turner           *m_string_pools[h]
115bf9a7730SZachary Turner                .m_string_map.insert(std::make_pair(string_ref, nullptr))
116bf9a7730SZachary Turner                .first;
117bf9a7730SZachary Turner       return entry.getKeyData();
118bf9a7730SZachary Turner     }
119bf9a7730SZachary Turner     return nullptr;
120bf9a7730SZachary Turner   }
121bf9a7730SZachary Turner 
122bf9a7730SZachary Turner   const char *
12319a357adSPavel Labath   GetConstCStringAndSetMangledCounterPart(llvm::StringRef demangled,
124bf9a7730SZachary Turner                                           const char *mangled_ccstr) {
125bf9a7730SZachary Turner     const char *demangled_ccstr = nullptr;
126bf9a7730SZachary Turner 
127bf9a7730SZachary Turner     {
12819a357adSPavel Labath       const uint8_t h = hash(demangled);
129bf9a7730SZachary Turner       llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
130bf9a7730SZachary Turner 
1312397a2b6SStefan Granitz       // Make or update string pool entry with the mangled counterpart
1322397a2b6SStefan Granitz       StringPool &map = m_string_pools[h].m_string_map;
1332397a2b6SStefan Granitz       StringPoolEntryType &entry = *map.try_emplace(demangled).first;
1342397a2b6SStefan Granitz 
1352397a2b6SStefan Granitz       entry.second = mangled_ccstr;
136bf9a7730SZachary Turner 
137bf9a7730SZachary Turner       // Extract the const version of the demangled_cstr
138bf9a7730SZachary Turner       demangled_ccstr = entry.getKeyData();
139bf9a7730SZachary Turner     }
140bf9a7730SZachary Turner 
141bf9a7730SZachary Turner     {
142bf9a7730SZachary Turner       // Now assign the demangled const string as the counterpart of the
143bf9a7730SZachary Turner       // mangled const string...
144bf9a7730SZachary Turner       const uint8_t h = hash(llvm::StringRef(mangled_ccstr));
145bf9a7730SZachary Turner       llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
146bf9a7730SZachary Turner       GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr);
147bf9a7730SZachary Turner     }
148bf9a7730SZachary Turner 
149bf9a7730SZachary Turner     // Return the constant demangled C string
150bf9a7730SZachary Turner     return demangled_ccstr;
151bf9a7730SZachary Turner   }
152bf9a7730SZachary Turner 
153bf9a7730SZachary Turner   const char *GetConstTrimmedCStringWithLength(const char *cstr,
154bf9a7730SZachary Turner                                                size_t cstr_len) {
155bf9a7730SZachary Turner     if (cstr != nullptr) {
156bb3609e4SJan Kratochvil       const size_t trimmed_len = strnlen(cstr, cstr_len);
157bf9a7730SZachary Turner       return GetConstCStringWithLength(cstr, trimmed_len);
158bf9a7730SZachary Turner     }
159bf9a7730SZachary Turner     return nullptr;
160bf9a7730SZachary Turner   }
161bf9a7730SZachary Turner 
16205097246SAdrian Prantl   // Return the size in bytes that this object and any items in its collection
16305097246SAdrian Prantl   // of uniqued strings + data count values takes in memory.
164bf9a7730SZachary Turner   size_t MemorySize() const {
165bf9a7730SZachary Turner     size_t mem_size = sizeof(Pool);
166bf9a7730SZachary Turner     for (const auto &pool : m_string_pools) {
167bf9a7730SZachary Turner       llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
168bf9a7730SZachary Turner       for (const auto &entry : pool.m_string_map)
169bf9a7730SZachary Turner         mem_size += sizeof(StringPoolEntryType) + entry.getKey().size();
170bf9a7730SZachary Turner     }
171bf9a7730SZachary Turner     return mem_size;
172bf9a7730SZachary Turner   }
173bf9a7730SZachary Turner 
174*cd8122b2SJonas Devlieghere   ConstString::MemoryStats GetMemoryStats() const {
175*cd8122b2SJonas Devlieghere     ConstString::MemoryStats stats;
176*cd8122b2SJonas Devlieghere     for (const auto &pool : m_string_pools) {
177*cd8122b2SJonas Devlieghere       llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
178*cd8122b2SJonas Devlieghere       const Allocator &alloc = pool.m_string_map.getAllocator();
179*cd8122b2SJonas Devlieghere       stats.bytes_total += alloc.getTotalMemory();
180*cd8122b2SJonas Devlieghere       stats.bytes_used += alloc.getBytesAllocated();
181*cd8122b2SJonas Devlieghere     }
182*cd8122b2SJonas Devlieghere     return stats;
183*cd8122b2SJonas Devlieghere   }
184*cd8122b2SJonas Devlieghere 
185bf9a7730SZachary Turner protected:
186bf9a7730SZachary Turner   uint8_t hash(const llvm::StringRef &s) const {
187560ce2c7SJonas Devlieghere     uint32_t h = llvm::djbHash(s);
188bf9a7730SZachary Turner     return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff;
189bf9a7730SZachary Turner   }
190bf9a7730SZachary Turner 
191bf9a7730SZachary Turner   struct PoolEntry {
192bf9a7730SZachary Turner     mutable llvm::sys::SmartRWMutex<false> m_mutex;
193755420c0SRaphael Isemann     StringPool m_string_map;
194bf9a7730SZachary Turner   };
195bf9a7730SZachary Turner 
196bf9a7730SZachary Turner   std::array<PoolEntry, 256> m_string_pools;
197bf9a7730SZachary Turner };
198bf9a7730SZachary Turner 
19905097246SAdrian Prantl // Frameworks and dylibs aren't supposed to have global C++ initializers so we
20005097246SAdrian Prantl // hide the string pool in a static function so that it will get initialized on
20105097246SAdrian Prantl // the first call to this static function.
202bf9a7730SZachary Turner //
20305097246SAdrian Prantl // Note, for now we make the string pool a pointer to the pool, because we
20405097246SAdrian Prantl // can't guarantee that some objects won't get destroyed after the global
20505097246SAdrian Prantl // destructor chain is run, and trying to make sure no destructors touch
20605097246SAdrian Prantl // ConstStrings is difficult.  So we leak the pool instead.
207bf9a7730SZachary Turner static Pool &StringPool() {
208c5f28e2aSKamil Rytarowski   static llvm::once_flag g_pool_initialization_flag;
209bf9a7730SZachary Turner   static Pool *g_string_pool = nullptr;
210bf9a7730SZachary Turner 
211c5f28e2aSKamil Rytarowski   llvm::call_once(g_pool_initialization_flag,
212bf9a7730SZachary Turner                  []() { g_string_pool = new Pool(); });
213bf9a7730SZachary Turner 
214bf9a7730SZachary Turner   return *g_string_pool;
215bf9a7730SZachary Turner }
216bf9a7730SZachary Turner 
217bf9a7730SZachary Turner ConstString::ConstString(const char *cstr)
218bf9a7730SZachary Turner     : m_string(StringPool().GetConstCString(cstr)) {}
219bf9a7730SZachary Turner 
220bf9a7730SZachary Turner ConstString::ConstString(const char *cstr, size_t cstr_len)
221bf9a7730SZachary Turner     : m_string(StringPool().GetConstCStringWithLength(cstr, cstr_len)) {}
222bf9a7730SZachary Turner 
223bf9a7730SZachary Turner ConstString::ConstString(const llvm::StringRef &s)
22412886f04SRaphael Isemann     : m_string(StringPool().GetConstCStringWithStringRef(s)) {}
225bf9a7730SZachary Turner 
226ccdb5b4bSJonas Devlieghere bool ConstString::operator<(ConstString rhs) const {
227bf9a7730SZachary Turner   if (m_string == rhs.m_string)
228bf9a7730SZachary Turner     return false;
229bf9a7730SZachary Turner 
2308070bf0aSPavel Labath   llvm::StringRef lhs_string_ref(GetStringRef());
2318070bf0aSPavel Labath   llvm::StringRef rhs_string_ref(rhs.GetStringRef());
232bf9a7730SZachary Turner 
233bf9a7730SZachary Turner   // If both have valid C strings, then return the comparison
234bf9a7730SZachary Turner   if (lhs_string_ref.data() && rhs_string_ref.data())
235bf9a7730SZachary Turner     return lhs_string_ref < rhs_string_ref;
236bf9a7730SZachary Turner 
237bf9a7730SZachary Turner   // Else one of them was nullptr, so if LHS is nullptr then it is less than
238bf9a7730SZachary Turner   return lhs_string_ref.data() == nullptr;
239bf9a7730SZachary Turner }
240bf9a7730SZachary Turner 
241ccdb5b4bSJonas Devlieghere Stream &lldb_private::operator<<(Stream &s, ConstString str) {
242bf9a7730SZachary Turner   const char *cstr = str.GetCString();
243bf9a7730SZachary Turner   if (cstr != nullptr)
244bf9a7730SZachary Turner     s << cstr;
245bf9a7730SZachary Turner 
246bf9a7730SZachary Turner   return s;
247bf9a7730SZachary Turner }
248bf9a7730SZachary Turner 
249bf9a7730SZachary Turner size_t ConstString::GetLength() const {
2508070bf0aSPavel Labath   return Pool::GetConstCStringLength(m_string);
251bf9a7730SZachary Turner }
252bf9a7730SZachary Turner 
253ccdb5b4bSJonas Devlieghere bool ConstString::Equals(ConstString lhs, ConstString rhs,
254bf9a7730SZachary Turner                          const bool case_sensitive) {
255bf9a7730SZachary Turner   if (lhs.m_string == rhs.m_string)
256bf9a7730SZachary Turner     return true;
257bf9a7730SZachary Turner 
258bf9a7730SZachary Turner   // Since the pointers weren't equal, and identical ConstStrings always have
25905097246SAdrian Prantl   // identical pointers, the result must be false for case sensitive equality
26005097246SAdrian Prantl   // test.
261bf9a7730SZachary Turner   if (case_sensitive)
262bf9a7730SZachary Turner     return false;
263bf9a7730SZachary Turner 
264bf9a7730SZachary Turner   // perform case insensitive equality test
2658070bf0aSPavel Labath   llvm::StringRef lhs_string_ref(lhs.GetStringRef());
2668070bf0aSPavel Labath   llvm::StringRef rhs_string_ref(rhs.GetStringRef());
267e50f9c41SMartin Storsjö   return lhs_string_ref.equals_insensitive(rhs_string_ref);
268bf9a7730SZachary Turner }
269bf9a7730SZachary Turner 
270ccdb5b4bSJonas Devlieghere int ConstString::Compare(ConstString lhs, ConstString rhs,
271bf9a7730SZachary Turner                          const bool case_sensitive) {
272bf9a7730SZachary Turner   // If the iterators are the same, this is the same string
273bf9a7730SZachary Turner   const char *lhs_cstr = lhs.m_string;
274bf9a7730SZachary Turner   const char *rhs_cstr = rhs.m_string;
275bf9a7730SZachary Turner   if (lhs_cstr == rhs_cstr)
276bf9a7730SZachary Turner     return 0;
277bf9a7730SZachary Turner   if (lhs_cstr && rhs_cstr) {
2788070bf0aSPavel Labath     llvm::StringRef lhs_string_ref(lhs.GetStringRef());
2798070bf0aSPavel Labath     llvm::StringRef rhs_string_ref(rhs.GetStringRef());
280bf9a7730SZachary Turner 
281bf9a7730SZachary Turner     if (case_sensitive) {
282bf9a7730SZachary Turner       return lhs_string_ref.compare(rhs_string_ref);
283bf9a7730SZachary Turner     } else {
284e50f9c41SMartin Storsjö       return lhs_string_ref.compare_insensitive(rhs_string_ref);
285bf9a7730SZachary Turner     }
286bf9a7730SZachary Turner   }
287bf9a7730SZachary Turner 
288bf9a7730SZachary Turner   if (lhs_cstr)
289bf9a7730SZachary Turner     return +1; // LHS isn't nullptr but RHS is
290bf9a7730SZachary Turner   else
291bf9a7730SZachary Turner     return -1; // LHS is nullptr but RHS isn't
292bf9a7730SZachary Turner }
293bf9a7730SZachary Turner 
294bf9a7730SZachary Turner void ConstString::Dump(Stream *s, const char *fail_value) const {
295bf9a7730SZachary Turner   if (s != nullptr) {
296bf9a7730SZachary Turner     const char *cstr = AsCString(fail_value);
297bf9a7730SZachary Turner     if (cstr != nullptr)
298bf9a7730SZachary Turner       s->PutCString(cstr);
299bf9a7730SZachary Turner   }
300bf9a7730SZachary Turner }
301bf9a7730SZachary Turner 
302bf9a7730SZachary Turner void ConstString::DumpDebug(Stream *s) const {
303bf9a7730SZachary Turner   const char *cstr = GetCString();
304bf9a7730SZachary Turner   size_t cstr_len = GetLength();
305bf9a7730SZachary Turner   // Only print the parens if we have a non-nullptr string
306bf9a7730SZachary Turner   const char *parens = cstr ? "\"" : "";
307bf9a7730SZachary Turner   s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64,
308bf9a7730SZachary Turner             static_cast<int>(sizeof(void *) * 2),
309bf9a7730SZachary Turner             static_cast<const void *>(this), parens, cstr, parens,
310bf9a7730SZachary Turner             static_cast<uint64_t>(cstr_len));
311bf9a7730SZachary Turner }
312bf9a7730SZachary Turner 
313bf9a7730SZachary Turner void ConstString::SetCString(const char *cstr) {
314bf9a7730SZachary Turner   m_string = StringPool().GetConstCString(cstr);
315bf9a7730SZachary Turner }
316bf9a7730SZachary Turner 
317bf9a7730SZachary Turner void ConstString::SetString(const llvm::StringRef &s) {
318bf9a7730SZachary Turner   m_string = StringPool().GetConstCStringWithLength(s.data(), s.size());
319bf9a7730SZachary Turner }
320bf9a7730SZachary Turner 
32119a357adSPavel Labath void ConstString::SetStringWithMangledCounterpart(llvm::StringRef demangled,
322ccdb5b4bSJonas Devlieghere                                                   ConstString mangled) {
323bf9a7730SZachary Turner   m_string = StringPool().GetConstCStringAndSetMangledCounterPart(
324bf9a7730SZachary Turner       demangled, mangled.m_string);
325bf9a7730SZachary Turner }
326bf9a7730SZachary Turner 
327bf9a7730SZachary Turner bool ConstString::GetMangledCounterpart(ConstString &counterpart) const {
328bf9a7730SZachary Turner   counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
329bf9a7730SZachary Turner   return (bool)counterpart;
330bf9a7730SZachary Turner }
331bf9a7730SZachary Turner 
332bf9a7730SZachary Turner void ConstString::SetCStringWithLength(const char *cstr, size_t cstr_len) {
333bf9a7730SZachary Turner   m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
334bf9a7730SZachary Turner }
335bf9a7730SZachary Turner 
336bf9a7730SZachary Turner void ConstString::SetTrimmedCStringWithLength(const char *cstr,
337bf9a7730SZachary Turner                                               size_t cstr_len) {
338bf9a7730SZachary Turner   m_string = StringPool().GetConstTrimmedCStringWithLength(cstr, cstr_len);
339bf9a7730SZachary Turner }
340bf9a7730SZachary Turner 
341bf9a7730SZachary Turner size_t ConstString::StaticMemorySize() {
342bf9a7730SZachary Turner   // Get the size of the static string pool
343bf9a7730SZachary Turner   return StringPool().MemorySize();
344bf9a7730SZachary Turner }
3453b7e1981SPavel Labath 
346*cd8122b2SJonas Devlieghere ConstString::MemoryStats ConstString::GetMemoryStats() {
347*cd8122b2SJonas Devlieghere   return StringPool().GetMemoryStats();
348*cd8122b2SJonas Devlieghere }
349*cd8122b2SJonas Devlieghere 
3503b7e1981SPavel Labath void llvm::format_provider<ConstString>::format(const ConstString &CS,
3513b7e1981SPavel Labath                                                 llvm::raw_ostream &OS,
3523b7e1981SPavel Labath                                                 llvm::StringRef Options) {
353642bc15dSRaphael Isemann   format_provider<StringRef>::format(CS.GetStringRef(), OS, Options);
3543b7e1981SPavel Labath }
355bc9b6b33SJonas Devlieghere 
356bc9b6b33SJonas Devlieghere void llvm::yaml::ScalarTraits<ConstString>::output(const ConstString &Val,
357bc9b6b33SJonas Devlieghere                                                    void *, raw_ostream &Out) {
358bc9b6b33SJonas Devlieghere   Out << Val.GetStringRef();
359bc9b6b33SJonas Devlieghere }
360bc9b6b33SJonas Devlieghere 
361bc9b6b33SJonas Devlieghere llvm::StringRef
362bc9b6b33SJonas Devlieghere llvm::yaml::ScalarTraits<ConstString>::input(llvm::StringRef Scalar, void *,
363bc9b6b33SJonas Devlieghere                                              ConstString &Val) {
364bc9b6b33SJonas Devlieghere   Val = ConstString(Scalar);
365bc9b6b33SJonas Devlieghere   return {};
366bc9b6b33SJonas Devlieghere }
367