[Lldb-commits] [lldb] [lldb] Cache register types by object UID and register size (PR #215874)
Bar Soloveychik via lldb-commits
lldb-commits at lists.llvm.org
Thu Aug 13 11:57:12 PDT 2026
https://github.com/barsolo2000 updated https://github.com/llvm/llvm-project/pull/215874
>From 0c22b83e5850a45f4345fb9ab8a0dcd8fec566ec Mon Sep 17 00:00:00 2001
From: Bar Soloveychik <barsolo at fb.com>
Date: Wed, 12 Aug 2026 11:46:37 -0700
Subject: [PATCH 1/2] [lldb] Cache register types by object UID and register
size
XML type IDs are only unique within a feature, so they cannot identify
entries in the target-wide CompilerType cache. Assign each RegisterType a
lifetime-unique UID and combine it with the register size for cache keys.
This also prevents a new process from aliasing stale entries when an
allocator reuses a RegisterType address.
Insert completed enum and flags types into the cache, and clear cached
CompilerTypes when the target replaces its scratch TypeSystemClang. Add
direct builder tests for cache reuse, same-ID definitions, size-sensitive
enums, object-address reuse, and scratch type-system replacement.
Co-authored-by: David Spickett <david.spickett at arm.com>
---
lldb/include/lldb/Utility/RegisterType.h | 12 +-
.../RegisterTypeBuilderClang.cpp | 84 +++++----
.../RegisterTypeBuilderClang.h | 22 ++-
lldb/source/Utility/RegisterType.cpp | 10 ++
lldb/unittests/Target/CMakeLists.txt | 3 +
.../Target/RegisterTypeBuilderClangTest.cpp | 161 ++++++++++++++++++
6 files changed, 244 insertions(+), 48 deletions(-)
create mode 100644 lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp
diff --git a/lldb/include/lldb/Utility/RegisterType.h b/lldb/include/lldb/Utility/RegisterType.h
index 9ecd6c1dfb639..b045580b2567c 100644
--- a/lldb/include/lldb/Utility/RegisterType.h
+++ b/lldb/include/lldb/Utility/RegisterType.h
@@ -9,6 +9,7 @@
#ifndef LLDB_UTILITY_REGISTERTYPE_H
#define LLDB_UTILITY_REGISTERTYPE_H
+#include <cstdint>
#include <string>
#include <unordered_set>
#include <vector>
@@ -27,8 +28,11 @@ class RegisterType {
RegisterTypeKind getKind() const { return m_kind; }
- RegisterType(RegisterTypeKind kind, std::string id)
- : m_kind(kind), m_id(std::move(id)) {}
+ RegisterType(RegisterTypeKind kind, std::string id);
+ RegisterType(const RegisterType &) = delete;
+ RegisterType &operator=(const RegisterType &) = delete;
+ RegisterType(RegisterType &&) = delete;
+ RegisterType &operator=(RegisterType &&) = delete;
/// Output XML that describes this type, to be inserted into a target XML
/// file. Reserved characters like "<" are replaced with their XML safe
@@ -47,6 +51,9 @@ class RegisterType {
const std::string &GetID() const { return m_id; }
+ /// Return an identifier unique for the lifetime of this debugger process.
+ uint64_t GetUID() const { return m_uid; }
+
void SetDependencies(std::vector<const RegisterType *> dependencies) {
m_dependencies = dependencies;
}
@@ -54,6 +61,7 @@ class RegisterType {
private:
const RegisterTypeKind m_kind;
const std::string m_id;
+ const uint64_t m_uid;
std::vector<const RegisterType *> m_dependencies;
};
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index 001cd35604620..7a49c75f181bd 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -33,48 +33,25 @@ RegisterTypeBuilderClang::CreateInstance(Target &target) {
RegisterTypeBuilderClang::RegisterTypeBuilderClang(Target &target)
: m_target(target) {}
-static std::string MakeTypeName(const RegisterType &type_info,
- uint32_t register_byte_size) {
- std::string type_name = "__lldb_register_";
- switch (type_info.getKind()) {
- case RegisterType::eRegisterTypeKindFlags:
- type_name += "flags_";
- break;
- case RegisterType::eRegisterTypeKindEnum:
- // Enums can be used by many registers and the size of each register
- // may be different. The register size is used as the underlying size
- // of the enumerators, so we must make one enum type per register size
- // it is used with.
- type_name += "enum_" + std::to_string(register_byte_size) + "_";
- break;
- }
-
- return type_name + type_info.GetID();
-}
-
CompilerType
-RegisterTypeBuilderClang::BuildEnumType(const RegisterTypeEnum &enum_type_info,
+RegisterTypeBuilderClang::BuildEnumType(const RegisterTypeEnum *enum_type_info,
uint32_t register_byte_size,
lldb::TypeSystemClangSP type_system) {
- std::string enum_type_name = MakeTypeName(enum_type_info, register_byte_size);
-
- // Reuse existing type if we can.
- if (CompilerType enum_type =
- type_system->GetTypeForIdentifier<clang::EnumDecl>(
- type_system->getASTContext(), enum_type_name))
- return enum_type;
+ if (auto maybe_compiler_type =
+ GetExistingCompilerType(enum_type_info, register_byte_size))
+ return *maybe_compiler_type;
CompilerType register_uint_type =
type_system->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,
register_byte_size * 8);
CompilerType enum_type = type_system->CreateEnumerationType(
- enum_type_name, type_system->GetTranslationUnitDecl(),
- OptionalClangModuleID(), Declaration(), register_uint_type, false);
+ "", type_system->GetTranslationUnitDecl(), OptionalClangModuleID(),
+ Declaration(), register_uint_type, false);
type_system->StartTagDeclarationDefinition(enum_type);
Declaration decl;
- for (const auto &enumerator : enum_type_info.GetEnumerators()) {
+ for (const auto &enumerator : enum_type_info->GetEnumerators()) {
type_system->AddEnumerationValueToEnumerationType(
enum_type, decl, enumerator.m_name.c_str(), enumerator.m_value,
register_byte_size * 8);
@@ -82,19 +59,17 @@ RegisterTypeBuilderClang::BuildEnumType(const RegisterTypeEnum &enum_type_info,
type_system->CompleteTagDeclarationDefinition(enum_type);
+ m_type_cache.try_emplace(
+ std::make_pair(enum_type_info->GetUID(), register_byte_size), enum_type);
return enum_type;
}
CompilerType RegisterTypeBuilderClang::BuildFlagsType(
- const lldb_private::RegisterTypeFlags &flags_info,
+ const lldb_private::RegisterTypeFlags *flags_info,
uint32_t register_byte_size, lldb::TypeSystemClangSP type_system) {
- std::string register_type_name = MakeTypeName(flags_info, register_byte_size);
-
- // Reuse existing type if we can.
- if (CompilerType flags_type =
- type_system->GetTypeForIdentifier<clang::CXXRecordDecl>(
- type_system->getASTContext(), register_type_name))
- return flags_type;
+ if (auto maybe_compiler_type =
+ GetExistingCompilerType(flags_info, register_byte_size))
+ return *maybe_compiler_type;
// In most ABI, a change of field type means a change in storage unit.
// We want it all in one unit, so we use a field type the same as the
@@ -104,17 +79,17 @@ CompilerType RegisterTypeBuilderClang::BuildFlagsType(
register_byte_size * 8);
CompilerType flags_type = type_system->CreateRecordType(
- nullptr, OptionalClangModuleID(), register_type_name,
+ nullptr, OptionalClangModuleID(), "",
llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC);
type_system->StartTagDeclarationDefinition(flags_type);
- for (auto field : flags_info.GetFields()) {
+ for (auto field : flags_info->GetFields()) {
CompilerType field_type = field_uint_type;
if (const RegisterTypeEnum *enum_type_info = field.GetEnum())
if (!enum_type_info->GetEnumerators().empty())
field_type =
- BuildEnumType(*enum_type_info, register_byte_size, type_system);
+ BuildEnumType(enum_type_info, register_byte_size, type_system);
type_system->AddFieldToRecordType(flags_type, field.GetName(), field_type,
field.GetSizeInBits());
@@ -127,8 +102,10 @@ CompilerType RegisterTypeBuilderClang::BuildFlagsType(
// This should be true if RegisterTypeFlags padded correctly.
assert(
llvm::expectedToOptional(flags_type.GetByteSize(nullptr)).value_or(0) ==
- flags_info.GetSize());
+ flags_info->GetSize());
+ m_type_cache.try_emplace(
+ std::make_pair(flags_info->GetUID(), register_byte_size), flags_type);
return flags_type;
}
@@ -138,17 +115,36 @@ RegisterTypeBuilderClang::GetRegisterType(const RegisterInfo ®_info) {
ScratchTypeSystemClang::GetForTarget(m_target);
assert(type_system);
+ if (m_cached_type_system.lock() != type_system) {
+ m_type_cache.clear();
+ m_cached_type_system = type_system;
+ }
+
if (!reg_info.register_type)
return CompilerType();
+ // Note that we do not check the type cache here because types can be nested.
+ // There is a cache check in each of the Build<subtype> methods, and those
+ // methods may call each other (Flags may use Enums for example).
+
switch (reg_info.register_type->getKind()) {
case RegisterType::eRegisterTypeKindFlags:
return BuildFlagsType(
- *llvm::dyn_cast<RegisterTypeFlags>(reg_info.register_type),
+ llvm::dyn_cast<RegisterTypeFlags>(reg_info.register_type),
reg_info.byte_size, type_system);
case RegisterType::eRegisterTypeKindEnum:
return BuildEnumType(
- *llvm::dyn_cast<RegisterTypeEnum>(reg_info.register_type),
+ llvm::dyn_cast<RegisterTypeEnum>(reg_info.register_type),
reg_info.byte_size, type_system);
}
}
+
+std::optional<CompilerType> RegisterTypeBuilderClang::GetExistingCompilerType(
+ const RegisterType *register_type, uint32_t register_byte_size) {
+ auto cached =
+ m_type_cache.find({register_type->GetUID(), register_byte_size});
+ if (cached != m_type_cache.end())
+ return cached->second;
+
+ return {};
+}
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
index ae2bea69c70a8..7359c72531eaf 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -33,15 +33,33 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
CompilerType GetRegisterType(const RegisterInfo ®_info) override;
private:
- CompilerType BuildEnumType(const RegisterTypeEnum &enum_type_info,
+ CompilerType BuildEnumType(const RegisterTypeEnum *enum_type_info,
uint32_t register_byte_size,
lldb::TypeSystemClangSP type_system);
- CompilerType BuildFlagsType(const RegisterTypeFlags &flags_info,
+ CompilerType BuildFlagsType(const RegisterTypeFlags *flags_info,
uint32_t register_byte_size,
lldb::TypeSystemClangSP type_system);
Target &m_target;
+
+ // A cache of previously created types. We do not cache by element ID because
+ // IDs are not unique across xml <feature> elements and this class does not
+ // know anything about features.
+ //
+ // The key contains the lifetime-unique ID of the type and the size of the
+ // register we made it for. Some types (enums for example) use the register
+ // size in their type and must be rebuilt for a different size.
+ //
+ // 8 is chosen because types are only made when needed, and most lldb commands
+ // do not need them.
+ llvm::SmallDenseMap<std::pair<uint64_t, uint32_t>, CompilerType, 8>
+ m_type_cache;
+ std::weak_ptr<TypeSystemClang> m_cached_type_system;
+
+ std::optional<CompilerType>
+ GetExistingCompilerType(const RegisterType *register_type,
+ uint32_t register_byte_size);
};
} // namespace lldb_private
diff --git a/lldb/source/Utility/RegisterType.cpp b/lldb/source/Utility/RegisterType.cpp
index 9191831bb52c1..89547cb484bc6 100644
--- a/lldb/source/Utility/RegisterType.cpp
+++ b/lldb/source/Utility/RegisterType.cpp
@@ -8,8 +8,18 @@
#include "lldb/Utility/RegisterType.h"
+#include <atomic>
+
using namespace lldb_private;
+namespace {
+std::atomic<uint64_t> g_next_register_type_uid{1};
+}
+
+RegisterType::RegisterType(RegisterTypeKind kind, std::string id)
+ : m_kind(kind), m_id(std::move(id)),
+ m_uid(g_next_register_type_uid.fetch_add(1, std::memory_order_relaxed)) {}
+
void RegisterType::ToXML(
Stream &strm, std::unordered_set<const RegisterType *> &previously_emitted,
const RegisterType *user) const {
diff --git a/lldb/unittests/Target/CMakeLists.txt b/lldb/unittests/Target/CMakeLists.txt
index b12c781cf5789..ebfb06e8fc780 100644
--- a/lldb/unittests/Target/CMakeLists.txt
+++ b/lldb/unittests/Target/CMakeLists.txt
@@ -9,6 +9,7 @@ add_lldb_unittest(TargetTests
MemoryTagMapTest.cpp
ModuleCacheTest.cpp
PathMappingListTest.cpp
+ RegisterTypeBuilderClangTest.cpp
RemoteAwarePlatformTest.cpp
ScratchTypeSystemTest.cpp
StackFrameRecognizerTest.cpp
@@ -26,8 +27,10 @@ add_lldb_unittest(TargetTests
lldbPluginPlatformLinux
lldbPluginPlatformMacOSX
lldbPluginPlatformAndroid
+ lldbPluginRegisterTypeBuilderClang
lldbPluginSymbolFileBreakpad
lldbPluginSymbolFileSymtab
+ lldbPluginTypeSystemClang
lldbTarget
lldbSymbol
lldbUtility
diff --git a/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp b/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp
new file mode 100644
index 0000000000000..29840b7f7bad0
--- /dev/null
+++ b/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp
@@ -0,0 +1,161 @@
+//===-- RegisterTypeBuilderClangTest.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h"
+#include "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/RegisterInfo.h"
+#include "lldb/Utility/RegisterTypeFlags.h"
+#include "gtest/gtest.h"
+
+#include <mutex>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+class RegisterTypeBuilderClangTest : public testing::Test {
+public:
+ SubsystemRAII<FileSystem, HostInfo, TypeSystemClang,
+ platform_linux::PlatformLinux>
+ subsystems;
+
+protected:
+ void SetUp() override {
+ std::call_once(TestUtilities::g_debugger_initialize_flag,
+ []() { Debugger::Initialize(nullptr); });
+ ArchSpec host_arch("x86_64-pc-linux");
+ Platform::SetHostPlatform(
+ platform_linux::PlatformLinux::CreateInstance(true, &host_arch));
+ m_debugger_sp = Debugger::CreateInstance();
+ }
+
+ static RegisterInfo MakeRegisterInfo(const RegisterType &type,
+ uint32_t byte_size) {
+ RegisterInfo info{};
+ info.name = "test";
+ info.byte_size = byte_size;
+ info.register_type = &type;
+ return info;
+ }
+
+ DebuggerSP m_debugger_sp;
+};
+
+TEST_F(RegisterTypeBuilderClangTest, ReusesCachedType) {
+ Target &target = m_debugger_sp->GetDummyTarget();
+ RegisterTypeFlags flags("flags", 4,
+ {RegisterTypeFlags::Field("field", 0, 31)});
+ RegisterInfo info = MakeRegisterInfo(flags, 4);
+ RegisterTypeBuilderClang builder(target);
+
+ CompilerType first = builder.GetRegisterType(info);
+ CompilerType second = builder.GetRegisterType(info);
+
+ ASSERT_TRUE(first);
+ ASSERT_TRUE(second);
+ EXPECT_EQ(first, second);
+}
+
+TEST_F(RegisterTypeBuilderClangTest, DistinguishesTypesWithTheSameID) {
+ Target &target = m_debugger_sp->GetDummyTarget();
+ RegisterTypeFlags first_flags("flags", 4,
+ {RegisterTypeFlags::Field("first", 0, 31)});
+ RegisterTypeFlags second_flags("flags", 4,
+ {RegisterTypeFlags::Field("second", 0, 31)});
+ RegisterTypeBuilderClang builder(target);
+
+ CompilerType first =
+ builder.GetRegisterType(MakeRegisterInfo(first_flags, 4));
+ CompilerType second =
+ builder.GetRegisterType(MakeRegisterInfo(second_flags, 4));
+
+ ASSERT_TRUE(first);
+ ASSERT_TRUE(second);
+ EXPECT_NE(first, second);
+
+ std::string first_field_name;
+ std::string second_field_name;
+ ASSERT_TRUE(
+ first.GetFieldAtIndex(0, first_field_name, nullptr, nullptr, nullptr));
+ ASSERT_TRUE(
+ second.GetFieldAtIndex(0, second_field_name, nullptr, nullptr, nullptr));
+ EXPECT_EQ(first_field_name, "first");
+ EXPECT_EQ(second_field_name, "second");
+}
+
+TEST_F(RegisterTypeBuilderClangTest, RegisterSizeIsPartOfCacheKey) {
+ Target &target = m_debugger_sp->GetDummyTarget();
+ RegisterTypeEnum type("enum", {{0, "zero"}, {1, "one"}});
+ RegisterTypeBuilderClang builder(target);
+
+ CompilerType four_byte = builder.GetRegisterType(MakeRegisterInfo(type, 4));
+ CompilerType eight_byte = builder.GetRegisterType(MakeRegisterInfo(type, 8));
+
+ ASSERT_TRUE(four_byte);
+ ASSERT_TRUE(eight_byte);
+ EXPECT_NE(four_byte, eight_byte);
+ EXPECT_EQ(llvm::expectedToOptional(four_byte.GetByteSize(nullptr)), 4u);
+ EXPECT_EQ(llvm::expectedToOptional(eight_byte.GetByteSize(nullptr)), 8u);
+ EXPECT_EQ(four_byte, builder.GetRegisterType(MakeRegisterInfo(type, 4)));
+ EXPECT_EQ(eight_byte, builder.GetRegisterType(MakeRegisterInfo(type, 8)));
+}
+
+TEST_F(RegisterTypeBuilderClangTest, DistinguishesReusedObjectAddresses) {
+ Target &target = m_debugger_sp->GetDummyTarget();
+ RegisterTypeBuilderClang builder(target);
+ std::optional<RegisterTypeEnum> type;
+
+ type.emplace("enum", RegisterTypeEnum::Enumerators{{0, "first"}});
+ const RegisterTypeEnum *first_address = &*type;
+ uint64_t first_uid = type->GetUID();
+ CompilerType first = builder.GetRegisterType(MakeRegisterInfo(*type, 4));
+ ASSERT_TRUE(first);
+
+ type.reset();
+ type.emplace("enum", RegisterTypeEnum::Enumerators{{0, "second"}});
+ ASSERT_EQ(first_address, &*type);
+ ASSERT_NE(first_uid, type->GetUID());
+ CompilerType second = builder.GetRegisterType(MakeRegisterInfo(*type, 4));
+
+ ASSERT_TRUE(second);
+ EXPECT_NE(first, second);
+}
+
+TEST_F(RegisterTypeBuilderClangTest, CacheFollowsScratchTypeSystem) {
+ Target &target = m_debugger_sp->GetDummyTarget();
+ RegisterTypeEnum type("enum", {{0, "zero"}, {1, "one"}});
+ RegisterInfo info = MakeRegisterInfo(type, 4);
+ RegisterTypeBuilderClang builder(target);
+
+ CompilerType first = builder.GetRegisterType(info);
+ ASSERT_TRUE(first);
+ std::shared_ptr<TypeSystemClang> first_type_system =
+ first.GetTypeSystem<TypeSystemClang>();
+ ASSERT_TRUE(first_type_system);
+
+ target.ClearModules(/*delete_locations=*/false);
+
+ CompilerType second = builder.GetRegisterType(info);
+ ASSERT_TRUE(second);
+ std::shared_ptr<TypeSystemClang> second_type_system =
+ second.GetTypeSystem<TypeSystemClang>();
+ ASSERT_TRUE(second_type_system);
+ EXPECT_NE(first_type_system, second_type_system);
+ EXPECT_NE(first, second);
+}
+
+} // namespace
>From 498df609b5036c62a878433ec73872e093dc9ba3 Mon Sep 17 00:00:00 2001
From: Bar Soloveychik <barsolo at fb.com>
Date: Thu, 13 Aug 2026 11:56:39 -0700
Subject: [PATCH 2/2] Added some comments and fixes
---
lldb/include/lldb/Target/RegisterTypeBuilder.h | 2 ++
lldb/include/lldb/Utility/RegisterType.h | 4 +++-
.../Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h | 2 +-
lldb/source/Utility/RegisterType.cpp | 4 +---
lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp | 2 ++
5 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/lldb/include/lldb/Target/RegisterTypeBuilder.h b/lldb/include/lldb/Target/RegisterTypeBuilder.h
index 26b97b6194d49..9a5981af75b08 100644
--- a/lldb/include/lldb/Target/RegisterTypeBuilder.h
+++ b/lldb/include/lldb/Target/RegisterTypeBuilder.h
@@ -18,6 +18,8 @@ class RegisterTypeBuilder : public PluginInterface {
public:
~RegisterTypeBuilder() override = default;
+ /// Do not cache the returned CompilerType. A target may replace its scratch
+ /// type system, so callers must request the type again whenever needed.
virtual CompilerType GetRegisterType(const RegisterInfo ®_info) = 0;
protected:
diff --git a/lldb/include/lldb/Utility/RegisterType.h b/lldb/include/lldb/Utility/RegisterType.h
index b045580b2567c..859de9ee65719 100644
--- a/lldb/include/lldb/Utility/RegisterType.h
+++ b/lldb/include/lldb/Utility/RegisterType.h
@@ -51,7 +51,9 @@ class RegisterType {
const std::string &GetID() const { return m_id; }
- /// Return an identifier unique for the lifetime of this debugger process.
+ /// Return an identifier unique among all RegisterType instances constructed
+ /// during the lifetime of the LLDB host process. The identifier is not
+ /// reused after this instance is destroyed.
uint64_t GetUID() const { return m_uid; }
void SetDependencies(std::vector<const RegisterType *> dependencies) {
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
index 7359c72531eaf..8d970367a15b2 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -47,7 +47,7 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
// IDs are not unique across xml <feature> elements and this class does not
// know anything about features.
//
- // The key contains the lifetime-unique ID of the type and the size of the
+ // The key contains the process-wide UID of the type and the size of the
// register we made it for. Some types (enums for example) use the register
// size in their type and must be rebuilt for a different size.
//
diff --git a/lldb/source/Utility/RegisterType.cpp b/lldb/source/Utility/RegisterType.cpp
index 89547cb484bc6..a7de0688cff22 100644
--- a/lldb/source/Utility/RegisterType.cpp
+++ b/lldb/source/Utility/RegisterType.cpp
@@ -12,9 +12,7 @@
using namespace lldb_private;
-namespace {
-std::atomic<uint64_t> g_next_register_type_uid{1};
-}
+static std::atomic<uint64_t> g_next_register_type_uid{1};
RegisterType::RegisterType(RegisterTypeKind kind, std::string id)
: m_kind(kind), m_id(std::move(id)),
diff --git a/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp b/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp
index 29840b7f7bad0..c24c3e35957f9 100644
--- a/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp
+++ b/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp
@@ -70,6 +70,8 @@ TEST_F(RegisterTypeBuilderClangTest, ReusesCachedType) {
EXPECT_EQ(first, second);
}
+// XML type IDs are scoped to a feature, so separate features may define
+// different types using the same ID.
TEST_F(RegisterTypeBuilderClangTest, DistinguishesTypesWithTheSameID) {
Target &target = m_debugger_sp->GetDummyTarget();
RegisterTypeFlags first_flags("flags", 4,
More information about the lldb-commits
mailing list