@@ -503,17 +503,20 @@ bool ModuleList::ReplaceModule(const lldb::ModuleSP &old_module_sp,
503503 return true ;
504504}
505505
506- bool ModuleList::RemoveIfOrphaned (const Module *module_ptr ) {
507- if (module_ptr ) {
506+ bool ModuleList::RemoveIfOrphaned (const ModuleWP module_wp ) {
507+ if (auto module_sp = module_wp. lock () ) {
508508 std::lock_guard<std::recursive_mutex> guard (m_modules_mutex);
509509 collection::iterator pos, end = m_modules.end ();
510510 for (pos = m_modules.begin (); pos != end; ++pos) {
511- if (pos->get () == module_ptr) {
512- if (pos->use_count () == 1 ) {
511+ if (pos->get () == module_sp.get ()) {
512+ // Since module_sp increases the refcount by 1, the use count should be
513+ // the regular use count + 1.
514+ constexpr long kUseCountOrphaned = kUseCountModuleListOrphaned + 1 ;
515+ if (pos->use_count () == kUseCountOrphaned ) {
513516 pos = RemoveImpl (pos);
514517 return true ;
515- } else
516- return false ;
518+ }
519+ return false ;
517520 }
518521 }
519522 }
@@ -540,7 +543,7 @@ size_t ModuleList::RemoveOrphans(bool mandatory) {
540543 made_progress = false ;
541544 collection::iterator pos = m_modules.begin ();
542545 while (pos != m_modules.end ()) {
543- if (pos->use_count () == 1 ) {
546+ if (pos->use_count () == kUseCountModuleListOrphaned ) {
544547 pos = RemoveImpl (pos);
545548 ++remove_count;
546549 // We did make progress.
@@ -1017,8 +1020,238 @@ size_t ModuleList::GetIndexForModule(const Module *module) const {
10171020}
10181021
10191022namespace {
1023+ // / A wrapper around ModuleList for shared modules. Provides fast lookups for
1024+ // / file-based ModuleSpec queries.
1025+ class SharedModuleList {
1026+ public:
1027+ // / Finds all the modules matching the module_spec, and adds them to \p
1028+ // / matching_module_list.
1029+ void FindModules (const ModuleSpec &module_spec,
1030+ ModuleList &matching_module_list) const {
1031+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1032+ // Try map first for performance - if found, skip expensive full list
1033+ // search.
1034+ FindModulesInMap (module_spec, matching_module_list);
1035+ if (!matching_module_list.IsEmpty ())
1036+ return ;
1037+ m_list.FindModules (module_spec, matching_module_list);
1038+ // Assert that modules were found in the list but not the map, it's
1039+ // because the module_spec has no filename or the found module has a
1040+ // different filename. For example, when searching by UUID and finding a
1041+ // module with an alias.
1042+ assert ((matching_module_list.IsEmpty () ||
1043+ module_spec.GetFileSpec ().GetFilename ().IsEmpty () ||
1044+ module_spec.GetFileSpec ().GetFilename () !=
1045+ matching_module_list.GetModuleAtIndex (0 )
1046+ ->GetFileSpec ()
1047+ .GetFilename ()) &&
1048+ " Search by name not found in SharedModuleList's map" );
1049+ }
1050+
1051+ ModuleSP FindModule (const Module &module ) {
1052+
1053+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1054+ if (ModuleSP result = FindModuleInMap (module ))
1055+ return result;
1056+ return m_list.FindModule (&module );
1057+ }
1058+
1059+ // UUID searches bypass map since UUIDs aren't indexed by filename.
1060+ ModuleSP FindModule (const UUID &uuid) const {
1061+ return m_list.FindModule (uuid);
1062+ }
1063+
1064+ void Append (const ModuleSP &module_sp, bool use_notifier) {
1065+ if (!module_sp)
1066+ return ;
1067+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1068+ m_list.Append (module_sp, use_notifier);
1069+ AddToMap (module_sp);
1070+ }
1071+
1072+ size_t RemoveOrphans (bool mandatory) {
1073+ std::unique_lock<std::recursive_mutex> lock (GetMutex (), std::defer_lock);
1074+ if (mandatory) {
1075+ lock.lock ();
1076+ } else {
1077+ if (!lock.try_lock ())
1078+ return 0 ;
1079+ }
1080+ size_t total_count = 0 ;
1081+ size_t run_count;
1082+ do {
1083+ // Remove indexed orphans first, then remove non-indexed orphans. This
1084+ // order is important because the shared count will be different if a
1085+ // module is indexed or not.
1086+ run_count = RemoveOrphansFromMapAndList ();
1087+ run_count += m_list.RemoveOrphans (mandatory);
1088+ total_count += run_count;
1089+ // Because removing orphans might make new orphans, remove from both
1090+ // containers until a fixed-point is reached.
1091+ } while (run_count != 0 );
1092+
1093+ return total_count;
1094+ }
1095+
1096+ bool Remove (const ModuleSP &module_sp, bool use_notifier = true ) {
1097+ if (!module_sp)
1098+ return false ;
1099+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1100+ RemoveFromMap (module_sp);
1101+ return m_list.Remove (module_sp, use_notifier);
1102+ }
1103+
1104+ void ReplaceEquivalent (const ModuleSP &module_sp,
1105+ llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) {
1106+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1107+ m_list.ReplaceEquivalent (module_sp, old_modules);
1108+ ReplaceEquivalentInMap (module_sp);
1109+ }
1110+
1111+ bool RemoveIfOrphaned (const ModuleWP module_wp) {
1112+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1113+ RemoveFromMap (module_wp, /* if_orphaned=*/ true );
1114+ return m_list.RemoveIfOrphaned (module_wp);
1115+ }
1116+
1117+ std::recursive_mutex &GetMutex () const { return m_list.GetMutex (); }
1118+
1119+ private:
1120+ ModuleSP FindModuleInMap (const Module &module ) const {
1121+ if (!module .GetFileSpec ().GetFilename ())
1122+ return ModuleSP ();
1123+ ConstString name = module .GetFileSpec ().GetFilename ();
1124+ auto it = m_name_to_modules.find (name);
1125+ if (it == m_name_to_modules.end ())
1126+ return ModuleSP ();
1127+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second ;
1128+ for (const ModuleSP &module_sp : vector) {
1129+ if (module_sp.get () == &module )
1130+ return module_sp;
1131+ }
1132+ return ModuleSP ();
1133+ }
1134+
1135+ void FindModulesInMap (const ModuleSpec &module_spec,
1136+ ModuleList &matching_module_list) const {
1137+ auto it = m_name_to_modules.find (module_spec.GetFileSpec ().GetFilename ());
1138+ if (it == m_name_to_modules.end ())
1139+ return ;
1140+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second ;
1141+ for (const ModuleSP &module_sp : vector) {
1142+ if (module_sp->MatchesModuleSpec (module_spec))
1143+ matching_module_list.Append (module_sp);
1144+ }
1145+ }
1146+
1147+ void AddToMap (const ModuleSP &module_sp) {
1148+ ConstString name = module_sp->GetFileSpec ().GetFilename ();
1149+ if (name.IsEmpty ())
1150+ return ;
1151+ m_name_to_modules[name].push_back (module_sp);
1152+ }
1153+
1154+ void RemoveFromMap (const ModuleWP module_wp, bool if_orphaned = false ) {
1155+ if (auto module_sp = module_wp.lock ()) {
1156+ ConstString name = module_sp->GetFileSpec ().GetFilename ();
1157+ if (!m_name_to_modules.contains (name))
1158+ return ;
1159+ llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
1160+ for (auto *it = vec.begin (); it != vec.end (); ++it) {
1161+ if (it->get () == module_sp.get ()) {
1162+ // Since module_sp increases the refcount by 1, the use count should
1163+ // be the regular use count + 1.
1164+ constexpr long kUseCountOrphaned =
1165+ kUseCountSharedModuleListOrphaned + 1 ;
1166+ if (!if_orphaned || it->use_count () == kUseCountOrphaned ) {
1167+ vec.erase (it);
1168+ break ;
1169+ }
1170+ }
1171+ }
1172+ }
1173+ }
1174+
1175+ void ReplaceEquivalentInMap (const ModuleSP &module_sp) {
1176+ RemoveEquivalentModulesFromMap (module_sp);
1177+ AddToMap (module_sp);
1178+ }
1179+
1180+ void RemoveEquivalentModulesFromMap (const ModuleSP &module_sp) {
1181+ ConstString name = module_sp->GetFileSpec ().GetFilename ();
1182+ if (name.IsEmpty ())
1183+ return ;
1184+
1185+ auto it = m_name_to_modules.find (name);
1186+ if (it == m_name_to_modules.end ())
1187+ return ;
1188+
1189+ // First remove any equivalent modules. Equivalent modules are modules
1190+ // whose path, platform path and architecture match.
1191+ ModuleSpec equivalent_module_spec (module_sp->GetFileSpec (),
1192+ module_sp->GetArchitecture ());
1193+ equivalent_module_spec.GetPlatformFileSpec () =
1194+ module_sp->GetPlatformFileSpec ();
1195+
1196+ llvm::SmallVectorImpl<ModuleSP> &vec = it->second ;
1197+ llvm::erase_if (vec, [&equivalent_module_spec](ModuleSP &element) {
1198+ return element->MatchesModuleSpec (equivalent_module_spec);
1199+ });
1200+ }
1201+
1202+ // / Remove orphans from the vector and return the removed modules.
1203+ ModuleList RemoveOrphansFromVector (llvm::SmallVectorImpl<ModuleSP> &vec) {
1204+ // remove_if moves the elements that match the condition to the end of the
1205+ // container, and returns an iterator to the first element that was moved.
1206+ auto *to_remove_start = llvm::remove_if (vec, [](const ModuleSP &module ) {
1207+ return module .use_count () == kUseCountSharedModuleListOrphaned ;
1208+ });
1209+
1210+ ModuleList to_remove;
1211+ for (ModuleSP *it = to_remove_start; it != vec.end (); ++it)
1212+ to_remove.Append (*it);
1213+
1214+ vec.erase (to_remove_start, vec.end ());
1215+ return to_remove;
1216+ }
1217+
1218+ // / Remove orphans that exist in both the map and list. This does not remove
1219+ // / any orphans that exist exclusively on the list.
1220+ // /
1221+ // / The mutex must be locked by the caller.
1222+ int RemoveOrphansFromMapAndList () {
1223+ // Modules might hold shared pointers to other modules, so removing one
1224+ // module might orphan other modules. Keep removing modules until
1225+ // there are no further modules that can be removed.
1226+ int remove_count = 0 ;
1227+ int previous_remove_count;
1228+ do {
1229+ previous_remove_count = remove_count;
1230+ for (auto &[name, vec] : m_name_to_modules) {
1231+ if (vec.empty ())
1232+ continue ;
1233+ ModuleList to_remove = RemoveOrphansFromVector (vec);
1234+ remove_count += to_remove.GetSize ();
1235+ m_list.Remove (to_remove);
1236+ }
1237+ // Break when fixed-point is reached.
1238+ } while (previous_remove_count != remove_count);
1239+
1240+ return remove_count;
1241+ }
1242+
1243+ ModuleList m_list;
1244+
1245+ // / A hash map from a module's filename to all the modules that share that
1246+ // / filename, for fast module lookups by name.
1247+ llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1 >> m_name_to_modules;
1248+
1249+ // / The use count of a module held only by m_list and m_name_to_modules.
1250+ static constexpr long kUseCountSharedModuleListOrphaned = 2 ;
1251+ };
1252+
10201253struct SharedModuleListInfo {
1021- ModuleList module_list;
1254+ SharedModuleList module_list;
10221255 ModuleListProperties module_list_properties;
10231256};
10241257}
@@ -1036,7 +1269,7 @@ static SharedModuleListInfo &GetSharedModuleListInfo()
10361269 return *g_shared_module_list_info;
10371270}
10381271
1039- static ModuleList &GetSharedModuleList () {
1272+ static SharedModuleList &GetSharedModuleList () {
10401273 return GetSharedModuleListInfo ().module_list ;
10411274}
10421275
@@ -1046,8 +1279,8 @@ ModuleListProperties &ModuleList::GetGlobalModuleListProperties() {
10461279
10471280bool ModuleList::ModuleIsInCache (const Module *module_ptr) {
10481281 if (module_ptr) {
1049- ModuleList &shared_module_list = GetSharedModuleList ();
1050- return shared_module_list.FindModule (module_ptr).get () != nullptr ;
1282+ SharedModuleList &shared_module_list = GetSharedModuleList ();
1283+ return shared_module_list.FindModule (* module_ptr).get () != nullptr ;
10511284 }
10521285 return false ;
10531286}
@@ -1070,9 +1303,8 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
10701303 const FileSpecList *module_search_paths_ptr,
10711304 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
10721305 bool *did_create_ptr, bool always_create) {
1073- ModuleList &shared_module_list = GetSharedModuleList ();
1074- std::lock_guard<std::recursive_mutex> guard (
1075- shared_module_list.m_modules_mutex );
1306+ SharedModuleList &shared_module_list = GetSharedModuleList ();
1307+ std::lock_guard<std::recursive_mutex> guard (shared_module_list.GetMutex ());
10761308 char path[PATH_MAX];
10771309
10781310 Status error;
@@ -1316,8 +1548,8 @@ bool ModuleList::RemoveSharedModule(lldb::ModuleSP &module_sp) {
13161548 return GetSharedModuleList ().Remove (module_sp);
13171549}
13181550
1319- bool ModuleList::RemoveSharedModuleIfOrphaned (const Module *module_ptr ) {
1320- return GetSharedModuleList ().RemoveIfOrphaned (module_ptr );
1551+ bool ModuleList::RemoveSharedModuleIfOrphaned (const ModuleWP module_wp ) {
1552+ return GetSharedModuleList ().RemoveIfOrphaned (module_wp );
13211553}
13221554
13231555bool ModuleList::LoadScriptingResourcesInTarget (Target *target,
0 commit comments