[Lldb-commits] [lldb] Reland "[NFC][lldb] Speed up lookup of shared modules" (229d860) (PR #152607)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Fri Aug 8 09:11:31 PDT 2025
================
@@ -755,6 +755,235 @@ size_t ModuleList::GetIndexForModule(const Module *module) const {
}
namespace {
+/// A wrapper around ModuleList for shared modules. Provides fast lookups for
+/// file-based ModuleSpec queries.
+class SharedModuleList {
+public:
+ /// Finds all the modules matching the module_spec, and adds them to \p
+ /// matching_module_list.
+ void FindModules(const ModuleSpec &module_spec,
+ ModuleList &matching_module_list) const {
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ // Try map first for performance - if found, skip expensive full list
+ // search.
+ if (FindModulesInMap(module_spec, matching_module_list))
+ return;
+ m_list.FindModules(module_spec, matching_module_list);
+ // Assert that modules were found in the list but not the map, it's
+ // because the module_spec has no filename or the found module has a
+ // different filename. For example, when searching by UUID and finding a
+ // module with an alias.
+ assert((matching_module_list.IsEmpty() ||
+ module_spec.GetFileSpec().GetFilename().IsEmpty() ||
+ module_spec.GetFileSpec().GetFilename() !=
+ matching_module_list.GetModuleAtIndex(0)
+ ->GetFileSpec()
+ .GetFilename()) &&
+ "Search by name not found in SharedModuleList's map");
+ }
+
+ ModuleSP FindModule(const Module *module_ptr) {
+ if (!module_ptr)
+ return ModuleSP();
+
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ if (ModuleSP result = FindModuleInMap(module_ptr))
+ return result;
+ return m_list.FindModule(module_ptr);
+ }
+
+ // UUID searches bypass map since UUIDs aren't indexed by filename.
+ ModuleSP FindModule(const UUID &uuid) const {
+ return m_list.FindModule(uuid);
+ }
+
+ void Append(const ModuleSP &module_sp, bool use_notifier) {
+ if (!module_sp)
+ return;
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ m_list.Append(module_sp, use_notifier);
+ AddToMap(module_sp);
+ }
+
+ size_t RemoveOrphans(bool mandatory) {
+ std::unique_lock<std::recursive_mutex> lock(GetMutex(), std::defer_lock);
+ if (mandatory) {
+ lock.lock();
+ } else {
+ if (!lock.try_lock())
+ return 0;
+ }
+ size_t total_count = 0;
+ size_t run_count;
+ do {
+ // Remove indexed orphans first, then remove non-indexed orphans. This
+ // order is important because the shared count will be different if a
+ // module is indexed or not.
+ run_count = RemoveOrphansFromMapAndList();
+ run_count += m_list.RemoveOrphans(mandatory);
+ total_count += run_count;
+ // Because removing orphans might make new orphans, remove from both
+ // containers until a fixed-point is reached.
+ } while (run_count != 0);
+
+ return total_count;
+ }
+
+ bool Remove(const ModuleSP &module_sp, bool use_notifier = true) {
+ if (!module_sp)
+ return false;
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ RemoveFromMap(module_sp.get());
+ return m_list.Remove(module_sp, use_notifier);
+ }
+
+ void ReplaceEquivalent(const ModuleSP &module_sp,
+ llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) {
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ m_list.ReplaceEquivalent(module_sp, old_modules);
+ ReplaceEquivalentInMap(module_sp);
+ }
+
+ bool RemoveIfOrphaned(const Module *module_ptr) {
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ RemoveFromMap(module_ptr, /*if_orphaned=*/true);
+ return m_list.RemoveIfOrphaned(module_ptr);
+ }
+
+ std::recursive_mutex &GetMutex() const { return m_list.GetMutex(); }
+
+private:
+ ModuleSP FindModuleInMap(const Module *module_ptr) const {
+ if (!module_ptr->GetFileSpec().GetFilename())
+ return ModuleSP();
+ ConstString name = module_ptr->GetFileSpec().GetFilename();
+ auto it = m_name_to_modules.find(name);
+ if (it == m_name_to_modules.end())
+ return ModuleSP();
+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second;
+ for (const ModuleSP &module_sp : vector) {
+ if (module_sp.get() == module_ptr)
+ return module_sp;
+ }
+ return ModuleSP();
+ }
+
+ bool FindModulesInMap(const ModuleSpec &module_spec,
+ ModuleList &matching_module_list) const {
+ auto it = m_name_to_modules.find(module_spec.GetFileSpec().GetFilename());
+ if (it == m_name_to_modules.end())
+ return false;
+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second;
+ bool found = false;
+ for (const ModuleSP &module_sp : vector) {
+ if (module_sp->MatchesModuleSpec(module_spec)) {
+ matching_module_list.Append(module_sp);
+ found = true;
+ }
+ }
+ return found;
+ }
+
+ void AddToMap(const ModuleSP &module_sp) {
+ ConstString name = module_sp->GetFileSpec().GetFilename();
+ if (name.IsEmpty())
+ return;
+ m_name_to_modules[name].push_back(module_sp);
+ }
+
+ void RemoveFromMap(const Module *module_ptr, bool if_orphaned = false) {
+ if (!module_ptr)
+ return;
+ ConstString name = module_ptr->GetFileSpec().GetFilename();
+ if (!m_name_to_modules.contains(name))
+ return;
+ llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
+ for (auto *it = vec.begin(); it != vec.end(); ++it) {
+ if (it->get() == module_ptr) {
+ // use_count == 2 means only held by map and list (orphaned).
+ constexpr long kUseCountOrphaned = 2;
----------------
JDevlieghere wrote:
Make this a static outside the function so you don't have to repeat it in `RemoveOrphansFromVector` as that kind of defeats the purpose of a constant.
https://github.com/llvm/llvm-project/pull/152607
More information about the lldb-commits
mailing list