Skip to content

Commit bd1b3d4

Browse files
authored
[lldb] Reduce size of Mangled class (llvm#200181)
The Mangled class is used in several places in LLDB, most notably as a direct member of Symbol. This makes this class one of the most frequently long-lived allocations in LLDB. In commit a267225 , this class got a (large) cache that stores information about demangled data. This cache is stored in a std::optional member, which means the memory for the class is allocated within our Mangled object. It should be noted that this cache is only used when we actually demangle the name, which doesn't happen for every mangled name we encounter. The additional cache member caused that the size of Mangled went from 16B to 152B by default (that is, even if the Mangled name was never demangled). This patch replaces the std::optional with a unique_ptr which stores the cache on first use in a separate heap allocation. This changes decreases the amount of allocated memory when debugging a relatively small Objective-C project from 1.57GiB to 1.18GiB (-400MiB).
1 parent 919f72a commit bd1b3d4

4 files changed

Lines changed: 52 additions & 28 deletions

File tree

lldb/include/lldb/Core/Mangled.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,28 @@ class Mangled {
5353
/// Initialize with both mangled and demangled names empty.
5454
Mangled() = default;
5555

56+
Mangled(const Mangled &other)
57+
: m_mangled(other.m_mangled), m_demangled(other.m_demangled),
58+
m_demangled_info(
59+
other.m_demangled_info
60+
? std::make_unique<DemangledNameInfo>(*other.m_demangled_info)
61+
: nullptr) {}
62+
63+
Mangled &operator=(const Mangled &other) {
64+
if (this != &other) {
65+
m_mangled = other.m_mangled;
66+
m_demangled = other.m_demangled;
67+
m_demangled_info =
68+
other.m_demangled_info
69+
? std::make_unique<DemangledNameInfo>(*other.m_demangled_info)
70+
: nullptr;
71+
}
72+
return *this;
73+
}
74+
75+
Mangled(Mangled &&) = default;
76+
Mangled &operator=(Mangled &&) = default;
77+
5678
/// Construct with name.
5779
///
5880
/// Constructor with an optional string and auto-detect if \a name is
@@ -279,7 +301,7 @@ class Mangled {
279301
void Encode(DataEncoder &encoder, ConstStringTable &strtab) const;
280302

281303
/// Retrieve \c DemangledNameInfo of the demangled name held by this object.
282-
const std::optional<DemangledNameInfo> &GetDemangledInfo() const;
304+
const DemangledNameInfo *GetDemangledInfo() const;
283305

284306
/// Compute the base name (without namespace/class qualifiers) from the
285307
/// demangled name.
@@ -308,7 +330,7 @@ class Mangled {
308330

309331
/// If available, holds information about where in \c m_demangled certain
310332
/// parts of the name (e.g., basename, arguments, etc.) begin and end.
311-
mutable std::optional<DemangledNameInfo> m_demangled_info = std::nullopt;
333+
mutable std::unique_ptr<DemangledNameInfo> m_demangled_info;
312334
};
313335

314336
Stream &operator<<(Stream &s, const Mangled &obj);

lldb/source/Core/Mangled.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,10 @@ ConstString Mangled::GetDemangledName() const {
285285
return GetDemangledNameImpl(/*force=*/false);
286286
}
287287

288-
std::optional<DemangledNameInfo> const &Mangled::GetDemangledInfo() const {
288+
const DemangledNameInfo *Mangled::GetDemangledInfo() const {
289289
if (!m_demangled_info)
290290
GetDemangledNameImpl(/*force=*/true);
291-
292-
return m_demangled_info;
291+
return m_demangled_info.get();
293292
}
294293

295294
// Generate the demangled name on demand using this accessor. Code in this
@@ -319,7 +318,8 @@ ConstString Mangled::GetDemangledNameImpl(bool force) const {
319318
std::pair<char *, DemangledNameInfo> demangled =
320319
GetItaniumDemangledStr(m_mangled.GetCString());
321320
demangled_name = demangled.first;
322-
m_demangled_info.emplace(std::move(demangled.second));
321+
m_demangled_info =
322+
std::make_unique<DemangledNameInfo>(std::move(demangled.second));
323323
break;
324324
}
325325
case eManglingSchemeRustV0:
@@ -556,8 +556,8 @@ void Mangled::Encode(DataEncoder &file, ConstStringTable &strtab) const {
556556
}
557557

558558
ConstString Mangled::GetBaseName() const {
559-
const auto &demangled_info = GetDemangledInfo();
560-
if (!demangled_info.has_value())
559+
const auto *demangled_info = GetDemangledInfo();
560+
if (demangled_info == nullptr)
561561
return {};
562562

563563
ConstString demangled_name = GetDemangledName();

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ GetAndValidateInfo(const SymbolContext &sc) {
269269
"function '{0}' does not have a demangled name",
270270
mangled.GetMangledName());
271271

272-
const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
272+
const DemangledNameInfo *info = mangled.GetDemangledInfo();
273273
if (!info)
274274
return llvm::createStringErrorV(
275275
"function '{0}' does not have demangled info", demangled_name);

lldb/unittests/Core/MangledTest.cpp

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -355,23 +355,24 @@ static bool NameInfoEquals(const DemangledNameInfo &lhs,
355355

356356
TEST(MangledTest, DemangledNameInfo_SetMangledResets) {
357357
Mangled mangled;
358-
EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
358+
EXPECT_EQ(mangled.GetDemangledInfo(), nullptr);
359359

360360
mangled.SetMangledName(ConstString("_Z3foov"));
361361
ASSERT_TRUE(mangled);
362362

363-
auto info1 = mangled.GetDemangledInfo();
364-
EXPECT_NE(info1, std::nullopt);
365-
EXPECT_TRUE(info1->hasBasename());
363+
ASSERT_NE(mangled.GetDemangledInfo(), nullptr);
364+
// Keep a copy of the original demangled info.
365+
DemangledNameInfo info1 = *mangled.GetDemangledInfo();
366+
EXPECT_TRUE(info1.hasBasename());
366367

367368
mangled.SetMangledName(ConstString("_Z4funcv"));
368369

369370
// Should have re-calculated demangled-info since mangled name changed.
370-
auto info2 = mangled.GetDemangledInfo();
371-
ASSERT_NE(info2, std::nullopt);
372-
EXPECT_TRUE(info2->hasBasename());
371+
ASSERT_NE(mangled.GetDemangledInfo(), nullptr);
372+
DemangledNameInfo info2 = *mangled.GetDemangledInfo();
373+
EXPECT_TRUE(info2.hasBasename());
373374

374-
EXPECT_FALSE(NameInfoEquals(info1.value(), info2.value()));
375+
EXPECT_FALSE(NameInfoEquals(info1, info2));
375376
EXPECT_EQ(mangled.GetDemangledName(), "func()");
376377
}
377378

@@ -383,45 +384,46 @@ TEST(MangledTest, DemangledNameInfo_SetDemangledResets) {
383384

384385
// Mangled name hasn't changed, so GetDemangledInfo causes re-demangling
385386
// of previously set mangled name.
386-
EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
387+
EXPECT_NE(mangled.GetDemangledInfo(), nullptr);
387388
EXPECT_EQ(mangled.GetDemangledName(), "foo()");
388389
}
389390

390391
TEST(MangledTest, DemangledNameInfo_Clear) {
391392
Mangled mangled("_Z3foov");
392393
ASSERT_TRUE(mangled);
393-
EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
394+
EXPECT_NE(mangled.GetDemangledInfo(), nullptr);
394395

395396
mangled.Clear();
396397

397-
EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
398+
EXPECT_EQ(mangled.GetDemangledInfo(), nullptr);
398399
}
399400

400401
TEST(MangledTest, DemangledNameInfo_SetValue) {
401402
Mangled mangled("_Z4funcv");
402403
ASSERT_TRUE(mangled);
403404

404-
auto demangled_func = mangled.GetDemangledInfo();
405+
ASSERT_NE(mangled.GetDemangledInfo(), nullptr);
406+
// Keep a copy of the original demangled info.
407+
DemangledNameInfo demangled_func = *mangled.GetDemangledInfo();
405408

406409
// SetValue(mangled) resets demangled-info
407410
mangled.SetValue(ConstString("_Z3foov"));
408-
auto demangled_foo = mangled.GetDemangledInfo();
409-
EXPECT_NE(demangled_foo, std::nullopt);
410-
EXPECT_FALSE(NameInfoEquals(demangled_foo.value(), demangled_func.value()));
411+
ASSERT_NE(mangled.GetDemangledInfo(), nullptr);
412+
DemangledNameInfo demangled_foo = *mangled.GetDemangledInfo();
413+
EXPECT_FALSE(NameInfoEquals(demangled_foo, demangled_func));
411414

412415
// SetValue(demangled) resets demangled-info
413416
mangled.SetValue(ConstString("_Z4funcv"));
414-
EXPECT_TRUE(NameInfoEquals(mangled.GetDemangledInfo().value(),
415-
demangled_func.value()));
417+
EXPECT_TRUE(NameInfoEquals(*mangled.GetDemangledInfo(), demangled_func));
416418

417419
// SetValue(empty) resets demangled-info
418420
mangled.SetValue(ConstString());
419-
EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
421+
EXPECT_EQ(mangled.GetDemangledInfo(), nullptr);
420422

421423
// Demangling invalid mangled name will set demangled-info
422424
// (without a valid basename).
423425
mangled.SetValue(ConstString("_Zinvalid"));
424-
ASSERT_NE(mangled.GetDemangledInfo(), std::nullopt);
426+
ASSERT_NE(mangled.GetDemangledInfo(), nullptr);
425427
EXPECT_FALSE(mangled.GetDemangledInfo()->hasBasename());
426428
}
427429

0 commit comments

Comments
 (0)