Skip to content

Commit 8063aee

Browse files
[lldb][SwiftASTContext] Teach clang module loading from CAS
Teach SwiftASTContext to load clang module dependencies from CAS instead of FileSystem.
1 parent 784f186 commit 8063aee

File tree

3 files changed

+150
-28
lines changed

3 files changed

+150
-28
lines changed

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

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

916+
static void ConfigureCASStorage(SwiftASTContext *m_ast_context,
917+
FileSpec CandidateConfigSearchPath) {
918+
// Config CAS from properties.
919+
llvm::cas::CASConfiguration cas_config;
920+
cas_config.CASPath =
921+
ModuleList::GetGlobalModuleListProperties().GetCASOnDiskPath().GetPath();
922+
cas_config.PluginPath =
923+
ModuleList::GetGlobalModuleListProperties().GetCASPluginPath().GetPath();
924+
cas_config.PluginOptions =
925+
ModuleList::GetGlobalModuleListProperties().GetCASPluginOptions();
926+
927+
auto &m_description = m_ast_context->GetDescription();
928+
929+
if (!cas_config.CASPath.empty()) {
930+
if (auto maybe_cas = cas_config.createDatabases()) {
931+
m_ast_context->SetCASStorage(std::move(maybe_cas->first),
932+
std::move(maybe_cas->second));
933+
m_ast_context->GetCASOptions().Config = cas_config;
934+
LOG_PRINTF(GetLog(LLDBLog::Types),
935+
"Setup CAS from module list properties with cas path: %s",
936+
cas_config.CASPath.c_str());
937+
return;
938+
} else
939+
llvm::consumeError(maybe_cas.takeError());
940+
}
941+
942+
// Try search from candidiate path.
943+
auto search_config = llvm::cas::CASConfiguration::createFromSearchConfigFile(
944+
CandidateConfigSearchPath.GetPath());
945+
if (!search_config)
946+
return;
947+
948+
if (auto maybe_cas = search_config->second.createDatabases()) {
949+
m_ast_context->SetCASStorage(std::move(maybe_cas->first),
950+
std::move(maybe_cas->second));
951+
m_ast_context->GetCASOptions().Config = search_config->second;
952+
LOG_PRINTF(GetLog(LLDBLog::Types), "Setup CAS from cas config file: %s",
953+
search_config->first.c_str());
954+
return;
955+
} else
956+
llvm::consumeError(maybe_cas.takeError());
957+
958+
return;
959+
}
960+
916961
SwiftASTContext::ScopedDiagnostics::ScopedDiagnostics(
917962
swift::DiagnosticConsumer &consumer)
918963
: m_consumer(consumer),
@@ -1930,41 +1975,81 @@ void SwiftASTContext::AddExtraClangCC1Args(
19301975
return;
19311976
}
19321977

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-
19411978
// Add options to allow clang importer to do implicit module build.
19421979
invocation.getLangOpts().ImplicitModules = true;
19431980
invocation.getHeaderSearchOpts().ImplicitModuleMaps = true;
19441981
invocation.getHeaderSearchOpts().ModuleCachePath =
19451982
GetCompilerInvocation().getClangModuleCachePath().str();
19461983

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;
1984+
bool use_cas_module = m_cas && m_action_cache;
1985+
if (use_cas_module) {
1986+
// Load from CAS.
1987+
invocation.getCASOpts().CASPath = GetCASOptions().Config.CASPath;
1988+
invocation.getCASOpts().PluginPath = GetCASOptions().Config.PluginPath;
1989+
invocation.getCASOpts().PluginOptions = GetCASOptions().Config.PluginOptions;
1990+
1991+
// Check the module availability in CAS, if not, fallback to regular load.
1992+
auto CheckModuleInCAS = [&](const std::string &key) {
1993+
auto id = m_cas->parseID(key);
1994+
if (!id) {
1995+
llvm::consumeError(id.takeError());
1996+
return false;
1997+
}
1998+
auto lookup = m_action_cache->get(*id);
1999+
if (!lookup) {
2000+
llvm::consumeError(lookup.takeError());
2001+
return false;
2002+
}
2003+
return (bool)*lookup;
2004+
};
2005+
2006+
use_cas_module = llvm::all_of(invocation.getFrontendOpts().ModuleCacheKeys,
2007+
[&](const auto &entry) {
2008+
auto exist = CheckModuleInCAS(entry.second);
2009+
if (!exist) {
2010+
LOG_PRINTF(
2011+
GetLog(LLDBLog::Types),
2012+
"module '%s' cannot be load "
2013+
"from CAS using key: %s, fallback to "
2014+
"load from file system",
2015+
entry.first.c_str(),
2016+
entry.second.c_str());
2017+
}
2018+
return exist;
2019+
});
2020+
}
2021+
2022+
if (!use_cas_module) {
2023+
// Clear module cache key and other CAS options to load modules from disk
2024+
// directly.
2025+
invocation.getFrontendOpts().ModuleCacheKeys.clear();
2026+
invocation.getCASOpts() = clang::CASOptions();
2027+
2028+
// Ignore CAS info inside modules when loading.
2029+
invocation.getFrontendOpts().ModuleLoadIgnoreCAS = true;
2030+
2031+
// Remove non-existing modules in a systematic way.
2032+
auto CheckFileExists = [&](const std::string &file) -> bool {
2033+
if (llvm::sys::fs::exists(file))
2034+
return true;
2035+
std::string warn;
2036+
llvm::raw_string_ostream(warn)
2037+
<< "Nonexistent explicit module file " << file;
2038+
AddDiagnostic(eSeverityWarning, warn);
2039+
return false;
2040+
};
2041+
for (auto it = invocation.getHeaderSearchOpts().PrebuiltModuleFiles.begin();
2042+
it != invocation.getHeaderSearchOpts().PrebuiltModuleFiles.end();) {
2043+
if (!CheckFileExists(it->second))
2044+
it = invocation.getHeaderSearchOpts().PrebuiltModuleFiles.erase(it);
2045+
else
2046+
++it;
2047+
}
2048+
invocation.getFrontendOpts().ModuleFiles.erase(
2049+
llvm::remove_if(invocation.getFrontendOpts().ModuleFiles,
2050+
[&](const auto &mod) { return !CheckFileExists(mod); }),
2051+
invocation.getFrontendOpts().ModuleFiles.end());
19632052
}
1964-
invocation.getFrontendOpts().ModuleFiles.erase(
1965-
llvm::remove_if(invocation.getFrontendOpts().ModuleFiles,
1966-
[&](const auto &mod) { return !CheckFileExists(mod); }),
1967-
invocation.getFrontendOpts().ModuleFiles.end());
19682053

19692054
invocation.generateCC1CommandLine(
19702055
[&](const llvm::Twine &arg) { dest.push_back(arg.str()); });
@@ -2546,6 +2631,8 @@ SwiftASTContext::CreateInstance(lldb::LanguageType language, Module &module,
25462631
}
25472632
}
25482633

2634+
ConfigureCASStorage(swift_ast_sp.get(), module.GetFileSpec());
2635+
25492636
// The serialized triple is the triple of the last binary
25502637
// __swiftast section that was processed. Instead of relying on
25512638
// the section contents order, we overwrite the triple in the
@@ -3026,6 +3113,8 @@ lldb::TypeSystemSP SwiftASTContext::CreateInstance(
30263113
}
30273114
}
30283115

3116+
ConfigureCASStorage(swift_ast_sp.get(), sc.module_sp->GetFileSpec());
3117+
30293118
std::string resource_dir = HostInfo::GetSwiftResourceDir(
30303119
triple, swift_ast_sp->GetPlatformSDKPath());
30313120
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)