Skip to content

Commit 9048cc5

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 8a34352 commit 9048cc5

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
@@ -1896,6 +1896,22 @@ void SwiftASTContext::AddExtraClangArgs(
18961896
RemoveExplicitModules(importer_options.ExtraArgs);
18971897
}
18981898

1899+
bool SwiftASTContext::IsModuleAvailableInCAS(const std::string &key) {
1900+
auto id = m_cas->parseID(key);
1901+
if (!id) {
1902+
HEALTH_LOG_PRINTF("failed to parse CASID when loading module: %s",
1903+
toString(id.takeError()).c_str());
1904+
return false;
1905+
}
1906+
auto lookup = m_action_cache->get(*id);
1907+
if (!lookup) {
1908+
HEALTH_LOG_PRINTF("module lookup failure through action cache: %s",
1909+
toString(lookup.takeError()).c_str());
1910+
return false;
1911+
}
1912+
return (bool)*lookup;
1913+
};
1914+
18991915
void SwiftASTContext::AddExtraClangCC1Args(
19001916
const std::vector<std::string> &source,
19011917
const std::vector<std::pair<std::string, bool>> module_search_paths,
@@ -1967,26 +1983,9 @@ void SwiftASTContext::AddExtraClangCC1Args(
19671983
invocation.getCASOpts().PluginOptions =
19681984
GetCASOptions().Config.PluginOptions;
19691985

1970-
// Check the module availability in CAS, if not, fallback to regular load.
1971-
auto CheckModuleInCAS = [&](const std::string &key) {
1972-
auto id = m_cas->parseID(key);
1973-
if (!id) {
1974-
HEALTH_LOG_PRINTF("failed to parse CASID when loading module: %s",
1975-
toString(id.takeError()).c_str());
1976-
return false;
1977-
}
1978-
auto lookup = m_action_cache->get(*id);
1979-
if (!lookup) {
1980-
HEALTH_LOG_PRINTF("module lookup failure through action cache: %s",
1981-
toString(lookup.takeError()).c_str());
1982-
return false;
1983-
}
1984-
return (bool)*lookup;
1985-
};
1986-
19871986
use_cas_module = llvm::all_of(
19881987
invocation.getFrontendOpts().ModuleCacheKeys, [&](const auto &entry) {
1989-
auto exist = CheckModuleInCAS(entry.second);
1988+
bool exist = IsModuleAvailableInCAS(entry.second);
19901989
if (!exist)
19911990
HEALTH_LOG_PRINTF("module '%s' cannot be load "
19921991
"from CAS using key: %s, fallback to "
@@ -3745,7 +3744,6 @@ ThreadSafeASTContext SwiftASTContext::GetASTContext() {
37453744
std::string moduleCachePath =
37463745
GetCompilerInvocation().getClangModuleCachePath().str();
37473746
std::unique_ptr<swift::ClangImporter> clang_importer_up;
3748-
auto &clang_importer_options = GetClangImporterOptions();
37493747
if (!m_ast_context_up->SearchPathOpts.getSDKPath().empty() ||
37503748
TargetHasNoSDK()) {
37513749
// Create the DWARFImporterDelegate.
@@ -3845,15 +3843,34 @@ ThreadSafeASTContext SwiftASTContext::GetASTContext() {
38453843
m_ast_context_up->addModuleLoader(std::move(memory_buffer_loader_up));
38463844
}
38473845

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

3854-
// 2. Create and install the module interface loader.
3871+
// 3. Create and install the module interface loader.
38553872
//
3856-
// The ordering of 2-4 is the same as the Swift compiler's 1-3,
3873+
// The ordering of 2-4 is the same as the Swift compiler's 2-4,
38573874
// where unintuitively the serialized module loader comes before the
38583875
// module interface loader. The reason for this is that the module
38593876
// interface loader is actually 2-in-1 and secretly attempts to load
@@ -3865,21 +3882,22 @@ ThreadSafeASTContext SwiftASTContext::GetASTContext() {
38653882
if (loading_mode != swift::ModuleLoadingMode::OnlySerialized) {
38663883
std::unique_ptr<swift::ModuleLoader> module_interface_loader_up(
38673884
swift::ModuleInterfaceLoader::create(
3868-
*m_ast_context_up, *static_cast<swift::ModuleInterfaceCheckerImpl*>(
3869-
m_ast_context_up->getModuleInterfaceChecker()), m_dependency_tracker.get(),
3870-
loading_mode));
3885+
*m_ast_context_up,
3886+
*static_cast<swift::ModuleInterfaceCheckerImpl *>(
3887+
m_ast_context_up->getModuleInterfaceChecker()),
3888+
m_dependency_tracker.get(), loading_mode));
38713889
if (module_interface_loader_up)
38723890
m_ast_context_up->addModuleLoader(std::move(module_interface_loader_up));
38733891
}
38743892

3875-
// 3. Create and install the serialized module loader.
3893+
// 4. Create and install the serialized module loader.
38763894
std::unique_ptr<swift::ModuleLoader> serialized_module_loader_up(
38773895
swift::ImplicitSerializedModuleLoader::create(
38783896
*m_ast_context_up, m_dependency_tracker.get(), loading_mode));
38793897
if (serialized_module_loader_up)
38803898
m_ast_context_up->addModuleLoader(std::move(serialized_module_loader_up));
38813899

3882-
// 4. Install the clang importer.
3900+
// 5. Install the clang importer.
38833901
if (clang_importer_up) {
38843902
m_clangimporter = (swift::ClangImporter *)clang_importer_up.get();
38853903
m_ast_context_up->addModuleLoader(std::move(clang_importer_up),
@@ -4077,6 +4095,23 @@ SwiftASTContext::GetModule(const SourceModule &module, bool *cached) {
40774095
// Create a diagnostic consumer for the diagnostics produced by the import.
40784096
auto import_diags = getScopedDiagnosticConsumer();
40794097

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

40824117
// Error handling.
@@ -4099,6 +4134,16 @@ SwiftASTContext::GetModule(const SourceModule &module, bool *cached) {
40994134
LOG_PRINTF(GetLog(LLDBLog::Types), "(\"%s\") -- found %s",
41004135
module_name.c_str(), module_decl->getName().str().str().c_str());
41014136

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

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)