@@ -755,11 +755,244 @@ size_t ModuleList::GetIndexForModule(const Module *module) const {
755755}
756756
757757namespace {
758+ // / A wrapper around ModuleList for shared modules. Provides fast lookups for
759+ // / file-based ModuleSpec queries.
760+ class SharedModuleList {
761+ public:
762+ // / Finds all the modules matching the module_spec, and adds them to \p
763+ // / matching_module_list.
764+ void FindModules (const ModuleSpec &module_spec,
765+ ModuleList &matching_module_list) const {
766+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
767+ // Try map first for performance - if found, skip expensive full list
768+ // search
769+ if (FindModulesInMap (module_spec, matching_module_list))
770+ return ;
771+ m_list.FindModules (module_spec, matching_module_list);
772+ // Assert that modules were found in the list but not the map, it's
773+ // because the module_spec has no filename or the found module has a
774+ // different filename. For example, when searching by UUID and finding a
775+ // module with an alias.
776+ assert ((matching_module_list.IsEmpty () ||
777+ module_spec.GetFileSpec ().GetFilename ().IsEmpty () ||
778+ module_spec.GetFileSpec ().GetFilename () !=
779+ matching_module_list.GetModuleAtIndex (0 )
780+ ->GetFileSpec ()
781+ .GetFilename ()) &&
782+ " Search by name not found in SharedModuleList's map" );
783+ }
784+
785+ ModuleSP FindModule (const Module *module_ptr) {
786+ if (!module_ptr)
787+ return ModuleSP ();
788+
789+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
790+ if (ModuleSP result = FindModuleInMap (module_ptr))
791+ return result;
792+ return m_list.FindModule (module_ptr);
793+ }
794+
795+ // UUID searches bypass map since UUIDs aren't indexed by filename.
796+ ModuleSP FindModule (const UUID &uuid) const {
797+ return m_list.FindModule (uuid);
798+ }
799+
800+ void Append (const ModuleSP &module_sp, bool use_notifier) {
801+ if (!module_sp)
802+ return ;
803+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
804+ m_list.Append (module_sp, use_notifier);
805+ AddToMap (module_sp);
806+ }
807+
808+ size_t RemoveOrphans (bool mandatory) {
809+ std::unique_lock<std::recursive_mutex> lock (GetMutex (), std::defer_lock);
810+ if (mandatory) {
811+ lock.lock ();
812+ } else {
813+ if (!lock.try_lock ())
814+ return 0 ;
815+ }
816+ size_t total_count = 0 ;
817+ size_t run_count;
818+ do {
819+ // Remove indexed orphans first, then remove non-indexed orphans. This
820+ // order is important because the shared count will be different if a
821+ // module is indexed or not.
822+ run_count = RemoveOrphansFromMapAndList ();
823+ run_count += m_list.RemoveOrphans (mandatory);
824+ total_count += run_count;
825+ // Because removing orphans might make new orphans, remove from both
826+ // containers until a fixed-point is reached.
827+ } while (run_count != 0 );
828+
829+ return total_count;
830+ }
831+
832+ bool Remove (const ModuleSP &module_sp, bool use_notifier = true ) {
833+ if (!module_sp)
834+ return false ;
835+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
836+ RemoveFromMap (module_sp.get ());
837+ return m_list.Remove (module_sp, use_notifier);
838+ }
839+
840+ void ReplaceEquivalent (const ModuleSP &module_sp,
841+ llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) {
842+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
843+ m_list.ReplaceEquivalent (module_sp, old_modules);
844+ ReplaceEquivalentInMap (module_sp);
845+ }
846+
847+ bool RemoveIfOrphaned (const Module *module_ptr) {
848+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
849+ RemoveFromMap (module_ptr, /* if_orphaned =*/ true );
850+ return m_list.RemoveIfOrphaned (module_ptr);
851+ }
852+
853+ std::recursive_mutex &GetMutex () const { return m_list.GetMutex (); }
854+
855+ private:
856+ ModuleSP FindModuleInMap (const Module *module_ptr) {
857+ if (!module_ptr->GetFileSpec ().GetFilename ())
858+ return ModuleSP ();
859+ ConstString name = module_ptr->GetFileSpec ().GetFilename ();
860+ auto it = m_name_to_modules.find (name);
861+ if (it == m_name_to_modules.end ())
862+ return ModuleSP ();
863+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second ;
864+ for (auto &module_sp : vector) {
865+ if (module_sp.get () == module_ptr)
866+ return module_sp;
867+ }
868+ return ModuleSP ();
869+ }
870+
871+ bool FindModulesInMap (const ModuleSpec &module_spec,
872+ ModuleList &matching_module_list) const {
873+ auto it = m_name_to_modules.find (module_spec.GetFileSpec ().GetFilename ());
874+ if (it == m_name_to_modules.end ())
875+ return false ;
876+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second ;
877+ bool found = false ;
878+ for (auto &module_sp : vector) {
879+ if (module_sp->MatchesModuleSpec (module_spec)) {
880+ matching_module_list.Append (module_sp);
881+ found = true ;
882+ }
883+ }
884+ return found;
885+ }
886+
887+ void AddToMap (const ModuleSP &module_sp) {
888+ ConstString name = module_sp->GetFileSpec ().GetFilename ();
889+ if (name.IsEmpty ())
890+ return ;
891+ llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
892+ vec.push_back (module_sp);
893+ }
894+
895+ void RemoveFromMap (const Module *module_ptr, bool if_orphaned = false ) {
896+ ConstString name = module_ptr->GetFileSpec ().GetFilename ();
897+ auto it = m_name_to_modules.find (name);
898+ if (it == m_name_to_modules.end ())
899+ return ;
900+ llvm::SmallVectorImpl<ModuleSP> &vec = it->second ;
901+ for (auto *it = vec.begin (); it != vec.end (); ++it) {
902+ if (it->get () == module_ptr) {
903+ // use_count == 2 means only held by map and list (orphaned)
904+ if (!if_orphaned || it->use_count () == 2 )
905+ vec.erase (it);
906+ break ;
907+ }
908+ }
909+ }
910+
911+ void ReplaceEquivalentInMap (const ModuleSP &module_sp) {
912+ RemoveEquivalentModulesFromMap (module_sp);
913+ AddToMap (module_sp);
914+ }
915+
916+ void RemoveEquivalentModulesFromMap (const ModuleSP &module_sp) {
917+ ConstString name = module_sp->GetFileSpec ().GetFilename ();
918+ if (name.IsEmpty ())
919+ return ;
920+
921+ auto it = m_name_to_modules.find (name);
922+ if (it == m_name_to_modules.end ())
923+ return ;
924+
925+ // First remove any equivalent modules. Equivalent modules are modules
926+ // whose path, platform path and architecture match.
927+ ModuleSpec equivalent_module_spec (module_sp->GetFileSpec (),
928+ module_sp->GetArchitecture ());
929+ equivalent_module_spec.GetPlatformFileSpec () =
930+ module_sp->GetPlatformFileSpec ();
931+
932+ llvm::SmallVectorImpl<ModuleSP> &vec = it->second ;
933+ // Iterate backwards to minimize element shifting during removal.
934+ for (int i = vec.size () - 1 ; i >= 0 ; --i) {
935+ auto *it = vec.begin () + i;
936+ if ((*it)->MatchesModuleSpec (equivalent_module_spec))
937+ vec.erase (it);
938+ }
939+ }
940+
941+ // / Remove orphans from the vector.
942+ // /
943+ // / Returns the removed orphans.
944+ ModuleList RemoveOrphansFromVector (llvm::SmallVectorImpl<ModuleSP> &vec) {
945+ ModuleList to_remove;
946+ for (int i = vec.size () - 1 ; i >= 0 ; --i) {
947+ ModuleSP module = vec[i];
948+ long kUseCountOrphaned = 2 ;
949+ long kUseCountLocalVariable = 1 ;
950+ // use_count == 3: map + list + local variable = orphaned.
951+ if (module .use_count () == kUseCountOrphaned + kUseCountLocalVariable ) {
952+ to_remove.Append (module );
953+ vec.erase (vec.begin () + i);
954+ }
955+ }
956+ return to_remove;
957+ }
958+
959+ // / Remove orphans that exist in both the map and list. This does not remove
960+ // / any orphans that exist exclusively on the list.
961+ // /
962+ // / This assumes that the mutex is locked.
963+ int RemoveOrphansFromMapAndList () {
964+ // Modules might hold shared pointers to other modules, so removing one
965+ // module might orphan other modules. Keep removing modules until
966+ // there are no further modules that can be removed.
967+ bool made_progress = true ;
968+ int remove_count = 0 ;
969+ while (made_progress) {
970+ made_progress = false ;
971+ for (auto &[name, vec] : m_name_to_modules) {
972+ if (vec.empty ())
973+ continue ;
974+ ModuleList to_remove = RemoveOrphansFromVector (vec);
975+ remove_count += to_remove.GetSize ();
976+ made_progress = !to_remove.IsEmpty ();
977+ m_list.Remove (to_remove);
978+ }
979+ }
980+ return remove_count;
981+ }
982+
983+ ModuleList m_list;
984+
985+ // / A hash map from a module's filename to all the modules that share that
986+ // / filename, for fast module lookups by name.
987+ llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1 >> m_name_to_modules;
988+ };
989+
758990struct SharedModuleListInfo {
759- ModuleList module_list;
991+ SharedModuleList module_list;
760992 ModuleListProperties module_list_properties;
761993};
762- }
994+ } // namespace
995+
763996static SharedModuleListInfo &GetSharedModuleListInfo ()
764997{
765998 static SharedModuleListInfo *g_shared_module_list_info = nullptr ;
@@ -774,7 +1007,7 @@ static SharedModuleListInfo &GetSharedModuleListInfo()
7741007 return *g_shared_module_list_info;
7751008}
7761009
777- static ModuleList &GetSharedModuleList () {
1010+ static SharedModuleList &GetSharedModuleList () {
7781011 return GetSharedModuleListInfo ().module_list ;
7791012}
7801013
@@ -784,7 +1017,7 @@ ModuleListProperties &ModuleList::GetGlobalModuleListProperties() {
7841017
7851018bool ModuleList::ModuleIsInCache (const Module *module_ptr) {
7861019 if (module_ptr) {
787- ModuleList &shared_module_list = GetSharedModuleList ();
1020+ SharedModuleList &shared_module_list = GetSharedModuleList ();
7881021 return shared_module_list.FindModule (module_ptr).get () != nullptr ;
7891022 }
7901023 return false ;
@@ -808,9 +1041,8 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
8081041 const FileSpecList *module_search_paths_ptr,
8091042 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
8101043 bool *did_create_ptr, bool always_create) {
811- ModuleList &shared_module_list = GetSharedModuleList ();
812- std::lock_guard<std::recursive_mutex> guard (
813- shared_module_list.m_modules_mutex );
1044+ SharedModuleList &shared_module_list = GetSharedModuleList ();
1045+ std::lock_guard<std::recursive_mutex> guard (shared_module_list.GetMutex ());
8141046 char path[PATH_MAX];
8151047
8161048 Status error;
0 commit comments