Skip to content

Commit caaf170

Browse files
[lldb][SwiftASTContext] Teach clang module loading from CAS
Teach SwiftASTContext to load clang module dependencies from CAS instead of FileSystem.
1 parent d16d36c commit caaf170

File tree

3 files changed

+128
-29
lines changed

3 files changed

+128
-29
lines changed

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

Lines changed: 95 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,28 @@ static std::string GetClangModulesCacheProperty() {
913913
return std::string(path);
914914
}
915915

916+
static void ConfigureCASStorage(SwiftASTContext *m_ast_context,
917+
FileSpec CandidateConfigSearchPath) {
918+
std::string m_description;
919+
auto cas_config = ModuleList::GetCASConfiguration(CandidateConfigSearchPath);
920+
if (!cas_config) {
921+
HEALTH_LOG_PRINTF("no CAS available");
922+
return;
923+
}
924+
auto maybe_cas = cas_config->createDatabases();
925+
if (!maybe_cas) {
926+
Debugger::ReportWarning("failed to create CAS: " +
927+
toString(maybe_cas.takeError()));
928+
return;
929+
}
930+
m_ast_context->SetCASStorage(std::move(maybe_cas->first),
931+
std::move(maybe_cas->second));
932+
m_ast_context->GetCASOptions().Config = *cas_config;
933+
LOG_PRINTF(GetLog(LLDBLog::Types),
934+
"Setup CAS from module list properties with cas path: %s",
935+
cas_config->CASPath.c_str());
936+
}
937+
916938
SwiftASTContext::ScopedDiagnostics::ScopedDiagnostics(
917939
swift::DiagnosticConsumer &consumer)
918940
: m_consumer(consumer),
@@ -1930,41 +1952,81 @@ void SwiftASTContext::AddExtraClangCC1Args(
19301952
return;
19311953
}
19321954

1933-
// Clear module cache key and other CAS options to load modules from disk
1934-
// directly.
1935-
invocation.getFrontendOpts().ModuleCacheKeys.clear();
1936-
invocation.getCASOpts() = clang::CASOptions();
1937-
1938-
// Ignore CAS info inside modules when loading.
1939-
invocation.getFrontendOpts().ModuleLoadIgnoreCAS = true;
1940-
1941-
// Add options to allow clang importer to do implicit module build.
1955+
// Add options to allow ClangImporter to do implicit module build.
1956+
// This allows expression evaluator to load addition modules if needed.
19421957
invocation.getLangOpts().ImplicitModules = true;
19431958
invocation.getHeaderSearchOpts().ImplicitModuleMaps = true;
19441959
invocation.getHeaderSearchOpts().ModuleCachePath =
19451960
GetCompilerInvocation().getClangModuleCachePath().str();
19461961

1947-
// Remove non-existing modules in a systematic way.
1948-
auto CheckFileExists = [&](const std::string &file) -> bool {
1949-
if (llvm::sys::fs::exists(file))
1950-
return true;
1951-
std::string warn;
1952-
llvm::raw_string_ostream(warn)
1953-
<< "Nonexistent explicit module file " << file;
1954-
AddDiagnostic(eSeverityWarning, warn);
1955-
return false;
1956-
};
1957-
for (auto it = invocation.getHeaderSearchOpts().PrebuiltModuleFiles.begin();
1958-
it != invocation.getHeaderSearchOpts().PrebuiltModuleFiles.end();) {
1959-
if (!CheckFileExists(it->second))
1960-
it = invocation.getHeaderSearchOpts().PrebuiltModuleFiles.erase(it);
1961-
else
1962-
++it;
1962+
bool use_cas_module = m_cas && m_action_cache;
1963+
if (use_cas_module) {
1964+
// Load from CAS.
1965+
invocation.getCASOpts().CASPath = GetCASOptions().Config.CASPath;
1966+
invocation.getCASOpts().PluginPath = GetCASOptions().Config.PluginPath;
1967+
invocation.getCASOpts().PluginOptions =
1968+
GetCASOptions().Config.PluginOptions;
1969+
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+
1987+
use_cas_module = llvm::all_of(
1988+
invocation.getFrontendOpts().ModuleCacheKeys, [&](const auto &entry) {
1989+
auto exist = CheckModuleInCAS(entry.second);
1990+
if (!exist)
1991+
HEALTH_LOG_PRINTF("module '%s' cannot be load "
1992+
"from CAS using key: %s, fallback to "
1993+
"load from file system",
1994+
entry.first.c_str(), entry.second.c_str());
1995+
return exist;
1996+
});
1997+
}
1998+
1999+
if (!use_cas_module) {
2000+
// Clear module cache key and other CAS options to load modules from disk
2001+
// directly.
2002+
invocation.getFrontendOpts().ModuleCacheKeys.clear();
2003+
invocation.getCASOpts() = clang::CASOptions();
2004+
2005+
// Ignore CAS info inside modules when loading.
2006+
invocation.getFrontendOpts().ModuleLoadIgnoreCAS = true;
2007+
2008+
// Remove non-existing modules in a systematic way.
2009+
auto CheckFileExists = [&](const std::string &file) -> bool {
2010+
if (llvm::sys::fs::exists(file))
2011+
return true;
2012+
std::string warn;
2013+
llvm::raw_string_ostream(warn)
2014+
<< "Nonexistent explicit module file " << file;
2015+
AddDiagnostic(eSeverityWarning, warn);
2016+
return false;
2017+
};
2018+
for (auto it = invocation.getHeaderSearchOpts().PrebuiltModuleFiles.begin();
2019+
it != invocation.getHeaderSearchOpts().PrebuiltModuleFiles.end();) {
2020+
if (!CheckFileExists(it->second))
2021+
it = invocation.getHeaderSearchOpts().PrebuiltModuleFiles.erase(it);
2022+
else
2023+
++it;
2024+
}
2025+
invocation.getFrontendOpts().ModuleFiles.erase(
2026+
llvm::remove_if(invocation.getFrontendOpts().ModuleFiles,
2027+
[&](const auto &mod) { return !CheckFileExists(mod); }),
2028+
invocation.getFrontendOpts().ModuleFiles.end());
19632029
}
1964-
invocation.getFrontendOpts().ModuleFiles.erase(
1965-
llvm::remove_if(invocation.getFrontendOpts().ModuleFiles,
1966-
[&](const auto &mod) { return !CheckFileExists(mod); }),
1967-
invocation.getFrontendOpts().ModuleFiles.end());
19682030

19692031
invocation.generateCC1CommandLine(
19702032
[&](const llvm::Twine &arg) { dest.push_back(arg.str()); });
@@ -2546,6 +2608,8 @@ SwiftASTContext::CreateInstance(lldb::LanguageType language, Module &module,
25462608
}
25472609
}
25482610

2611+
ConfigureCASStorage(swift_ast_sp.get(), module.GetFileSpec());
2612+
25492613
// The serialized triple is the triple of the last binary
25502614
// __swiftast section that was processed. Instead of relying on
25512615
// the section contents order, we overwrite the triple in the
@@ -3027,6 +3091,8 @@ lldb::TypeSystemSP SwiftASTContext::CreateInstance(
30273091
}
30283092
}
30293093

3094+
ConfigureCASStorage(swift_ast_sp.get(), sc.module_sp->GetFileSpec());
3095+
30303096
std::string resource_dir = HostInfo::GetSwiftResourceDir(
30313097
triple, swift_ast_sp->GetPlatformSDKPath());
30323098
ConfigureResourceDirs(swift_ast_sp->GetCompilerInvocation(), resource_dir,

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,12 @@ class SwiftASTContext : public TypeSystemSwift {
311311
m_platform_sdk_path = path.str();
312312
}
313313

314+
void SetCASStorage(std::shared_ptr<llvm::cas::ObjectStore> cas,
315+
std::shared_ptr<llvm::cas::ActionCache> action_cache) {
316+
m_cas = std::move(cas);
317+
m_action_cache = std::move(action_cache);
318+
}
319+
314320
/// \return the ExtraArgs of the ClangImporterOptions.
315321
const std::vector<std::string> &GetClangArguments();
316322

@@ -987,6 +993,9 @@ class SwiftASTContext : public TypeSystemSwift {
987993
library_load_cache;
988994
/// A cache for GetCompileUnitImports();
989995
llvm::DenseSet<std::pair<Module *, lldb::user_id_t>> m_cu_imports;
996+
/// ObjectStore and ActionCache;
997+
std::shared_ptr<llvm::cas::ObjectStore> m_cas;
998+
std::shared_ptr<llvm::cas::ActionCache> m_action_cache;
990999

9911000
typedef std::map<Module *, std::vector<lldb::DataBufferSP>> ASTFileDataMap;
9921001
ASTFileDataMap m_ast_file_data_map;

lldb/test/Shell/Swift/caching.test

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,21 @@
99
# RUN: -module-name main -o %t/main
1010

1111
# RUN: %lldb %t/main -s %t/lldb.script 2>&1 | FileCheck %s
12+
13+
## Setup CAS and try loading from CAS
14+
# RUN: sed "s|DIR|%/t|g" %t/lldb.script.template > %t/lldb_2.script
15+
# RUN: %lldb %t/main -s %t/lldb_2.script 2>&1 | FileCheck %s --check-prefix=CAS-LOAD --check-prefix=CHECK
16+
17+
## Check fallback to file system.
18+
# RUN: rm -rf %t/cas
19+
# RUN: %lldb %t/main -s %t/lldb_2.script 2>&1 | FileCheck %s --check-prefix=CAS-FALLBACK --check-prefix=CHECK
20+
21+
# CAS-FALLBACK: operator()() -- module '{{.*}}' cannot be load from CAS using key
22+
# CAS-FALLBACK-SAME: fallback to load from file system
23+
# CAS-LOAD: ConfigureCASStorage() -- Setup CAS from module list properties with cas path
1224
# CHECK: LogConfiguration() -- Extra clang arguments
1325
# CHECK-COUNT-1: LogConfiguration() -- -triple
26+
# CAS-LOAD: LogConfiguration() -- -fmodule-file-cache-key
1427
# CHECK: (Int) ${{.*}} = 1
1528

1629
//--- main.swift
@@ -28,3 +41,14 @@ run
2841
# Create a SwiftASTContext
2942
expr 1
3043
quit
44+
45+
//--- lldb.script.template
46+
# Force loading from interface to simulate no binary module available.
47+
settings set symbols.swift-module-loading-mode prefer-interface
48+
settings set symbols.cas-path DIR/cas
49+
log enable lldb types
50+
b test
51+
run
52+
# Create a SwiftASTContext
53+
expr 1
54+
quit

0 commit comments

Comments
 (0)