1717#include " lldb/Interpreter/Property.h"
1818#include " lldb/Symbol/ObjectFile.h"
1919#include " lldb/Symbol/SymbolContext.h"
20+ #include " lldb/Symbol/SymbolFile.h"
2021#include " lldb/Symbol/TypeList.h"
2122#include " lldb/Symbol/VariableList.h"
2223#include " lldb/Utility/ArchSpec.h"
2728#include " lldb/Utility/Log.h"
2829#include " lldb/Utility/UUID.h"
2930#include " lldb/lldb-defines.h"
31+ #include " lldb/lldb-private-enumerations.h"
3032#include " llvm/ADT/ScopeExit.h"
33+ #include " llvm/Support/Error.h"
3134#include " llvm/Support/FileUtilities.h"
3235
3336#if defined(_WIN32)
@@ -304,6 +307,11 @@ FileSpec ModuleListProperties::GetCASOnDiskPath() const {
304307 return GetPropertyAtIndexAs<FileSpec>(idx, {});
305308}
306309
310+ bool ModuleListProperties::SetCASOnDiskPath (const FileSpec &path) {
311+ const uint32_t idx = ePropertyCASOnDiskPath;
312+ return SetPropertyAtIndex (idx, path);
313+ }
314+
307315FileSpec ModuleListProperties::GetCASPluginPath () const {
308316 const uint32_t idx = ePropertyCASPluginPath;
309317 return GetPropertyAtIndexAs<FileSpec>(idx, {});
@@ -1278,6 +1286,16 @@ class SharedModuleList {
12781286 continue ;
12791287 ModuleList to_remove = RemoveOrphansFromVector (vec);
12801288 remove_count += to_remove.GetSize ();
1289+ // BEGIN CAS
1290+ to_remove.ForEach ([&](auto &m) {
1291+ auto it = m_cas_configs.find (m.get ());
1292+ if (it != m_cas_configs.end ()) {
1293+ m_cas_cache.erase (it->second .get ());
1294+ m_cas_configs.erase (it);
1295+ }
1296+ return IterationAction::Continue;
1297+ });
1298+ // END CAS
12811299 m_list.Remove (to_remove);
12821300 }
12831301 // Break when fixed-point is reached.
@@ -1292,14 +1310,29 @@ class SharedModuleList {
12921310 // / filename, for fast module lookups by name.
12931311 llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1 >> m_name_to_modules;
12941312
1313+ // BEGIN CAS
1314+ public:
1315+ // / Each module may have a CAS config associated with it.
1316+ // / Often many modules share the same CAS.
1317+ llvm::DenseMap<const Module *, std::shared_ptr<llvm::cas::CASConfiguration>>
1318+ m_cas_configs;
1319+
1320+ // / Each CAS config has a CAS associated with it.
1321+ llvm::DenseMap<const llvm::cas::CASConfiguration *,
1322+ std::pair<std::shared_ptr<llvm::cas::ObjectStore>,
1323+ std::shared_ptr<llvm::cas::ActionCache>>>
1324+ m_cas_cache;
1325+
1326+ private:
1327+ // END CAS
1328+
12951329 // / The use count of a module held only by m_list and m_name_to_modules.
12961330 static constexpr long kUseCountSharedModuleListOrphaned = 2 ;
12971331};
12981332
12991333struct SharedModuleListInfo {
13001334 SharedModuleList module_list;
13011335 ModuleListProperties module_list_properties;
1302- std::shared_ptr<llvm::cas::ObjectStore> cas_object_store;
13031336 std::mutex shared_lock;
13041337};
13051338}
@@ -1322,45 +1355,24 @@ static SharedModuleList &GetSharedModuleList() {
13221355 return GetSharedModuleListInfo ().module_list ;
13231356}
13241357
1325- std::optional <llvm::cas::CASConfiguration>
1326- ModuleList:: GetCASConfiguration (FileSpec CandidateConfigSearchPath) {
1358+ static std::shared_ptr <llvm::cas::CASConfiguration>
1359+ GetCASConfiguration (FileSpec CandidateConfigSearchPath) {
13271360 // Config CAS from properties.
1328- llvm::cas::CASConfiguration cas_config;
1329- cas_config.CASPath =
1330- ModuleList::GetGlobalModuleListProperties ().GetCASOnDiskPath ().GetPath ();
1331- cas_config.PluginPath =
1332- ModuleList::GetGlobalModuleListProperties ().GetCASPluginPath ().GetPath ();
1333- cas_config.PluginOptions =
1334- ModuleList::GetGlobalModuleListProperties ().GetCASPluginOptions ();
1335-
1336- if (!cas_config.CASPath .empty ())
1337- return cas_config;
1338-
1361+ auto &props = ModuleList::GetGlobalModuleListProperties ();
1362+ auto path = props.GetCASOnDiskPath ().GetPath ();
1363+ if (!path.empty ()) {
1364+ auto config = std::make_shared<llvm::cas::CASConfiguration>();
1365+ config->CASPath = props.GetCASOnDiskPath ().GetPath ();
1366+ config->PluginPath = props.GetCASPluginPath ().GetPath ();
1367+ config->PluginOptions = props.GetCASPluginOptions ();
1368+ return config;
1369+ }
13391370 auto search_config = llvm::cas::CASConfiguration::createFromSearchConfigFile (
13401371 CandidateConfigSearchPath.GetPath ());
13411372 if (search_config)
1342- return search_config->second ;
1373+ return std::make_shared<llvm::cas::CASConfiguration>( search_config->second ) ;
13431374
1344- return std::nullopt ;
1345- }
1346-
1347- static llvm::Expected<std::shared_ptr<llvm::cas::ObjectStore>>
1348- GetOrCreateCASStorage (FileSpec CandidateConfigSearchPath) {
1349- auto &shared_module_list = GetSharedModuleListInfo ();
1350- if (shared_module_list.cas_object_store )
1351- return shared_module_list.cas_object_store ;
1352-
1353- auto config = ModuleList::GetCASConfiguration (CandidateConfigSearchPath);
1354- if (!config)
1355- return nullptr ;
1356-
1357- auto cas = config->createDatabases ();
1358- if (!cas)
1359- return cas.takeError ();
1360-
1361- std::scoped_lock<std::mutex> lock (shared_module_list.shared_lock );
1362- shared_module_list.cas_object_store = std::move (cas->first );
1363- return shared_module_list.cas_object_store ;
1375+ return {};
13641376}
13651377
13661378ModuleListProperties &ModuleList::GetGlobalModuleListProperties () {
@@ -1634,19 +1646,18 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
16341646 return error;
16351647}
16361648
1637- static llvm::Expected<bool > loadModuleFromCAS (ConstString module_name,
1638- llvm::StringRef cas_id,
1639- FileSpec cu_path,
1640- ModuleSpec &module_spec) {
1641- auto maybe_cas = GetOrCreateCASStorage (cu_path);
1649+ static llvm::Expected<bool > loadModuleFromCASImpl (llvm::StringRef cas_id,
1650+ const lldb::ModuleSP &nearby,
1651+ ModuleSpec &module_spec) {
1652+ auto maybe_cas = ModuleList::GetOrCreateCAS (nearby);
16421653 if (!maybe_cas)
16431654 return maybe_cas.takeError ();
16441655
1645- auto cas = std::move (* maybe_cas);
1656+ auto cas = std::move (maybe_cas-> object_store );
16461657 if (!cas) {
16471658 LLDB_LOG (GetLog (LLDBLog::Modules),
16481659 " skip loading module '{0}' from CAS: CAS is not available" ,
1649- module_name );
1660+ cas_id );
16501661 return false ;
16511662 }
16521663
@@ -1670,15 +1681,131 @@ static llvm::Expected<bool> loadModuleFromCAS(ConstString module_name,
16701681 loaded.GetArchitecture () = module_spec.GetArchitecture ();
16711682 module_spec = loaded;
16721683
1673- LLDB_LOG (GetLog (LLDBLog::Modules), " loading module '{0}' using CASID '{1 }'" ,
1674- module_name, cas_id);
1684+ LLDB_LOG (GetLog (LLDBLog::Modules), " loading module using CASID '{0 }'" ,
1685+ cas_id);
16751686 return true ;
16761687}
16771688
1689+ // / Load the module referenced by \c cas_id from a CAS located
1690+ // / near \c nearby.
1691+ static llvm::Expected<bool > loadModuleFromCAS (llvm::StringRef cas_id,
1692+ const lldb::ModuleSP &nearby,
1693+ ModuleSpec &module_spec) {
1694+ static llvm::StringMap<bool > g_cache;
1695+ static std::recursive_mutex g_cache_lock;
1696+ std::scoped_lock<std::recursive_mutex> lock (g_cache_lock);
1697+ auto cached = g_cache.find (cas_id);
1698+ if (cached != g_cache.end ())
1699+ return cached->second ;
1700+ auto result = loadModuleFromCASImpl (cas_id, nearby, module_spec);
1701+ // Errors are only returned the first time.
1702+ g_cache.insert ({cas_id, result ? *result : false });
1703+ return result;
1704+ }
1705+
1706+ static std::shared_ptr<llvm::cas::CASConfiguration>
1707+ FindCASConfiguration (const ModuleSP &module_sp) {
1708+ auto get_dir = [](FileSpec path) {
1709+ path.ClearFilename ();
1710+ return path;
1711+ };
1712+
1713+ // Look near the binary / dSYM.
1714+ std::set<FileSpec> unique_paths;
1715+ std::shared_ptr<llvm::cas::CASConfiguration> cas_config =
1716+ GetCASConfiguration (module_sp->GetFileSpec ());
1717+
1718+ if (!cas_config) {
1719+ // Look near the object files.
1720+ auto insert_module_path = [&](const ModuleSP &m) -> IterationAction {
1721+ if (m)
1722+ unique_paths.insert (get_dir (m->GetFileSpec ()));
1723+ return IterationAction::Continue;
1724+ };
1725+
1726+ if (SymbolFile *sf = module_sp->GetSymbolFile ()) {
1727+ sf->GetDebugInfoModules ().ForEach (insert_module_path);
1728+ for (auto &path : unique_paths)
1729+ if ((cas_config = GetCASConfiguration (path)))
1730+ break ;
1731+ }
1732+ }
1733+ if (!cas_config)
1734+ for (auto &path : unique_paths) {
1735+ llvm::StringRef parent = path.GetDirectory ().GetStringRef ();
1736+ while (!parent.empty () &&
1737+ llvm::sys::path::filename (parent) != " DerivedData" )
1738+ parent = llvm::sys::path::parent_path (parent);
1739+ if (parent.empty ())
1740+ continue ;
1741+ llvm::SmallString<256 > cas_path (parent);
1742+ llvm::sys::path::append (cas_path, " CompilationCache.noindex" , " builtin" );
1743+ FileSpec fs = FileSpec (cas_path);
1744+ ModuleList::GetGlobalModuleListProperties ().SetCASOnDiskPath (fs);
1745+ cas_config = GetCASConfiguration (fs);
1746+ if (cas_config)
1747+ break ;
1748+ }
1749+ return cas_config;
1750+ }
1751+
1752+ llvm::Expected<ModuleList::CAS>
1753+ ModuleList::GetOrCreateCAS (const ModuleSP &module_sp) {
1754+ if (!module_sp)
1755+ return llvm::createStringError (" no lldb::Module available" );
1756+
1757+ // Look in cache first.
1758+ auto &shared_module_list = GetSharedModuleListInfo ();
1759+ std::scoped_lock<std::mutex> lock (shared_module_list.shared_lock );
1760+ auto &cas_configs = shared_module_list.module_list .m_cas_configs ;
1761+ auto &cas_cache = shared_module_list.module_list .m_cas_cache ;
1762+
1763+ std::shared_ptr<llvm::cas::CASConfiguration> cas_config;
1764+ {
1765+ auto cached_config = cas_configs.find (module_sp.get ());
1766+ if (cached_config != cas_configs.end ()) {
1767+ cas_config = cached_config->second ;
1768+ if (!cas_config)
1769+ return llvm::createStringError (" no CAS available (cached)" );
1770+ }
1771+ }
1772+
1773+ if (!cas_config) {
1774+ cas_config = FindCASConfiguration (module_sp);
1775+ // Cache the config or lack thereof.
1776+ cas_configs.insert ({module_sp.get (), cas_config});
1777+ }
1778+
1779+ if (!cas_config)
1780+ return llvm::createStringError (" no CAS available" );
1781+
1782+ // Look in the cache.
1783+ {
1784+ auto cached = cas_cache.find (cas_config.get ());
1785+ if (cached != cas_cache.end ()) {
1786+ if (!cached->second .first )
1787+ return llvm::createStringError (
1788+ " CAS config created, but CAS not available (cached)" );
1789+ return ModuleList::CAS{cas_config, cached->second .first ,
1790+ cached->second .second };
1791+ }
1792+ }
1793+
1794+ // Create the CAS.
1795+ auto cas = cas_config->createDatabases ();
1796+ if (!cas) {
1797+ cas_cache.insert ({cas_config.get (), {}});
1798+ return cas.takeError ();
1799+ }
1800+
1801+ cas_cache.insert ({cas_config.get (), {cas->first , cas->second }});
1802+ return ModuleList::CAS{cas_config, cas->first , cas->second };
1803+ }
1804+
16781805llvm::Expected<bool > ModuleList::GetSharedModuleFromCAS (
1679- ConstString module_name, llvm::StringRef cas_id, FileSpec cu_path ,
1806+ llvm::StringRef cas_id, const lldb::ModuleSP &nearby ,
16801807 ModuleSpec &module_spec, lldb::ModuleSP &module_sp) {
1681- auto loaded = loadModuleFromCAS (module_name, cas_id, cu_path , module_spec);
1808+ auto loaded = loadModuleFromCAS (cas_id, nearby , module_spec);
16821809 if (!loaded)
16831810 return loaded.takeError ();
16841811
@@ -1688,8 +1815,17 @@ llvm::Expected<bool> ModuleList::GetSharedModuleFromCAS(
16881815 auto status =
16891816 GetSharedModule (module_spec, module_sp, nullptr , nullptr , nullptr ,
16901817 /* always_create=*/ true );
1691- if (status.Success ())
1818+ if (status.Success ()) {
1819+ if (module_sp) {
1820+ // Enter the new module into the config cache.
1821+ auto &shared_module_list = GetSharedModuleListInfo ();
1822+ std::scoped_lock<std::mutex> lock (shared_module_list.shared_lock );
1823+ auto &cas_configs = shared_module_list.module_list .m_cas_configs ;
1824+ auto config = cas_configs.lookup (nearby.get ());
1825+ cas_configs.insert ({module_sp.get (), config});
1826+ }
16921827 return true ;
1828+ }
16931829 return status.takeError ();
16941830}
16951831
0 commit comments