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_module_configs.find (m.get ());
1292+ if (it != m_module_configs.end ()) {
1293+ m_cas_cache.erase (it->second .get ());
1294+ m_module_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,31 @@ 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_module_configs;
1319+
1320+ llvm::StringMap<std::weak_ptr<llvm::cas::CASConfiguration>> m_cas_configs;
1321+
1322+ // / Each CAS config has a CAS associated with it.
1323+ llvm::DenseMap<const llvm::cas::CASConfiguration *,
1324+ std::pair<std::shared_ptr<llvm::cas::ObjectStore>,
1325+ std::shared_ptr<llvm::cas::ActionCache>>>
1326+ m_cas_cache;
1327+
1328+ private:
1329+ // END CAS
1330+
12951331 // / The use count of a module held only by m_list and m_name_to_modules.
12961332 static constexpr long kUseCountSharedModuleListOrphaned = 2 ;
12971333};
12981334
12991335struct SharedModuleListInfo {
13001336 SharedModuleList module_list;
13011337 ModuleListProperties module_list_properties;
1302- std::shared_ptr<llvm::cas::ObjectStore> cas_object_store;
13031338 std::mutex shared_lock;
13041339};
13051340}
@@ -1322,45 +1357,24 @@ static SharedModuleList &GetSharedModuleList() {
13221357 return GetSharedModuleListInfo ().module_list ;
13231358}
13241359
1325- std::optional <llvm::cas::CASConfiguration>
1326- ModuleList:: GetCASConfiguration (FileSpec CandidateConfigSearchPath) {
1360+ static std::shared_ptr <llvm::cas::CASConfiguration>
1361+ GetCASConfiguration (FileSpec CandidateConfigSearchPath) {
13271362 // 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-
1363+ auto &props = ModuleList::GetGlobalModuleListProperties ();
1364+ auto path = props.GetCASOnDiskPath ().GetPath ();
1365+ if (!path.empty ()) {
1366+ auto config = std::make_shared<llvm::cas::CASConfiguration>();
1367+ config->CASPath = props.GetCASOnDiskPath ().GetPath ();
1368+ config->PluginPath = props.GetCASPluginPath ().GetPath ();
1369+ config->PluginOptions = props.GetCASPluginOptions ();
1370+ return config;
1371+ }
13391372 auto search_config = llvm::cas::CASConfiguration::createFromSearchConfigFile (
13401373 CandidateConfigSearchPath.GetPath ());
13411374 if (search_config)
1342- return search_config->second ;
1375+ return std::make_shared<llvm::cas::CASConfiguration>( search_config->second ) ;
13431376
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 ;
1377+ return {};
13641378}
13651379
13661380ModuleListProperties &ModuleList::GetGlobalModuleListProperties () {
@@ -1634,19 +1648,18 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
16341648 return error;
16351649}
16361650
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);
1651+ static llvm::Expected<bool > loadModuleFromCASImpl (llvm::StringRef cas_id,
1652+ const lldb::ModuleSP &nearby,
1653+ ModuleSpec &module_spec) {
1654+ auto maybe_cas = ModuleList::GetOrCreateCAS (nearby);
16421655 if (!maybe_cas)
16431656 return maybe_cas.takeError ();
16441657
1645- auto cas = std::move (* maybe_cas);
1658+ auto cas = std::move (maybe_cas-> object_store );
16461659 if (!cas) {
16471660 LLDB_LOG (GetLog (LLDBLog::Modules),
16481661 " skip loading module '{0}' from CAS: CAS is not available" ,
1649- module_name );
1662+ cas_id );
16501663 return false ;
16511664 }
16521665
@@ -1670,15 +1683,143 @@ static llvm::Expected<bool> loadModuleFromCAS(ConstString module_name,
16701683 loaded.GetArchitecture () = module_spec.GetArchitecture ();
16711684 module_spec = loaded;
16721685
1673- LLDB_LOG (GetLog (LLDBLog::Modules), " loading module '{0}' using CASID '{1 }'" ,
1674- module_name, cas_id);
1686+ LLDB_LOG (GetLog (LLDBLog::Modules), " loading module using CASID '{0 }'" ,
1687+ cas_id);
16751688 return true ;
16761689}
16771690
1691+ // / Load the module referenced by \c cas_id from a CAS located
1692+ // / near \c nearby.
1693+ static llvm::Expected<bool > loadModuleFromCAS (llvm::StringRef cas_id,
1694+ const lldb::ModuleSP &nearby,
1695+ ModuleSpec &module_spec) {
1696+ static llvm::StringMap<bool > g_cache;
1697+ static std::recursive_mutex g_cache_lock;
1698+ std::scoped_lock<std::recursive_mutex> lock (g_cache_lock);
1699+ auto cached = g_cache.find (cas_id);
1700+ if (cached != g_cache.end ())
1701+ return cached->second ;
1702+ auto result = loadModuleFromCASImpl (cas_id, nearby, module_spec);
1703+ // Errors are only returned the first time.
1704+ g_cache.insert ({cas_id, result ? *result : false });
1705+ return result;
1706+ }
1707+
1708+ static std::shared_ptr<llvm::cas::CASConfiguration>
1709+ FindCASConfiguration (const ModuleSP &module_sp) {
1710+ auto get_dir = [](FileSpec path) {
1711+ path.ClearFilename ();
1712+ return path;
1713+ };
1714+
1715+ // Look near the binary / dSYM.
1716+ std::set<FileSpec> unique_paths;
1717+ std::shared_ptr<llvm::cas::CASConfiguration> cas_config =
1718+ GetCASConfiguration (module_sp->GetFileSpec ());
1719+
1720+ if (!cas_config) {
1721+ // Look near the object files.
1722+ auto insert_module_path = [&](const ModuleSP &m) -> IterationAction {
1723+ if (m)
1724+ unique_paths.insert (get_dir (m->GetFileSpec ()));
1725+ return IterationAction::Continue;
1726+ };
1727+
1728+ if (SymbolFile *sf = module_sp->GetSymbolFile ()) {
1729+ sf->GetDebugInfoModules ().ForEach (insert_module_path);
1730+ for (auto &path : unique_paths)
1731+ if ((cas_config = GetCASConfiguration (path)))
1732+ break ;
1733+ }
1734+ }
1735+ if (!cas_config)
1736+ for (auto &path : unique_paths) {
1737+ llvm::StringRef parent = path.GetDirectory ().GetStringRef ();
1738+ while (!parent.empty () &&
1739+ llvm::sys::path::filename (parent) != " DerivedData" )
1740+ parent = llvm::sys::path::parent_path (parent);
1741+ if (parent.empty ())
1742+ continue ;
1743+ llvm::SmallString<256 > cas_path (parent);
1744+ llvm::sys::path::append (cas_path, " CompilationCache.noindex" , " builtin" );
1745+ FileSpec fs = FileSpec (cas_path);
1746+ ModuleList::GetGlobalModuleListProperties ().SetCASOnDiskPath (fs);
1747+ cas_config = GetCASConfiguration (fs);
1748+ if (cas_config)
1749+ break ;
1750+ }
1751+ return cas_config;
1752+ }
1753+
1754+ llvm::Expected<ModuleList::CAS>
1755+ ModuleList::GetOrCreateCAS (const ModuleSP &module_sp) {
1756+ if (!module_sp)
1757+ return llvm::createStringError (" no lldb::Module available" );
1758+
1759+ // Look in cache first.
1760+ auto &shared_module_list = GetSharedModuleListInfo ();
1761+ std::scoped_lock<std::mutex> lock (shared_module_list.shared_lock );
1762+ auto &module_configs = shared_module_list.module_list .m_module_configs ;
1763+ auto &cas_configs = shared_module_list.module_list .m_cas_configs ;
1764+ auto &cas_cache = shared_module_list.module_list .m_cas_cache ;
1765+
1766+ std::shared_ptr<llvm::cas::CASConfiguration> cas_config;
1767+ {
1768+ auto cached_config = module_configs.find (module_sp.get ());
1769+ if (cached_config != module_configs.end ()) {
1770+ cas_config = cached_config->second ;
1771+ if (!cas_config)
1772+ return llvm::createStringError (" no CAS available (cached)" );
1773+ }
1774+ }
1775+
1776+ if (!cas_config) {
1777+ cas_config = FindCASConfiguration (module_sp);
1778+ if (cas_config) {
1779+ // Unique the configuration. This assumes that no two configs
1780+ // with different plugins share the same path.
1781+ auto it = cas_configs.find (cas_config->CASPath );
1782+ if (it != cas_configs.end ())
1783+ if (auto unique_config = it->second .lock ())
1784+ cas_config = unique_config;
1785+ cas_configs.insert ({cas_config->CASPath , cas_config});
1786+ }
1787+ // Cache the config or lack thereof.
1788+ module_configs.insert ({module_sp.get (), cas_config});
1789+ }
1790+
1791+ if (!cas_config)
1792+ return llvm::createStringError (" no CAS available" );
1793+
1794+ // Look in the cache.
1795+ {
1796+ auto cached = cas_cache.find (cas_config.get ());
1797+ if (cached != cas_cache.end ()) {
1798+ if (!cached->second .first )
1799+ return llvm::createStringError (
1800+ " CAS config created, but CAS not available (cached)" );
1801+ return ModuleList::CAS{cas_config, cached->second .first ,
1802+ cached->second .second };
1803+ }
1804+ }
1805+
1806+ // Create the CAS.
1807+ auto cas = cas_config->createDatabases ();
1808+ if (!cas) {
1809+ cas_cache.insert ({cas_config.get (), {}});
1810+ return cas.takeError ();
1811+ }
1812+
1813+ LLDB_LOG (GetLog (LLDBLog::Modules | LLDBLog::Symbols),
1814+ " Initialized CAS at {0}" , cas_config->CASPath );
1815+ cas_cache.insert ({cas_config.get (), {cas->first , cas->second }});
1816+ return ModuleList::CAS{cas_config, cas->first , cas->second };
1817+ }
1818+
16781819llvm::Expected<bool > ModuleList::GetSharedModuleFromCAS (
1679- ConstString module_name, llvm::StringRef cas_id, FileSpec cu_path ,
1820+ llvm::StringRef cas_id, const lldb::ModuleSP &nearby ,
16801821 ModuleSpec &module_spec, lldb::ModuleSP &module_sp) {
1681- auto loaded = loadModuleFromCAS (module_name, cas_id, cu_path , module_spec);
1822+ auto loaded = loadModuleFromCAS (cas_id, nearby , module_spec);
16821823 if (!loaded)
16831824 return loaded.takeError ();
16841825
@@ -1688,8 +1829,17 @@ llvm::Expected<bool> ModuleList::GetSharedModuleFromCAS(
16881829 auto status =
16891830 GetSharedModule (module_spec, module_sp, nullptr , nullptr , nullptr ,
16901831 /* always_create=*/ true );
1691- if (status.Success ())
1832+ if (status.Success ()) {
1833+ if (module_sp) {
1834+ // Enter the new module into the config cache.
1835+ auto &shared_module_list = GetSharedModuleListInfo ();
1836+ std::scoped_lock<std::mutex> lock (shared_module_list.shared_lock );
1837+ auto &module_configs = shared_module_list.module_list .m_module_configs ;
1838+ auto config = module_configs.lookup (nearby.get ());
1839+ module_configs.insert ({module_sp.get (), config});
1840+ }
16921841 return true ;
1842+ }
16931843 return status.takeError ();
16941844}
16951845
0 commit comments