@@ -1017,6 +1017,230 @@ size_t ModuleList::GetIndexForModule(const Module *module) const {
10171017}
10181018
10191019namespace {
1020+ // / A wrapper around ModuleList for shared modules. Provides fast lookups for
1021+ // / file-based ModuleSpec queries.
1022+ class SharedModuleList {
1023+ public:
1024+ // / Finds all the modules matching the module_spec, and adds them to \p
1025+ // / matching_module_list.
1026+ void FindModules (const ModuleSpec &module_spec,
1027+ ModuleList &matching_module_list) const {
1028+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1029+ // Try map first for performance - if found, skip expensive full list
1030+ // search.
1031+ FindModulesInMap (module_spec, matching_module_list);
1032+ if (!matching_module_list.IsEmpty ())
1033+ return ;
1034+ m_list.FindModules (module_spec, matching_module_list);
1035+ // Assert that modules were found in the list but not the map, it's
1036+ // because the module_spec has no filename or the found module has a
1037+ // different filename. For example, when searching by UUID and finding a
1038+ // module with an alias.
1039+ assert ((matching_module_list.IsEmpty () ||
1040+ module_spec.GetFileSpec ().GetFilename ().IsEmpty () ||
1041+ module_spec.GetFileSpec ().GetFilename () !=
1042+ matching_module_list.GetModuleAtIndex (0 )
1043+ ->GetFileSpec ()
1044+ .GetFilename ()) &&
1045+ " Search by name not found in SharedModuleList's map" );
1046+ }
1047+
1048+ ModuleSP FindModule (const Module &module ) {
1049+
1050+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1051+ if (ModuleSP result = FindModuleInMap (module ))
1052+ return result;
1053+ return m_list.FindModule (&module );
1054+ }
1055+
1056+ // UUID searches bypass map since UUIDs aren't indexed by filename.
1057+ ModuleSP FindModule (const UUID &uuid) const {
1058+ return m_list.FindModule (uuid);
1059+ }
1060+
1061+ void Append (const ModuleSP &module_sp, bool use_notifier) {
1062+ if (!module_sp)
1063+ return ;
1064+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1065+ m_list.Append (module_sp, use_notifier);
1066+ AddToMap (module_sp);
1067+ }
1068+
1069+ size_t RemoveOrphans (bool mandatory) {
1070+ std::unique_lock<std::recursive_mutex> lock (GetMutex (), std::defer_lock);
1071+ if (mandatory) {
1072+ lock.lock ();
1073+ } else {
1074+ if (!lock.try_lock ())
1075+ return 0 ;
1076+ }
1077+ size_t total_count = 0 ;
1078+ size_t run_count;
1079+ do {
1080+ // Remove indexed orphans first, then remove non-indexed orphans. This
1081+ // order is important because the shared count will be different if a
1082+ // module is indexed or not.
1083+ run_count = RemoveOrphansFromMapAndList ();
1084+ run_count += m_list.RemoveOrphans (mandatory);
1085+ total_count += run_count;
1086+ // Because removing orphans might make new orphans, remove from both
1087+ // containers until a fixed-point is reached.
1088+ } while (run_count != 0 );
1089+
1090+ return total_count;
1091+ }
1092+
1093+ bool Remove (const ModuleSP &module_sp, bool use_notifier = true ) {
1094+ if (!module_sp)
1095+ return false ;
1096+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1097+ RemoveFromMap (*module_sp.get ());
1098+ return m_list.Remove (module_sp, use_notifier);
1099+ }
1100+
1101+ void ReplaceEquivalent (const ModuleSP &module_sp,
1102+ llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) {
1103+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1104+ m_list.ReplaceEquivalent (module_sp, old_modules);
1105+ ReplaceEquivalentInMap (module_sp);
1106+ }
1107+
1108+ bool RemoveIfOrphaned (const Module *module_ptr) {
1109+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
1110+ RemoveFromMap (*module_ptr, /* if_orphaned=*/ true );
1111+ return m_list.RemoveIfOrphaned (module_ptr);
1112+ }
1113+
1114+ std::recursive_mutex &GetMutex () const { return m_list.GetMutex (); }
1115+
1116+ private:
1117+ ModuleSP FindModuleInMap (const Module &module ) const {
1118+ if (!module .GetFileSpec ().GetFilename ())
1119+ return ModuleSP ();
1120+ ConstString name = module .GetFileSpec ().GetFilename ();
1121+ auto it = m_name_to_modules.find (name);
1122+ if (it == m_name_to_modules.end ())
1123+ return ModuleSP ();
1124+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second ;
1125+ for (const ModuleSP &module_sp : vector) {
1126+ if (module_sp.get () == &module )
1127+ return module_sp;
1128+ }
1129+ return ModuleSP ();
1130+ }
1131+
1132+ void FindModulesInMap (const ModuleSpec &module_spec,
1133+ ModuleList &matching_module_list) const {
1134+ auto it = m_name_to_modules.find (module_spec.GetFileSpec ().GetFilename ());
1135+ if (it == m_name_to_modules.end ())
1136+ return ;
1137+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second ;
1138+ for (const ModuleSP &module_sp : vector) {
1139+ if (module_sp->MatchesModuleSpec (module_spec))
1140+ matching_module_list.Append (module_sp);
1141+ }
1142+ }
1143+
1144+ void AddToMap (const ModuleSP &module_sp) {
1145+ ConstString name = module_sp->GetFileSpec ().GetFilename ();
1146+ if (name.IsEmpty ())
1147+ return ;
1148+ m_name_to_modules[name].push_back (module_sp);
1149+ }
1150+
1151+ void RemoveFromMap (const Module &module , bool if_orphaned = false ) {
1152+ ConstString name = module .GetFileSpec ().GetFilename ();
1153+ if (!m_name_to_modules.contains (name))
1154+ return ;
1155+ llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
1156+ for (auto *it = vec.begin (); it != vec.end (); ++it) {
1157+ if (it->get () == &module ) {
1158+ if (!if_orphaned || it->use_count () == kUseCountOrphaned ) {
1159+ vec.erase (it);
1160+ break ;
1161+ }
1162+ }
1163+ }
1164+ }
1165+
1166+ void ReplaceEquivalentInMap (const ModuleSP &module_sp) {
1167+ RemoveEquivalentModulesFromMap (module_sp);
1168+ AddToMap (module_sp);
1169+ }
1170+
1171+ void RemoveEquivalentModulesFromMap (const ModuleSP &module_sp) {
1172+ ConstString name = module_sp->GetFileSpec ().GetFilename ();
1173+ if (name.IsEmpty ())
1174+ return ;
1175+
1176+ auto it = m_name_to_modules.find (name);
1177+ if (it == m_name_to_modules.end ())
1178+ return ;
1179+
1180+ // First remove any equivalent modules. Equivalent modules are modules
1181+ // whose path, platform path and architecture match.
1182+ ModuleSpec equivalent_module_spec (module_sp->GetFileSpec (),
1183+ module_sp->GetArchitecture ());
1184+ equivalent_module_spec.GetPlatformFileSpec () =
1185+ module_sp->GetPlatformFileSpec ();
1186+
1187+ llvm::SmallVectorImpl<ModuleSP> &vec = it->second ;
1188+ llvm::erase_if (vec, [&equivalent_module_spec](ModuleSP &element) {
1189+ return element->MatchesModuleSpec (equivalent_module_spec);
1190+ });
1191+ }
1192+
1193+ // / Remove orphans from the vector and return the removed modules.
1194+ ModuleList RemoveOrphansFromVector (llvm::SmallVectorImpl<ModuleSP> &vec) {
1195+ // remove_if moves the elements that match the condition to the end of the
1196+ // container, and returns an iterator to the first element that was moved.
1197+ auto *to_remove_start = llvm::remove_if (vec, [](const ModuleSP &module ) {
1198+ return module .use_count () == kUseCountOrphaned ;
1199+ });
1200+
1201+ ModuleList to_remove;
1202+ for (ModuleSP *it = to_remove_start; it != vec.end (); ++it)
1203+ to_remove.Append (*it);
1204+
1205+ vec.erase (to_remove_start, vec.end ());
1206+ return to_remove;
1207+ }
1208+
1209+ // / Remove orphans that exist in both the map and list. This does not remove
1210+ // / any orphans that exist exclusively on the list.
1211+ // /
1212+ // / The mutex must be locked by the caller.
1213+ int RemoveOrphansFromMapAndList () {
1214+ // Modules might hold shared pointers to other modules, so removing one
1215+ // module might orphan other modules. Keep removing modules until
1216+ // there are no further modules that can be removed.
1217+ int remove_count = 0 ;
1218+ int previous_remove_count;
1219+ do {
1220+ previous_remove_count = remove_count;
1221+ for (auto &[name, vec] : m_name_to_modules) {
1222+ if (vec.empty ())
1223+ continue ;
1224+ ModuleList to_remove = RemoveOrphansFromVector (vec);
1225+ remove_count += to_remove.GetSize ();
1226+ m_list.Remove (to_remove);
1227+ }
1228+ // Break when fixed-point is reached.
1229+ } while (previous_remove_count != remove_count);
1230+
1231+ return remove_count;
1232+ }
1233+
1234+ ModuleList m_list;
1235+
1236+ // / A hash map from a module's filename to all the modules that share that
1237+ // / filename, for fast module lookups by name.
1238+ llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1 >> m_name_to_modules;
1239+
1240+ // / The use count of a module held only by m_list and m_name_to_modules.
1241+ static constexpr long kUseCountOrphaned = 2 ;
1242+ };
1243+
10201244struct SharedModuleListInfo {
10211245 ModuleList module_list;
10221246 ModuleListProperties module_list_properties;
0 commit comments