Skip to content

Commit a5a2a5a

Browse files
committed
[lldb][NFCI] Remove use of ConstString in StructuredData
The remaining use of ConstString in StructuredData is the Dictionary class. Internally it's backed by a `std::map<ConstString, ObjectSP>`. I propose that we replace it with a `llvm::StringMap<ObjectSP>`. Many StructuredData::Dictionary objects are ephemeral and only exist for a short amount of time. Many of these Dictionaries are only produced once and are never used again. That leaves us with a lot of string data in the ConstString StringPool that is sitting there never to be used again. Even if the same string is used many times for keys of different Dictionary objects, that is something we can measure and adjust for instead of assuming that every key may be reused at some point in the future. Quick comparisons of key data is likely not a concern with Dictionary, but the use of `llvm::StringMap` means that lookups should be fast with its hashing strategy. Switching to a llvm::StringMap meant that the iteration order may be different. To account for this when serializing/dumping the dictionary, I added some code to sort the output by key before emitting anything. Differential Revision: https://reviews.llvm.org/D159313
1 parent e2d39f7 commit a5a2a5a

File tree

6 files changed

+62
-58
lines changed

6 files changed

+62
-58
lines changed

lldb/include/lldb/Utility/StructuredData.h

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
#ifndef LLDB_UTILITY_STRUCTUREDDATA_H
1010
#define LLDB_UTILITY_STRUCTUREDDATA_H
1111

12+
#include "llvm/ADT/StringMap.h"
1213
#include "llvm/ADT/StringRef.h"
1314
#include "llvm/Support/JSON.h"
1415

15-
#include "lldb/Utility/ConstString.h"
1616
#include "lldb/Utility/FileSpec.h"
1717
#include "lldb/Utility/Stream.h"
1818
#include "lldb/lldb-enumerations.h"
@@ -423,34 +423,25 @@ class StructuredData {
423423

424424
size_t GetSize() const { return m_dict.size(); }
425425

426-
void ForEach(std::function<bool(ConstString key, Object *object)> const
426+
void ForEach(std::function<bool(llvm::StringRef key, Object *object)> const
427427
&callback) const {
428428
for (const auto &pair : m_dict) {
429-
if (!callback(pair.first, pair.second.get()))
429+
if (!callback(pair.first(), pair.second.get()))
430430
break;
431431
}
432432
}
433433

434434
ArraySP GetKeys() const {
435435
auto array_sp = std::make_shared<Array>();
436-
collection::const_iterator iter;
437-
for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) {
438-
auto key_object_sp = std::make_shared<String>();
439-
key_object_sp->SetValue(iter->first.AsCString());
436+
for (auto iter = m_dict.begin(); iter != m_dict.end(); ++iter) {
437+
auto key_object_sp = std::make_shared<String>(iter->first());
440438
array_sp->Push(key_object_sp);
441439
}
442440
return array_sp;
443441
}
444442

445443
ObjectSP GetValueForKey(llvm::StringRef key) const {
446-
ObjectSP value_sp;
447-
if (!key.empty()) {
448-
ConstString key_cs(key);
449-
collection::const_iterator iter = m_dict.find(key_cs);
450-
if (iter != m_dict.end())
451-
value_sp = iter->second;
452-
}
453-
return value_sp;
444+
return m_dict.lookup(key);
454445
}
455446

456447
bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const {
@@ -539,15 +530,10 @@ class StructuredData {
539530
return false;
540531
}
541532

542-
bool HasKey(llvm::StringRef key) const {
543-
ConstString key_cs(key);
544-
collection::const_iterator search = m_dict.find(key_cs);
545-
return search != m_dict.end();
546-
}
533+
bool HasKey(llvm::StringRef key) const { return m_dict.contains(key); }
547534

548535
void AddItem(llvm::StringRef key, ObjectSP value_sp) {
549-
ConstString key_cs(key);
550-
m_dict[key_cs] = std::move(value_sp);
536+
m_dict.insert_or_assign(key, std::move(value_sp));
551537
}
552538

553539
template <typename T> void AddIntegerItem(llvm::StringRef key, T value) {
@@ -577,8 +563,7 @@ class StructuredData {
577563
void GetDescription(lldb_private::Stream &s) const override;
578564

579565
protected:
580-
typedef std::map<ConstString, ObjectSP> collection;
581-
collection m_dict;
566+
llvm::StringMap<ObjectSP> m_dict;
582567
};
583568

584569
class Null : public Object {

lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ PlatformDarwin::ExtractAppSpecificInfo(Process &process) {
989989
StructuredData::DictionarySP dict_sp =
990990
std::make_shared<StructuredData::Dictionary>();
991991

992-
auto flatten_asi_dict = [&dict_sp](ConstString key,
992+
auto flatten_asi_dict = [&dict_sp](llvm::StringRef key,
993993
StructuredData::Object *val) -> bool {
994994
if (!val)
995995
return false;
@@ -998,7 +998,7 @@ PlatformDarwin::ExtractAppSpecificInfo(Process &process) {
998998
if (!arr || !arr->GetSize())
999999
return false;
10001000

1001-
dict_sp->AddItem(key.AsCString(), arr->GetItemAtIndex(0));
1001+
dict_sp->AddItem(key, arr->GetItemAtIndex(0));
10021002
return true;
10031003
};
10041004

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,24 +1926,23 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
19261926

19271927
lldb::ThreadSP
19281928
ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
1929-
static ConstString g_key_tid("tid");
1930-
static ConstString g_key_name("name");
1931-
static ConstString g_key_reason("reason");
1932-
static ConstString g_key_metype("metype");
1933-
static ConstString g_key_medata("medata");
1934-
static ConstString g_key_qaddr("qaddr");
1935-
static ConstString g_key_dispatch_queue_t("dispatch_queue_t");
1936-
static ConstString g_key_associated_with_dispatch_queue(
1929+
static constexpr llvm::StringLiteral g_key_tid("tid");
1930+
static constexpr llvm::StringLiteral g_key_name("name");
1931+
static constexpr llvm::StringLiteral g_key_reason("reason");
1932+
static constexpr llvm::StringLiteral g_key_metype("metype");
1933+
static constexpr llvm::StringLiteral g_key_medata("medata");
1934+
static constexpr llvm::StringLiteral g_key_qaddr("qaddr");
1935+
static constexpr llvm::StringLiteral g_key_dispatch_queue_t(
1936+
"dispatch_queue_t");
1937+
static constexpr llvm::StringLiteral g_key_associated_with_dispatch_queue(
19371938
"associated_with_dispatch_queue");
1938-
static ConstString g_key_queue_name("qname");
1939-
static ConstString g_key_queue_kind("qkind");
1940-
static ConstString g_key_queue_serial_number("qserialnum");
1941-
static ConstString g_key_registers("registers");
1942-
static ConstString g_key_memory("memory");
1943-
static ConstString g_key_address("address");
1944-
static ConstString g_key_bytes("bytes");
1945-
static ConstString g_key_description("description");
1946-
static ConstString g_key_signal("signal");
1939+
static constexpr llvm::StringLiteral g_key_queue_name("qname");
1940+
static constexpr llvm::StringLiteral g_key_queue_kind("qkind");
1941+
static constexpr llvm::StringLiteral g_key_queue_serial_number("qserialnum");
1942+
static constexpr llvm::StringLiteral g_key_registers("registers");
1943+
static constexpr llvm::StringLiteral g_key_memory("memory");
1944+
static constexpr llvm::StringLiteral g_key_description("description");
1945+
static constexpr llvm::StringLiteral g_key_signal("signal");
19471946

19481947
// Stop with signal and thread info
19491948
lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
@@ -1971,7 +1970,7 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
19711970
&thread_dispatch_qaddr, &queue_vars_valid,
19721971
&associated_with_dispatch_queue, &dispatch_queue_t,
19731972
&queue_name, &queue_kind, &queue_serial_number](
1974-
ConstString key,
1973+
llvm::StringRef key,
19751974
StructuredData::Object *object) -> bool {
19761975
if (key == g_key_tid) {
19771976
// thread in big endian hex
@@ -2029,10 +2028,10 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
20292028

20302029
if (registers_dict) {
20312030
registers_dict->ForEach(
2032-
[&expedited_register_map](ConstString key,
2031+
[&expedited_register_map](llvm::StringRef key,
20332032
StructuredData::Object *object) -> bool {
20342033
uint32_t reg;
2035-
if (llvm::to_integer(key.AsCString(), reg))
2034+
if (llvm::to_integer(key, reg))
20362035
expedited_register_map[reg] =
20372036
std::string(object->GetStringValue());
20382037
return true; // Keep iterating through all array items

lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp,
224224
[&module_sp, new_style_source_remapping_dictionary,
225225
original_DBGSourcePath_value,
226226
do_truncate_remapping_names](
227-
ConstString key,
227+
llvm::StringRef key,
228228
StructuredData::Object *object) -> bool {
229229
if (object && object->GetAsString()) {
230230

@@ -237,15 +237,15 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp,
237237
DBGSourcePath = original_DBGSourcePath_value;
238238
}
239239
module_sp->GetSourceMappingList().Append(
240-
key.GetStringRef(), DBGSourcePath, true);
240+
key, DBGSourcePath, true);
241241
// With version 2 of DBGSourcePathRemapping, we
242242
// can chop off the last two filename parts
243243
// from the source remapping and get a more
244244
// general source remapping that still works.
245245
// Add this as another option in addition to
246246
// the full source path remap.
247247
if (do_truncate_remapping_names) {
248-
FileSpec build_path(key.AsCString());
248+
FileSpec build_path(key);
249249
FileSpec source_path(DBGSourcePath.c_str());
250250
build_path.RemoveLastPathComponent();
251251
build_path.RemoveLastPathComponent();

lldb/source/Target/Target.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3859,11 +3859,10 @@ void Target::StopHookScripted::GetSubclassDescription(
38593859
s.Indent("Args:\n");
38603860
s.SetIndentLevel(s.GetIndentLevel() + 4);
38613861

3862-
auto print_one_element = [&s](ConstString key,
3862+
auto print_one_element = [&s](llvm::StringRef key,
38633863
StructuredData::Object *object) {
38643864
s.Indent();
3865-
s.Printf("%s : %s\n", key.GetCString(),
3866-
object->GetStringValue().str().c_str());
3865+
s.Format("{0} : {1}\n", key, object->GetStringValue());
38673866
return true;
38683867
};
38693868

lldb/source/Utility/StructuredData.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,18 @@ void StructuredData::String::Serialize(json::OStream &s) const {
162162

163163
void StructuredData::Dictionary::Serialize(json::OStream &s) const {
164164
s.objectBegin();
165-
for (const auto &pair : m_dict) {
166-
s.attributeBegin(pair.first.GetStringRef());
165+
166+
// To ensure the output format is always stable, we sort the dictionary by key
167+
// first.
168+
using Entry = std::pair<llvm::StringRef, ObjectSP>;
169+
std::vector<Entry> sorted_entries;
170+
for (const auto &pair : m_dict)
171+
sorted_entries.push_back({pair.first(), pair.second});
172+
173+
llvm::sort(sorted_entries);
174+
175+
for (const auto &pair : sorted_entries) {
176+
s.attributeBegin(pair.first);
167177
pair.second->Serialize(s);
168178
s.attributeEnd();
169179
}
@@ -228,17 +238,28 @@ void StructuredData::Array::GetDescription(lldb_private::Stream &s) const {
228238

229239
void StructuredData::Dictionary::GetDescription(lldb_private::Stream &s) const {
230240
size_t indentation_level = s.GetIndentLevel();
231-
for (auto iter = m_dict.begin(); iter != m_dict.end(); iter++) {
241+
242+
// To ensure the output format is always stable, we sort the dictionary by key
243+
// first.
244+
using Entry = std::pair<llvm::StringRef, ObjectSP>;
245+
std::vector<Entry> sorted_entries;
246+
for (const auto &pair : m_dict)
247+
sorted_entries.push_back({pair.first(), pair.second});
248+
249+
llvm::sort(sorted_entries);
250+
251+
for (auto iter = sorted_entries.begin(); iter != sorted_entries.end();
252+
iter++) {
232253
// Sanitize.
233-
if (iter->first.IsNull() || iter->first.IsEmpty() || !iter->second)
254+
if (iter->first.empty() || !iter->second)
234255
continue;
235256

236257
// Reset original indentation level.
237258
s.SetIndentLevel(indentation_level);
238259
s.Indent();
239260

240261
// Print key.
241-
s.Printf("%s:", iter->first.AsCString());
262+
s.Format("{0}:", iter->first);
242263

243264
// Return to new line and increase indentation if value is record type.
244265
// Otherwise add spacing.
@@ -252,7 +273,7 @@ void StructuredData::Dictionary::GetDescription(lldb_private::Stream &s) const {
252273

253274
// Print value and new line if now last pair.
254275
iter->second->GetDescription(s);
255-
if (std::next(iter) != m_dict.end())
276+
if (std::next(iter) != sorted_entries.end())
256277
s.EOL();
257278

258279
// Reset indentation level if it was incremented previously.

0 commit comments

Comments
 (0)