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,17 @@ 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+ if (auto config = it->second ) {
1294+ m_cas_cache.erase (config);
1295+ m_module_configs.erase (it);
1296+ }
1297+ return IterationAction::Continue;
1298+ });
1299+ // END CAS
12811300 m_list.Remove (to_remove);
12821301 }
12831302 // Break when fixed-point is reached.
@@ -1292,14 +1311,28 @@ class SharedModuleList {
12921311 // / filename, for fast module lookups by name.
12931312 llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1 >> m_name_to_modules;
12941313
1314+ // BEGIN CAS
1315+ public:
1316+ // / Each module may have a CAS config associated with it.
1317+ // / Often many modules share the same CAS.
1318+ llvm::DenseMap<const Module *, llvm::cas::CASConfiguration> m_module_configs;
1319+
1320+ // / Each CAS config has a CAS associated with it.
1321+ llvm::DenseMap<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,21 @@ static SharedModuleList &GetSharedModuleList() {
13221355 return GetSharedModuleListInfo ().module_list ;
13231356}
13241357
1325- std::optional< llvm::cas::CASConfiguration>
1326- ModuleList:: GetCASConfiguration (FileSpec CandidateConfigSearchPath) {
1358+ static 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+ return {props.GetCASOnDiskPath ().GetPath (),
1365+ props.GetCASPluginPath ().GetPath (), props.GetCASPluginOptions ()};
1366+ }
13391367 auto search_config = llvm::cas::CASConfiguration::createFromSearchConfigFile (
13401368 CandidateConfigSearchPath.GetPath ());
13411369 if (search_config)
13421370 return search_config->second ;
13431371
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 ;
1372+ return {};
13641373}
13651374
13661375ModuleListProperties &ModuleList::GetGlobalModuleListProperties () {
@@ -1634,19 +1643,18 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
16341643 return error;
16351644}
16361645
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);
1646+ static llvm::Expected<bool > loadModuleFromCASImpl (llvm::StringRef cas_id,
1647+ const lldb::ModuleSP &nearby,
1648+ ModuleSpec &module_spec) {
1649+ auto maybe_cas = ModuleList::GetOrCreateCAS (nearby);
16421650 if (!maybe_cas)
16431651 return maybe_cas.takeError ();
16441652
1645- auto cas = std::move (* maybe_cas);
1653+ auto cas = std::move (maybe_cas-> object_store );
16461654 if (!cas) {
16471655 LLDB_LOG (GetLog (LLDBLog::Modules),
16481656 " skip loading module '{0}' from CAS: CAS is not available" ,
1649- module_name );
1657+ cas_id );
16501658 return false ;
16511659 }
16521660
@@ -1665,20 +1673,142 @@ static llvm::Expected<bool> loadModuleFromCAS(ConstString module_name,
16651673 std::make_shared<DataBufferLLVM>(module_proxy->getMemoryBuffer ());
16661674
16671675 // Swap out the module_spec with the one loaded via CAS.
1668- ModuleSpec loaded (module_spec.GetFileSpec (), module_spec.GetUUID (),
1669- std::move (file_buffer));
1676+ FileSpec cas_spec;
1677+ cas_spec.SetDirectory (ConstString (maybe_cas->configuration .CASPath ));
1678+ cas_spec.SetFilename (ConstString (cas_id));
1679+ ModuleSpec loaded (cas_spec, module_spec.GetUUID (), std::move (file_buffer));
16701680 loaded.GetArchitecture () = module_spec.GetArchitecture ();
16711681 module_spec = loaded;
16721682
1673- LLDB_LOG (GetLog (LLDBLog::Modules), " loading module '{0}' using CASID '{1 }'" ,
1674- module_name, cas_id);
1683+ LLDB_LOG (GetLog (LLDBLog::Modules), " loading module using CASID '{0 }'" ,
1684+ cas_id);
16751685 return true ;
16761686}
16771687
1688+ // / Load the module referenced by \c cas_id from a CAS located
1689+ // / near \c nearby.
1690+ static llvm::Expected<bool > loadModuleFromCAS (llvm::StringRef cas_id,
1691+ const lldb::ModuleSP &nearby,
1692+ ModuleSpec &module_spec) {
1693+ static llvm::StringMap<bool > g_cache;
1694+ static std::recursive_mutex g_cache_lock;
1695+ std::scoped_lock<std::recursive_mutex> lock (g_cache_lock);
1696+ auto cached = g_cache.find (cas_id);
1697+ if (cached != g_cache.end ())
1698+ return cached->second ;
1699+ auto result = loadModuleFromCASImpl (cas_id, nearby, module_spec);
1700+ // Errors are only returned the first time.
1701+ g_cache.insert ({cas_id, result ? *result : false });
1702+ return result;
1703+ }
1704+
1705+ static llvm::cas::CASConfiguration
1706+ FindCASConfiguration (const ModuleSP &module_sp) {
1707+ auto get_dir = [](FileSpec path) {
1708+ path.ClearFilename ();
1709+ return path;
1710+ };
1711+
1712+ // Look near the binary / dSYM.
1713+ std::set<FileSpec> unique_paths;
1714+ llvm::cas::CASConfiguration cas_config =
1715+ GetCASConfiguration (module_sp->GetFileSpec ());
1716+
1717+ if (!cas_config) {
1718+ // Look near the object files.
1719+ if (SymbolFile *sf = module_sp->GetSymbolFile ()) {
1720+ sf->GetDebugInfoModules ().ForEach ([&](const ModuleSP &m) {
1721+ if (m)
1722+ unique_paths.insert (get_dir (m->GetFileSpec ()));
1723+ return IterationAction::Continue;
1724+ });
1725+ for (auto &path : unique_paths)
1726+ if ((cas_config = GetCASConfiguration (path)))
1727+ break ;
1728+ }
1729+ }
1730+ // TODO: Remove this block once the build system consistently
1731+ // generates .cas-config files.
1732+ if (!cas_config) {
1733+ unique_paths.insert (get_dir (module_sp->GetFileSpec ()));
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+ }
1750+ return cas_config;
1751+ }
1752+
1753+ llvm::Expected<ModuleList::CAS>
1754+ ModuleList::GetOrCreateCAS (const ModuleSP &module_sp) {
1755+ if (!module_sp)
1756+ return llvm::createStringError (" no lldb::Module available" );
1757+
1758+ // Look in cache first.
1759+ auto &shared_module_list = GetSharedModuleListInfo ();
1760+ std::scoped_lock<std::mutex> lock (shared_module_list.shared_lock );
1761+ auto &module_configs = shared_module_list.module_list .m_module_configs ;
1762+ auto &cas_cache = shared_module_list.module_list .m_cas_cache ;
1763+
1764+ llvm::cas::CASConfiguration cas_config;
1765+ {
1766+ auto cached_config = module_configs.find (module_sp.get ());
1767+ if (cached_config != module_configs.end ()) {
1768+ cas_config = cached_config->second ;
1769+ if (!cas_config)
1770+ return llvm::createStringError (" no CAS available (cached)" );
1771+ }
1772+ }
1773+
1774+ if (!cas_config) {
1775+ cas_config = FindCASConfiguration (module_sp);
1776+ // Cache the config or lack thereof.
1777+ module_configs.insert ({module_sp.get (), cas_config});
1778+ }
1779+
1780+ if (!cas_config)
1781+ return llvm::createStringError (" no CAS available" );
1782+
1783+ // Look in the cache.
1784+ {
1785+ auto cached = cas_cache.find (cas_config);
1786+ if (cached != cas_cache.end ()) {
1787+ if (!cached->second .first )
1788+ return llvm::createStringError (
1789+ " CAS config created, but CAS not available (cached)" );
1790+ return ModuleList::CAS{cas_config, cached->second .first ,
1791+ cached->second .second };
1792+ }
1793+ }
1794+
1795+ // Create the CAS.
1796+ auto cas = cas_config.createDatabases ();
1797+ if (!cas) {
1798+ cas_cache.insert ({cas_config, {}});
1799+ return cas.takeError ();
1800+ }
1801+
1802+ LLDB_LOG (GetLog (LLDBLog::Modules | LLDBLog::Symbols),
1803+ " Initialized CAS at {0}" , cas_config.CASPath );
1804+ cas_cache.insert ({cas_config, {cas->first , cas->second }});
1805+ return ModuleList::CAS{cas_config, cas->first , cas->second };
1806+ }
1807+
16781808llvm::Expected<bool > ModuleList::GetSharedModuleFromCAS (
1679- ConstString module_name, llvm::StringRef cas_id, FileSpec cu_path ,
1809+ llvm::StringRef cas_id, const lldb::ModuleSP &nearby ,
16801810 ModuleSpec &module_spec, lldb::ModuleSP &module_sp) {
1681- auto loaded = loadModuleFromCAS (module_name, cas_id, cu_path , module_spec);
1811+ auto loaded = loadModuleFromCAS (cas_id, nearby , module_spec);
16821812 if (!loaded)
16831813 return loaded.takeError ();
16841814
@@ -1688,8 +1818,17 @@ llvm::Expected<bool> ModuleList::GetSharedModuleFromCAS(
16881818 auto status =
16891819 GetSharedModule (module_spec, module_sp, nullptr , nullptr , nullptr ,
16901820 /* always_create=*/ true );
1691- if (status.Success ())
1821+ if (status.Success ()) {
1822+ if (module_sp) {
1823+ // Enter the new module into the config cache.
1824+ auto &shared_module_list = GetSharedModuleListInfo ();
1825+ std::scoped_lock<std::mutex> lock (shared_module_list.shared_lock );
1826+ auto &module_configs = shared_module_list.module_list .m_module_configs ;
1827+ auto config = module_configs.lookup (nearby.get ());
1828+ module_configs.insert ({module_sp.get (), config});
1829+ }
16921830 return true ;
1831+ }
16931832 return status.takeError ();
16941833}
16951834
0 commit comments