[Lldb-commits] [lldb] [lldb] Reduce symbol table memory by storing `DemangledNameInfo` on heap (NFC) (PR #200495)

via lldb-commits lldb-commits at lists.llvm.org
Fri May 29 13:51:58 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Dave Lee (kastiglione)

<details>
<summary>Changes</summary>

Change `m_demangled_info` from `std::optional<DemangledNameInfo>` to
`std::shared_ptr<DemangledNameInfo>`, which is a change from the unavoidable fixed costs
of inline storage, to lazy (dynamic cost) heap storage.

`DemangledNameInfo` is 128 bytes (8 pairs of size_t). After `std::optional` overhead,
the total is 136 bytes inline — regardless of whether the info is populated. This
dominates the size of `Mangled`, without it `Mangled` is just 16 bytes for two
`ConstString` instances.

By replacing optional with shared_ptr, the inline cost drops to 16 bytes, reducing
`Mangled` from 152 to 32 bytes — netting 120 bytes per `Symbol`.

The `DemangledNameInfo` is only applicable to Itanium-mangled C++ symbols, and is
produced on demand. Depending on the binary and the use, many (if not most) symbols will
have null for `DemangledNameInfo`.

shared_ptr is used instead of unique_ptr to preserve copyability of `Mangled`.


---
Full diff: https://github.com/llvm/llvm-project/pull/200495.diff


4 Files Affected:

- (modified) lldb/include/lldb/Core/Mangled.h (+2-2) 
- (modified) lldb/source/Core/Mangled.cpp (+7-5) 
- (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+1-1) 
- (modified) lldb/unittests/Core/MangledTest.cpp (+17-17) 


``````````diff
diff --git a/lldb/include/lldb/Core/Mangled.h b/lldb/include/lldb/Core/Mangled.h
index 546d7a9b409ed..bf4a68370d5a1 100644
--- a/lldb/include/lldb/Core/Mangled.h
+++ b/lldb/include/lldb/Core/Mangled.h
@@ -279,7 +279,7 @@ class Mangled {
   void Encode(DataEncoder &encoder, ConstStringTable &strtab) const;
 
   /// Retrieve \c DemangledNameInfo of the demangled name held by this object.
-  const std::optional<DemangledNameInfo> &GetDemangledInfo() const;
+  const DemangledNameInfo *GetDemangledInfo() const;
 
   /// Compute the base name (without namespace/class qualifiers) from the
   /// demangled name.
@@ -308,7 +308,7 @@ class Mangled {
 
   /// If available, holds information about where in \c m_demangled certain
   /// parts of the name (e.g., basename, arguments, etc.) begin and end.
-  mutable std::optional<DemangledNameInfo> m_demangled_info = std::nullopt;
+  mutable std::shared_ptr<DemangledNameInfo> m_demangled_info;
 };
 
 Stream &operator<<(Stream &s, const Mangled &obj);
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index 66c785d5871cc..47770649a90ea 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -25,6 +25,7 @@
 #include "llvm/Demangle/Demangle.h"
 #include "llvm/Support/Compiler.h"
 
+#include <memory>
 #include <mutex>
 #include <string>
 #include <string_view>
@@ -285,11 +286,11 @@ ConstString Mangled::GetDemangledName() const {
   return GetDemangledNameImpl(/*force=*/false);
 }
 
-std::optional<DemangledNameInfo> const &Mangled::GetDemangledInfo() const {
+const DemangledNameInfo *Mangled::GetDemangledInfo() const {
   if (!m_demangled_info)
     GetDemangledNameImpl(/*force=*/true);
 
-  return m_demangled_info;
+  return m_demangled_info.get();
 }
 
 // Generate the demangled name on demand using this accessor. Code in this
@@ -319,7 +320,8 @@ ConstString Mangled::GetDemangledNameImpl(bool force) const {
     std::pair<char *, DemangledNameInfo> demangled =
         GetItaniumDemangledStr(m_mangled.GetCString());
     demangled_name = demangled.first;
-    m_demangled_info.emplace(std::move(demangled.second));
+    if (demangled_name)
+      m_demangled_info = std::make_shared<DemangledNameInfo>(demangled.second);
     break;
   }
   case eManglingSchemeRustV0:
@@ -556,8 +558,8 @@ void Mangled::Encode(DataEncoder &file, ConstStringTable &strtab) const {
 }
 
 ConstString Mangled::GetBaseName() const {
-  const auto &demangled_info = GetDemangledInfo();
-  if (!demangled_info.has_value())
+  const auto *demangled_info = GetDemangledInfo();
+  if (!demangled_info)
     return {};
 
   ConstString demangled_name = GetDemangledName();
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 7e68d25c0110f..74a5a414de67b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -269,7 +269,7 @@ GetAndValidateInfo(const SymbolContext &sc) {
         "function '{0}' does not have a demangled name",
         mangled.GetMangledName());
 
-  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
+  const DemangledNameInfo *info = mangled.GetDemangledInfo();
   if (!info)
     return llvm::createStringErrorV(
         "function '{0}' does not have demangled info", demangled_name);
diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/MangledTest.cpp
index 706e67801e01a..97bd239c544b9 100644
--- a/lldb/unittests/Core/MangledTest.cpp
+++ b/lldb/unittests/Core/MangledTest.cpp
@@ -355,23 +355,24 @@ static bool NameInfoEquals(const DemangledNameInfo &lhs,
 
 TEST(MangledTest, DemangledNameInfo_SetMangledResets) {
   Mangled mangled;
-  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
+  EXPECT_EQ(mangled.GetDemangledInfo(), nullptr);
 
   mangled.SetMangledName(ConstString("_Z3foov"));
   ASSERT_TRUE(mangled);
 
-  auto info1 = mangled.GetDemangledInfo();
-  EXPECT_NE(info1, std::nullopt);
+  auto *info1 = mangled.GetDemangledInfo();
+  EXPECT_NE(info1, nullptr);
   EXPECT_TRUE(info1->hasBasename());
 
+  DemangledNameInfo prev_info = *info1;
   mangled.SetMangledName(ConstString("_Z4funcv"));
 
   // Should have re-calculated demangled-info since mangled name changed.
-  auto info2 = mangled.GetDemangledInfo();
-  ASSERT_NE(info2, std::nullopt);
+  auto *info2 = mangled.GetDemangledInfo();
+  ASSERT_NE(info2, nullptr);
   EXPECT_TRUE(info2->hasBasename());
 
-  EXPECT_FALSE(NameInfoEquals(info1.value(), info2.value()));
+  EXPECT_FALSE(NameInfoEquals(prev_info, *info2));
   EXPECT_EQ(mangled.GetDemangledName(), "func()");
 }
 
@@ -383,45 +384,44 @@ TEST(MangledTest, DemangledNameInfo_SetDemangledResets) {
 
   // Mangled name hasn't changed, so GetDemangledInfo causes re-demangling
   // of previously set mangled name.
-  EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
+  EXPECT_NE(mangled.GetDemangledInfo(), nullptr);
   EXPECT_EQ(mangled.GetDemangledName(), "foo()");
 }
 
 TEST(MangledTest, DemangledNameInfo_Clear) {
   Mangled mangled("_Z3foov");
   ASSERT_TRUE(mangled);
-  EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
+  EXPECT_NE(mangled.GetDemangledInfo(), nullptr);
 
   mangled.Clear();
 
-  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
+  EXPECT_EQ(mangled.GetDemangledInfo(), nullptr);
 }
 
 TEST(MangledTest, DemangledNameInfo_SetValue) {
   Mangled mangled("_Z4funcv");
   ASSERT_TRUE(mangled);
 
-  auto demangled_func = mangled.GetDemangledInfo();
+  DemangledNameInfo demangled_func = *mangled.GetDemangledInfo();
 
   // SetValue(mangled) resets demangled-info
   mangled.SetValue(ConstString("_Z3foov"));
-  auto demangled_foo = mangled.GetDemangledInfo();
-  EXPECT_NE(demangled_foo, std::nullopt);
-  EXPECT_FALSE(NameInfoEquals(demangled_foo.value(), demangled_func.value()));
+  auto *demangled_foo = mangled.GetDemangledInfo();
+  EXPECT_NE(demangled_foo, nullptr);
+  EXPECT_FALSE(NameInfoEquals(*demangled_foo, demangled_func));
 
   // SetValue(demangled) resets demangled-info
   mangled.SetValue(ConstString("_Z4funcv"));
-  EXPECT_TRUE(NameInfoEquals(mangled.GetDemangledInfo().value(),
-                             demangled_func.value()));
+  EXPECT_TRUE(NameInfoEquals(*mangled.GetDemangledInfo(), demangled_func));
 
   // SetValue(empty) resets demangled-info
   mangled.SetValue(ConstString());
-  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
+  EXPECT_EQ(mangled.GetDemangledInfo(), nullptr);
 
   // Demangling invalid mangled name will set demangled-info
   // (without a valid basename).
   mangled.SetValue(ConstString("_Zinvalid"));
-  ASSERT_NE(mangled.GetDemangledInfo(), std::nullopt);
+  ASSERT_NE(mangled.GetDemangledInfo(), nullptr);
   EXPECT_FALSE(mangled.GetDemangledInfo()->hasBasename());
 }
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/200495


More information about the lldb-commits mailing list