Skip to content

Commit 0e45e60

Browse files
committed
Use ForEachExternalModule in ParseTypeFromClangModule (NFC)
I wanted to further simplify ParseTypeFromClangModule by replacing the hand-rolled loop with ForEachExternalModule, and then realized that ForEachExternalModule also had the problem of visiting the same leaf node an exponential number of times in the worst-case. This adds a set of searched_symbol_files set to the function as well as the ability to early-exit from it. Differential Revision: https://reviews.llvm.org/D70215
1 parent c9de002 commit 0e45e60

File tree

10 files changed

+149
-51
lines changed

10 files changed

+149
-51
lines changed

lldb/include/lldb/Symbol/CompileUnit.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "lldb/lldb-enumerations.h"
2020

2121
#include "llvm/ADT/DenseMap.h"
22+
#include "llvm/ADT/DenseSet.h"
2223

2324
namespace lldb_private {
2425
/// \class CompileUnit CompileUnit.h "lldb/Symbol/CompileUnit.h"
@@ -241,9 +242,20 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
241242
/// compilation unit. Recursively also descends into the referenced external
242243
/// modules of any encountered compilation unit.
243244
///
244-
/// \param[in] f
245-
/// The lambda that should be applied to every module.
246-
void ForEachExternalModule(llvm::function_ref<void(lldb::ModuleSP)> f);
245+
/// \param visited_symbol_files
246+
/// A set of SymbolFiles that were already visited to avoid
247+
/// visiting one file more than once.
248+
///
249+
/// \param[in] lambda
250+
/// The lambda that should be applied to every function. The lambda can
251+
/// return true if the iteration should be aborted earlier.
252+
///
253+
/// \return
254+
/// If the lambda early-exited, this function returns true to
255+
/// propagate the early exit.
256+
virtual bool ForEachExternalModule(
257+
llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files,
258+
llvm::function_ref<bool(Module &)> lambda);
247259

248260
/// Get the compile unit's support file list.
249261
///

lldb/include/lldb/Symbol/SymbolFile.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,35 @@ class SymbolFile : public PluginInterface {
122122
virtual size_t ParseFunctions(CompileUnit &comp_unit) = 0;
123123
virtual bool ParseLineTable(CompileUnit &comp_unit) = 0;
124124
virtual bool ParseDebugMacros(CompileUnit &comp_unit) = 0;
125-
virtual void
126-
ForEachExternalModule(CompileUnit &comp_unit,
127-
llvm::function_ref<void(lldb::ModuleSP)> f) {}
125+
126+
/// Apply a lambda to each external lldb::Module referenced by this
127+
/// \p comp_unit. Recursively also descends into the referenced external
128+
/// modules of any encountered compilation unit.
129+
///
130+
/// \param comp_unit
131+
/// When this SymbolFile consists of multiple auxilliary
132+
/// SymbolFiles, for example, a Darwin debug map that references
133+
/// multiple .o files, comp_unit helps choose the auxilliary
134+
/// file. In most other cases comp_unit's symbol file is
135+
/// identiacal with *this.
136+
///
137+
/// \param[in] lambda
138+
/// The lambda that should be applied to every function. The lambda can
139+
/// return true if the iteration should be aborted earlier.
140+
///
141+
/// \param visited_symbol_files
142+
/// A set of SymbolFiles that were already visited to avoid
143+
/// visiting one file more than once.
144+
///
145+
/// \return
146+
/// If the lambda early-exited, this function returns true to
147+
/// propagate the early exit.
148+
virtual bool ForEachExternalModule(
149+
lldb_private::CompileUnit &comp_unit,
150+
llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files,
151+
llvm::function_ref<bool(Module &)> lambda) {
152+
return false;
153+
}
128154
virtual bool ParseSupportFiles(CompileUnit &comp_unit,
129155
FileSpecList &support_files) = 0;
130156
virtual size_t ParseTypes(CompileUnit &comp_unit) = 0;

lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "lldb/Symbol/CompileUnit.h"
4343
#include "lldb/Symbol/Function.h"
4444
#include "lldb/Symbol/ObjectFile.h"
45+
#include "lldb/Symbol/SymbolFile.h"
4546
#include "lldb/Symbol/SymbolVendor.h"
4647
#include "lldb/Symbol/Type.h"
4748
#include "lldb/Symbol/VariableList.h"
@@ -478,15 +479,18 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
478479
files.AppendIfUnique(f);
479480
// We also need to look at external modules in the case of -gmodules as they
480481
// contain the support files for libc++ and the C library.
481-
sc.comp_unit->ForEachExternalModule([&files](lldb::ModuleSP module) {
482-
for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) {
483-
const FileSpecList &support_files =
484-
module->GetCompileUnitAtIndex(i)->GetSupportFiles();
485-
for (const FileSpec &f : support_files) {
486-
files.AppendIfUnique(f);
487-
}
488-
}
489-
});
482+
llvm::DenseSet<SymbolFile *> visited_symbol_files;
483+
sc.comp_unit->ForEachExternalModule(
484+
visited_symbol_files, [&files](Module &module) {
485+
for (std::size_t i = 0; i < module.GetNumCompileUnits(); ++i) {
486+
const FileSpecList &support_files =
487+
module.GetCompileUnitAtIndex(i)->GetSupportFiles();
488+
for (const FileSpec &f : support_files) {
489+
files.AppendIfUnique(f);
490+
}
491+
}
492+
return false;
493+
});
490494

491495
LLDB_LOG(log, "[C++ module config] Found {0} support files to analyze",
492496
files.GetSize());

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ static lldb::ModuleSP GetContainingClangModule(const DWARFDIE &die) {
168168
return lldb::ModuleSP();
169169
}
170170

171-
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const DWARFDIE &die,
171+
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
172+
const DWARFDIE &die,
172173
Log *log) {
173174
ModuleSP dwo_module_sp = GetContainingClangModule(die);
174175
if (!dwo_module_sp)
@@ -189,19 +190,23 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const DWARFDIE &die,
189190
searched_symbol_files, pcm_types);
190191
if (pcm_types.Empty()) {
191192
// Since this type is defined in one of the Clang modules imported
192-
// by this symbol file, search all of them.
193+
// by this symbol file, search all of them. Instead of calling
194+
// sym_file->FindTypes(), which would return this again, go straight
195+
// to the imported modules.
193196
auto &sym_file = die.GetCU()->GetSymbolFileDWARF();
194-
for (const auto &name_module : sym_file.getExternalTypeModules()) {
195-
if (!name_module.second)
196-
continue;
197-
name_module.second->GetSymbolFile()->FindTypes(
198-
decl_context, languages, searched_symbol_files, pcm_types);
199-
if (pcm_types.GetSize())
200-
break;
201-
}
197+
198+
// Well-formed clang modules never form cycles; guard against corrupted
199+
// ones by inserting the current file.
200+
searched_symbol_files.insert(&sym_file);
201+
sym_file.ForEachExternalModule(
202+
*sc.comp_unit, searched_symbol_files, [&](Module &module) {
203+
module.GetSymbolFile()->FindTypes(decl_context, languages,
204+
searched_symbol_files, pcm_types);
205+
return pcm_types.GetSize();
206+
});
202207
}
203208

204-
if (pcm_types.GetSize() != 1)
209+
if (!pcm_types.GetSize())
205210
return TypeSP();
206211

207212
// We found a real definition for this type in the Clang module, so lets use
@@ -491,7 +496,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
491496
// contain those
492497
if (encoding_die &&
493498
encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) {
494-
type_sp = ParseTypeFromClangModule(die, log);
499+
type_sp = ParseTypeFromClangModule(sc, die, log);
495500
if (type_sp)
496501
return type_sp;
497502
}
@@ -667,13 +672,13 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
667672
case DW_TAG_class_type: {
668673
assert((!type_sp && !clang_type) &&
669674
"Did not expect partially computed structure-like type");
670-
TypeSP struct_like_type_sp = ParseStructureLikeDIE(die, attrs);
675+
TypeSP struct_like_type_sp = ParseStructureLikeDIE(sc, die, attrs);
671676
return UpdateSymbolContextScopeForType(sc, die, struct_like_type_sp);
672677
}
673678

674679
case DW_TAG_enumeration_type: {
675680
if (attrs.is_forward_declaration) {
676-
type_sp = ParseTypeFromClangModule(die, log);
681+
type_sp = ParseTypeFromClangModule(sc, die, log);
677682
if (type_sp)
678683
return type_sp;
679684

@@ -1339,7 +1344,8 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType(
13391344
}
13401345

13411346
TypeSP
1342-
DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die,
1347+
DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
1348+
const DWARFDIE &die,
13431349
ParsedDWARFTypeAttributes &attrs) {
13441350
TypeSP type_sp;
13451351
CompilerType clang_type;
@@ -1473,7 +1479,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die,
14731479

14741480
// See if the type comes from a Clang module and if so, track down
14751481
// that type.
1476-
type_sp = ParseTypeFromClangModule(die, log);
1482+
type_sp = ParseTypeFromClangModule(sc, die, log);
14771483
if (type_sp)
14781484
return type_sp;
14791485

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ class DWARFASTParserClang : public DWARFASTParser {
128128
const DWARFDIE &parent_die);
129129

130130
/// Parse a structure, class, or union type DIE.
131-
lldb::TypeSP ParseStructureLikeDIE(const DWARFDIE &die,
131+
lldb::TypeSP ParseStructureLikeDIE(const lldb_private::SymbolContext &sc,
132+
const DWARFDIE &die,
132133
ParsedDWARFTypeAttributes &attrs);
133134

134135
lldb_private::Type *GetTypeForDIE(const DWARFDIE &die);
@@ -160,7 +161,8 @@ class DWARFASTParserClang : public DWARFASTParser {
160161
const DWARFDIE &die, lldb::TypeSP type_sp);
161162

162163
/// Follow Clang Module Skeleton CU references to find a type definition.
163-
lldb::TypeSP ParseTypeFromClangModule(const DWARFDIE &die,
164+
lldb::TypeSP ParseTypeFromClangModule(const lldb_private::SymbolContext &sc,
165+
const DWARFDIE &die,
164166
lldb_private::Log *log);
165167

166168
// Return true if this type is a declaration to a type in an external

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -851,16 +851,32 @@ size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) {
851851
return functions_added;
852852
}
853853

854-
void SymbolFileDWARF::ForEachExternalModule(
855-
CompileUnit &comp_unit, llvm::function_ref<void(ModuleSP)> f) {
856-
UpdateExternalModuleListIfNeeded();
854+
bool SymbolFileDWARF::ForEachExternalModule(
855+
CompileUnit &comp_unit,
856+
llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files,
857+
llvm::function_ref<bool(Module &)> lambda) {
858+
// Only visit each symbol file once.
859+
if (!visited_symbol_files.insert(this).second)
860+
return false;
857861

862+
UpdateExternalModuleListIfNeeded();
858863
for (auto &p : m_external_type_modules) {
859864
ModuleSP module = p.second;
860-
f(module);
861-
for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i)
862-
module->GetCompileUnitAtIndex(i)->ForEachExternalModule(f);
865+
if (!module)
866+
continue;
867+
868+
// Invoke the action and potentially early-exit.
869+
if (lambda(*module))
870+
return true;
871+
872+
for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) {
873+
auto cu = module->GetCompileUnitAtIndex(i);
874+
bool early_exit = cu->ForEachExternalModule(visited_symbol_files, lambda);
875+
if (early_exit)
876+
return true;
877+
}
863878
}
879+
return false;
864880
}
865881

866882
bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit,
@@ -2490,11 +2506,22 @@ void SymbolFileDWARF::FindTypes(
24902506
if (!contextMatches(die_context, pattern))
24912507
continue;
24922508

2493-
if (Type *matching_type = ResolveType(die, true, true))
2509+
if (Type *matching_type = ResolveType(die, true, true)) {
24942510
// We found a type pointer, now find the shared pointer form our type
24952511
// list.
24962512
types.InsertUnique(matching_type->shared_from_this());
2513+
}
24972514
}
2515+
2516+
// Next search through the reachable Clang modules. This only applies for
2517+
// DWARF objects compiled with -gmodules that haven't been processed by
2518+
// dsymutil.
2519+
UpdateExternalModuleListIfNeeded();
2520+
2521+
for (const auto &pair : m_external_type_modules)
2522+
if (ModuleSP external_module_sp = pair.second)
2523+
external_module_sp->FindTypes(pattern, languages, searched_symbol_files,
2524+
types);
24982525
}
24992526

25002527
CompilerDeclContext

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ class SymbolFileDWARF : public lldb_private::SymbolFile,
105105

106106
bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
107107

108-
void
109-
ForEachExternalModule(lldb_private::CompileUnit &comp_unit,
110-
llvm::function_ref<void(lldb::ModuleSP)> f) override;
108+
bool ForEachExternalModule(
109+
lldb_private::CompileUnit &, llvm::DenseSet<lldb_private::SymbolFile *> &,
110+
llvm::function_ref<bool(lldb_private::Module &)>) override;
111111

112112
bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
113113
lldb_private::FileSpecList &support_files) override;

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -652,12 +652,15 @@ bool SymbolFileDWARFDebugMap::ParseDebugMacros(CompileUnit &comp_unit) {
652652
return false;
653653
}
654654

655-
void SymbolFileDWARFDebugMap::ForEachExternalModule(
656-
CompileUnit &comp_unit, llvm::function_ref<void(ModuleSP)> f) {
655+
bool SymbolFileDWARFDebugMap::ForEachExternalModule(
656+
CompileUnit &comp_unit,
657+
llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files,
658+
llvm::function_ref<bool(Module &)> f) {
657659
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
658660
SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
659661
if (oso_dwarf)
660-
oso_dwarf->ForEachExternalModule(comp_unit, f);
662+
return oso_dwarf->ForEachExternalModule(comp_unit, visited_symbol_files, f);
663+
return false;
661664
}
662665

663666
bool SymbolFileDWARFDebugMap::ParseSupportFiles(CompileUnit &comp_unit,
@@ -1183,6 +1186,16 @@ void SymbolFileDWARFDebugMap::FindTypes(
11831186
});
11841187
}
11851188

1189+
void SymbolFileDWARFDebugMap::FindTypes(
1190+
llvm::ArrayRef<CompilerContext> context, LanguageSet languages,
1191+
llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
1192+
TypeMap &types) {
1193+
ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
1194+
oso_dwarf->FindTypes(context, languages, searched_symbol_files, types);
1195+
return false;
1196+
});
1197+
}
1198+
11861199
//
11871200
// uint32_t
11881201
// SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile {
5353

5454
bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
5555

56-
void
57-
ForEachExternalModule(lldb_private::CompileUnit &comp_unit,
58-
llvm::function_ref<void(lldb::ModuleSP)> f) override;
56+
bool ForEachExternalModule(
57+
lldb_private::CompileUnit &, llvm::DenseSet<lldb_private::SymbolFile *> &,
58+
llvm::function_ref<bool(lldb_private::Module &)>) override;
5959

6060
bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
6161
lldb_private::FileSpecList &support_files) override;
@@ -114,6 +114,11 @@ class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile {
114114
uint32_t max_matches,
115115
llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
116116
lldb_private::TypeMap &types) override;
117+
void
118+
FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> context,
119+
lldb_private::LanguageSet languages,
120+
llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
121+
lldb_private::TypeMap &types) override;
117122
lldb_private::CompilerDeclContext FindNamespace(
118123
lldb_private::ConstString name,
119124
const lldb_private::CompilerDeclContext *parent_decl_ctx) override;

lldb/source/Symbol/CompileUnit.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,9 +379,12 @@ const std::vector<SourceModule> &CompileUnit::GetImportedModules() {
379379
return m_imported_modules;
380380
}
381381

382-
void CompileUnit::ForEachExternalModule(llvm::function_ref<void(ModuleSP)> f) {
382+
bool CompileUnit::ForEachExternalModule(
383+
llvm::DenseSet<SymbolFile *> &visited_symbol_files,
384+
llvm::function_ref<bool(Module &)> lambda) {
383385
if (SymbolFile *symfile = GetModule()->GetSymbolFile())
384-
symfile->ForEachExternalModule(*this, f);
386+
return symfile->ForEachExternalModule(*this, visited_symbol_files, lambda);
387+
return false;
385388
}
386389

387390
const FileSpecList &CompileUnit::GetSupportFiles() {

0 commit comments

Comments
 (0)