Skip to content

Commit ce39c37

Browse files
committed
[LLDB] Set up an explicit Swift module loader
and populate it with explicitly specified Swift modules. This change allows LLDB to precisely load the explicitly built main module belonging to the current CU from disk. The mere presence of an ESML also recursively enables the same behavior for all of its dependencies, since that functionality is already implemented in the Swift compiler. This fixes a performance cliff encountered when debugging with dSYMs which contain all user modules, but none from the SDK, thus triggering an implicit build of any SDK dependencies. During the transition period this behavior can be disabled with a setting. rdar://164274588
1 parent b58b2a3 commit ce39c37

File tree

6 files changed

+117
-29
lines changed

6 files changed

+117
-29
lines changed

lldb/include/lldb/Core/ModuleList.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ class ModuleListProperties : public Properties {
8383
bool GetUseSwiftClangImporter() const;
8484
bool GetUseSwiftDWARFImporter() const;
8585
bool SetUseSwiftDWARFImporter(bool new_value);
86+
bool GetUseSwiftExplicitModuleLoader() const;
87+
bool SetUseSwiftExplicitModuleLoader(bool new_value);
8688
bool GetSwiftValidateTypeSystem() const;
8789
bool GetSwiftTypeSystemFallback() const;
8890
bool GetSwiftLoadConformances() const;

lldb/source/Core/CoreProperties.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ let Definition = "modulelist" in {
2525
def UseSwiftDWARFImporter: Property<"use-swift-dwarfimporter", "Boolean">,
2626
DefaultTrue,
2727
Desc<"Reconstruct Clang module dependencies from DWARF when debugging Swift code">;
28+
def UseSwiftExplicitModuleLoader
29+
: Property<"use-swift-explicit-module-loader", "Boolean">,
30+
DefaultTrue,
31+
Desc<"Prefer explicitly specified modules over ones found in dSYMs">;
2832
def SwiftValidateTypeSystem: Property<"swift-validate-typesystem", "Boolean">,
2933
DefaultFalse,
3034
Desc<"Validate all Swift typesystem queries. Used for testing an asserts-enabled LLDB only.">;

lldb/source/Core/ModuleList.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,17 @@ bool ModuleListProperties::SetUseSwiftDWARFImporter(bool new_value) {
199199
return SetPropertyAtIndex(idx, new_value);
200200
}
201201

202+
bool ModuleListProperties::GetUseSwiftExplicitModuleLoader() const {
203+
const uint32_t idx = ePropertyUseSwiftExplicitModuleLoader;
204+
return GetPropertyAtIndexAs<bool>(
205+
idx, g_modulelist_properties[idx].default_uint_value != 0);
206+
}
207+
208+
bool ModuleListProperties::SetUseSwiftExplicitModuleLoader(bool new_value) {
209+
const uint32_t idx = ePropertyUseSwiftExplicitModuleLoader;
210+
return SetPropertyAtIndex(idx, new_value);
211+
}
212+
202213
bool ModuleListProperties::GetSwiftValidateTypeSystem() const {
203214
const uint32_t idx = ePropertySwiftValidateTypeSystem;
204215
return GetPropertyAtIndexAs<bool>(

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,6 +1899,22 @@ void SwiftASTContext::AddExtraClangArgs(
18991899
RemoveExplicitModules(importer_options.ExtraArgs);
19001900
}
19011901

1902+
bool SwiftASTContext::IsModuleAvailableInCAS(const std::string &key) {
1903+
auto id = m_cas->parseID(key);
1904+
if (!id) {
1905+
HEALTH_LOG_PRINTF("failed to parse CASID when loading module: %s",
1906+
toString(id.takeError()).c_str());
1907+
return false;
1908+
}
1909+
auto lookup = m_action_cache->get(*id);
1910+
if (!lookup) {
1911+
HEALTH_LOG_PRINTF("module lookup failure through action cache: %s",
1912+
toString(lookup.takeError()).c_str());
1913+
return false;
1914+
}
1915+
return (bool)*lookup;
1916+
};
1917+
19021918
void SwiftASTContext::AddExtraClangCC1Args(
19031919
const std::vector<std::string> &source,
19041920
const std::vector<std::pair<std::string, bool>> module_search_paths,
@@ -1970,26 +1986,9 @@ void SwiftASTContext::AddExtraClangCC1Args(
19701986
invocation.getCASOpts().PluginOptions =
19711987
GetCASOptions().CASOpts.PluginOptions;
19721988

1973-
// Check the module availability in CAS, if not, fallback to regular load.
1974-
auto CheckModuleInCAS = [&](const std::string &key) {
1975-
auto id = m_cas->parseID(key);
1976-
if (!id) {
1977-
HEALTH_LOG_PRINTF("failed to parse CASID when loading module: %s",
1978-
toString(id.takeError()).c_str());
1979-
return false;
1980-
}
1981-
auto lookup = m_action_cache->get(*id);
1982-
if (!lookup) {
1983-
HEALTH_LOG_PRINTF("module lookup failure through action cache: %s",
1984-
toString(lookup.takeError()).c_str());
1985-
return false;
1986-
}
1987-
return (bool)*lookup;
1988-
};
1989-
19901989
use_cas_module = llvm::all_of(
19911990
invocation.getFrontendOpts().ModuleCacheKeys, [&](const auto &entry) {
1992-
auto exist = CheckModuleInCAS(entry.second);
1991+
bool exist = IsModuleAvailableInCAS(entry.second);
19931992
if (!exist)
19941993
HEALTH_LOG_PRINTF("module '%s' cannot be load "
19951994
"from CAS using key: %s, fallback to "
@@ -3748,7 +3747,6 @@ ThreadSafeASTContext SwiftASTContext::GetASTContext() {
37483747
std::string moduleCachePath =
37493748
GetCompilerInvocation().getClangModuleCachePath().str();
37503749
std::unique_ptr<swift::ClangImporter> clang_importer_up;
3751-
auto &clang_importer_options = GetClangImporterOptions();
37523750
if (!m_ast_context_up->SearchPathOpts.getSDKPath().empty() ||
37533751
TargetHasNoSDK()) {
37543752
// Create the DWARFImporterDelegate.
@@ -3848,15 +3846,34 @@ ThreadSafeASTContext SwiftASTContext::GetASTContext() {
38483846
m_ast_context_up->addModuleLoader(std::move(memory_buffer_loader_up));
38493847
}
38503848

3849+
// 2. Create the explicit swift module loader.
3850+
if (props.GetUseSwiftExplicitModuleLoader()) {
3851+
auto &search_path_opts = GetCompilerInvocation().getSearchPathOptions();
3852+
std::unique_ptr<swift::ModuleLoader> esml_up =
3853+
swift::ExplicitSwiftModuleLoader::create(
3854+
*m_ast_context_up, m_dependency_tracker.get(), loading_mode,
3855+
search_path_opts.ExplicitSwiftModuleMapPath,
3856+
search_path_opts.ExplicitSwiftModuleInputs,
3857+
/*IgnoreSwiftSourceInfo*/ false);
3858+
if (esml_up) {
3859+
m_explicit_swift_module_loader =
3860+
static_cast<swift::ExplicitSwiftModuleLoader *>(esml_up.get());
3861+
m_ast_context_up->addModuleLoader(std::move(esml_up), /*isClang=*/false,
3862+
/*isDwarf=*/false,
3863+
/*isInterface=*/false,
3864+
/*isExplicit=*/true);
3865+
}
3866+
}
3867+
38513868
// Add a module interface checker.
38523869
m_ast_context_up->addModuleInterfaceChecker(
3853-
std::make_unique<swift::ModuleInterfaceCheckerImpl>(*m_ast_context_up,
3854-
moduleCachePath, prebuiltModuleCachePath,
3855-
swift::ModuleInterfaceLoaderOptions()));
3870+
std::make_unique<swift::ModuleInterfaceCheckerImpl>(
3871+
*m_ast_context_up, moduleCachePath, prebuiltModuleCachePath,
3872+
swift::ModuleInterfaceLoaderOptions()));
38563873

3857-
// 2. Create and install the module interface loader.
3874+
// 3. Create and install the module interface loader.
38583875
//
3859-
// The ordering of 2-4 is the same as the Swift compiler's 1-3,
3876+
// The ordering of 2-4 is the same as the Swift compiler's 2-4,
38603877
// where unintuitively the serialized module loader comes before the
38613878
// module interface loader. The reason for this is that the module
38623879
// interface loader is actually 2-in-1 and secretly attempts to load
@@ -3868,21 +3885,22 @@ ThreadSafeASTContext SwiftASTContext::GetASTContext() {
38683885
if (loading_mode != swift::ModuleLoadingMode::OnlySerialized) {
38693886
std::unique_ptr<swift::ModuleLoader> module_interface_loader_up(
38703887
swift::ModuleInterfaceLoader::create(
3871-
*m_ast_context_up, *static_cast<swift::ModuleInterfaceCheckerImpl*>(
3872-
m_ast_context_up->getModuleInterfaceChecker()), m_dependency_tracker.get(),
3873-
loading_mode));
3888+
*m_ast_context_up,
3889+
*static_cast<swift::ModuleInterfaceCheckerImpl *>(
3890+
m_ast_context_up->getModuleInterfaceChecker()),
3891+
m_dependency_tracker.get(), loading_mode));
38743892
if (module_interface_loader_up)
38753893
m_ast_context_up->addModuleLoader(std::move(module_interface_loader_up));
38763894
}
38773895

3878-
// 3. Create and install the serialized module loader.
3896+
// 4. Create and install the serialized module loader.
38793897
std::unique_ptr<swift::ModuleLoader> serialized_module_loader_up(
38803898
swift::ImplicitSerializedModuleLoader::create(
38813899
*m_ast_context_up, m_dependency_tracker.get(), loading_mode));
38823900
if (serialized_module_loader_up)
38833901
m_ast_context_up->addModuleLoader(std::move(serialized_module_loader_up));
38843902

3885-
// 4. Install the clang importer.
3903+
// 5. Install the clang importer.
38863904
if (clang_importer_up) {
38873905
m_clangimporter = (swift::ClangImporter *)clang_importer_up.get();
38883906
m_ast_context_up->addModuleLoader(std::move(clang_importer_up),
@@ -4080,6 +4098,23 @@ SwiftASTContext::GetModule(const SourceModule &module, bool *cached) {
40804098
// Create a diagnostic consumer for the diagnostics produced by the import.
40814099
auto import_diags = getScopedDiagnosticConsumer();
40824100

4101+
// Is this an explicitly specified explicit Swift module?
4102+
StringRef module_path = module.search_path.GetStringRef();
4103+
bool is_esml_module = (module_path.ends_with(".swiftmodule") &&
4104+
llvm::sys::fs::exists(module_path)) ||
4105+
(m_cas && IsModuleAvailableInCAS(module_path.str()));
4106+
if (is_esml_module) {
4107+
std::string path = module_path.str();
4108+
bool unloaded = false;
4109+
if (m_explicit_swift_module_loader) {
4110+
ast->addExplicitModulePath(module_name, path);
4111+
if (auto *memory_loader = GetMemoryBufferModuleLoader())
4112+
unloaded = memory_loader->unregisterMemoryBuffer(module_name);
4113+
}
4114+
HEALTH_LOG_PRINTF("found explicit module \"%s\"%s", path.c_str(),
4115+
unloaded ? "; replacing AST section module" : "");
4116+
}
4117+
40834118
swift::ModuleDecl *module_decl = ast->getModuleByName(module_name);
40844119

40854120
// Error handling.
@@ -4102,6 +4137,16 @@ SwiftASTContext::GetModule(const SourceModule &module, bool *cached) {
41024137
LOG_PRINTF(GetLog(LLDBLog::Types), "(\"%s\") -- found %s",
41034138
module_name.c_str(), module_decl->getName().str().str().c_str());
41044139

4140+
if (is_esml_module) {
4141+
// Simulate the effect of the BypassResilience flag in the
4142+
// MemoryBufferSerializedModuleLoader. Explicitly specified
4143+
// modules are not typically produced from textual interfaces. By
4144+
// disabling resilience, the debugger can directly access private
4145+
// members.
4146+
//if (!module_decl->isBuiltFromInterface())
4147+
// module_decl->setBypassResilience();
4148+
}
4149+
41054150
m_swift_module_cache.insert({module_name, *module_decl});
41064151
return *module_decl;
41074152
}

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,9 @@ class SwiftASTContext : public TypeSystemSwift {
278278

279279
void ConfigureModuleValidation(std::vector<std::string> &extra_args);
280280

281+
/// Check whether a module with key \c key is available in CAS.
282+
bool IsModuleAvailableInCAS(const std::string &key);
283+
281284
/// Add a list of Clang arguments to the ClangImporter options and
282285
/// apply the working directory to any relative paths.
283286
void AddExtraClangArgs(
@@ -972,6 +975,7 @@ class SwiftASTContext : public TypeSystemSwift {
972975
/// Owned by the AST.
973976
swift::MemoryBufferSerializedModuleLoader *m_memory_buffer_module_loader =
974977
nullptr;
978+
swift::ModuleLoader *m_explicit_swift_module_loader = nullptr;
975979
swift::ClangImporter *m_clangimporter = nullptr;
976980
/// Wraps the clang::ASTContext owned by ClangImporter.
977981
std::shared_ptr<TypeSystemClang> m_clangimporter_typesystem;

lldb/test/API/lang/swift/explicit_modules/simple/TestSwiftExplicitModules.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,30 @@ def test(self):
1313
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
1414
self, 'Set breakpoint here', lldb.SBFileSpec('main.swift'))
1515

16+
log = self.getBuildArtifact("types.log")
17+
self.expect('log enable lldb types -f "%s"' % log)
1618
self.expect("expression c", substrs=['hello explicit'])
19+
self.filecheck('platform shell cat "%s"' % log, __file__)
20+
# CHECK: SwiftASTContextForExpressions(module: "a", cu: "main.swift"){{.*}} found explicit module {{.*}}a.swiftmodule
21+
# CHECK: SwiftASTContextForExpressions(module: "a", cu: "main.swift"){{.*}} Module import remark: loaded module 'a'; source: '{{.*}}a.swiftmodule', loaded: '{{.*}}a.swiftmodule'
1722

23+
@swiftTest
24+
def test_disable_esml(self):
25+
"""Test disabling the explicit Swift module loader"""
26+
self.build()
27+
self.expect("settings set symbols.use-swift-explicit-module-loader false")
28+
29+
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
30+
self, 'Set breakpoint here', lldb.SBFileSpec('main.swift'))
31+
32+
log = self.getBuildArtifact("types.log")
33+
self.expect('log enable lldb types -f "%s"' % log)
34+
self.expect("expression c", substrs=['hello explicit'])
35+
self.filecheck('platform shell cat "%s"' % log, __file__, '--check-prefix=DISABLED')
36+
# DISABLED: SwiftASTContextForExpressions(module: "a", cu: "main.swift"){{.*}} found explicit module {{.*}}a.swiftmodule
37+
# DISABLED: SwiftASTContextForExpressions(module: "a", cu: "main.swift"){{.*}} Module import remark: loaded module 'a'; source: 'a', loaded: 'a'
38+
39+
1840
@swiftTest
1941
@skipUnlessDarwin
2042
def test_import(self):

0 commit comments

Comments
 (0)