@@ -755,6 +755,230 @@ 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+ FindModulesInMap (module_spec, matching_module_list);
770+ if (!matching_module_list.IsEmpty ())
771+ return ;
772+ m_list.FindModules (module_spec, matching_module_list);
773+ // Assert that modules were found in the list but not the map, it's
774+ // because the module_spec has no filename or the found module has a
775+ // different filename. For example, when searching by UUID and finding a
776+ // module with an alias.
777+ assert ((matching_module_list.IsEmpty () ||
778+ module_spec.GetFileSpec ().GetFilename ().IsEmpty () ||
779+ module_spec.GetFileSpec ().GetFilename () !=
780+ matching_module_list.GetModuleAtIndex (0 )
781+ ->GetFileSpec ()
782+ .GetFilename ()) &&
783+ " Search by name not found in SharedModuleList's map" );
784+ }
785+
786+ ModuleSP FindModule (const Module &module ) {
787+
788+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
789+ if (ModuleSP result = FindModuleInMap (module ))
790+ return result;
791+ return m_list.FindModule (&module );
792+ }
793+
794+ // UUID searches bypass map since UUIDs aren't indexed by filename.
795+ ModuleSP FindModule (const UUID &uuid) const {
796+ return m_list.FindModule (uuid);
797+ }
798+
799+ void Append (const ModuleSP &module_sp, bool use_notifier) {
800+ if (!module_sp)
801+ return ;
802+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
803+ m_list.Append (module_sp, use_notifier);
804+ AddToMap (module_sp);
805+ }
806+
807+ size_t RemoveOrphans (bool mandatory) {
808+ std::unique_lock<std::recursive_mutex> lock (GetMutex (), std::defer_lock);
809+ if (mandatory) {
810+ lock.lock ();
811+ } else {
812+ if (!lock.try_lock ())
813+ return 0 ;
814+ }
815+ size_t total_count = 0 ;
816+ size_t run_count;
817+ do {
818+ // Remove indexed orphans first, then remove non-indexed orphans. This
819+ // order is important because the shared count will be different if a
820+ // module is indexed or not.
821+ run_count = RemoveOrphansFromMapAndList ();
822+ run_count += m_list.RemoveOrphans (mandatory);
823+ total_count += run_count;
824+ // Because removing orphans might make new orphans, remove from both
825+ // containers until a fixed-point is reached.
826+ } while (run_count != 0 );
827+
828+ return total_count;
829+ }
830+
831+ bool Remove (const ModuleSP &module_sp, bool use_notifier = true ) {
832+ if (!module_sp)
833+ return false ;
834+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
835+ RemoveFromMap (*module_sp.get ());
836+ return m_list.Remove (module_sp, use_notifier);
837+ }
838+
839+ void ReplaceEquivalent (const ModuleSP &module_sp,
840+ llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) {
841+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
842+ m_list.ReplaceEquivalent (module_sp, old_modules);
843+ ReplaceEquivalentInMap (module_sp);
844+ }
845+
846+ bool RemoveIfOrphaned (const Module *module_ptr) {
847+ std::lock_guard<std::recursive_mutex> guard (GetMutex ());
848+ RemoveFromMap (*module_ptr, /* if_orphaned=*/ true );
849+ return m_list.RemoveIfOrphaned (module_ptr);
850+ }
851+
852+ std::recursive_mutex &GetMutex () const { return m_list.GetMutex (); }
853+
854+ private:
855+ ModuleSP FindModuleInMap (const Module &module ) const {
856+ if (!module .GetFileSpec ().GetFilename ())
857+ return ModuleSP ();
858+ ConstString name = module .GetFileSpec ().GetFilename ();
859+ auto it = m_name_to_modules.find (name);
860+ if (it == m_name_to_modules.end ())
861+ return ModuleSP ();
862+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second ;
863+ for (const ModuleSP &module_sp : vector) {
864+ if (module_sp.get () == &module )
865+ return module_sp;
866+ }
867+ return ModuleSP ();
868+ }
869+
870+ void FindModulesInMap (const ModuleSpec &module_spec,
871+ ModuleList &matching_module_list) const {
872+ auto it = m_name_to_modules.find (module_spec.GetFileSpec ().GetFilename ());
873+ if (it == m_name_to_modules.end ())
874+ return ;
875+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second ;
876+ for (const ModuleSP &module_sp : vector) {
877+ if (module_sp->MatchesModuleSpec (module_spec))
878+ matching_module_list.Append (module_sp);
879+ }
880+ }
881+
882+ void AddToMap (const ModuleSP &module_sp) {
883+ ConstString name = module_sp->GetFileSpec ().GetFilename ();
884+ if (name.IsEmpty ())
885+ return ;
886+ m_name_to_modules[name].push_back (module_sp);
887+ }
888+
889+ void RemoveFromMap (const Module &module , bool if_orphaned = false ) {
890+ ConstString name = module .GetFileSpec ().GetFilename ();
891+ if (!m_name_to_modules.contains (name))
892+ return ;
893+ llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
894+ for (auto *it = vec.begin (); it != vec.end (); ++it) {
895+ if (it->get () == &module ) {
896+ if (!if_orphaned || it->use_count () == kUseCountOrphaned ) {
897+ vec.erase (it);
898+ break ;
899+ }
900+ }
901+ }
902+ }
903+
904+ void ReplaceEquivalentInMap (const ModuleSP &module_sp) {
905+ RemoveEquivalentModulesFromMap (module_sp);
906+ AddToMap (module_sp);
907+ }
908+
909+ void RemoveEquivalentModulesFromMap (const ModuleSP &module_sp) {
910+ ConstString name = module_sp->GetFileSpec ().GetFilename ();
911+ if (name.IsEmpty ())
912+ return ;
913+
914+ auto it = m_name_to_modules.find (name);
915+ if (it == m_name_to_modules.end ())
916+ return ;
917+
918+ // First remove any equivalent modules. Equivalent modules are modules
919+ // whose path, platform path and architecture match.
920+ ModuleSpec equivalent_module_spec (module_sp->GetFileSpec (),
921+ module_sp->GetArchitecture ());
922+ equivalent_module_spec.GetPlatformFileSpec () =
923+ module_sp->GetPlatformFileSpec ();
924+
925+ llvm::SmallVectorImpl<ModuleSP> &vec = it->second ;
926+ llvm::erase_if (vec, [&equivalent_module_spec](ModuleSP &element) {
927+ return element->MatchesModuleSpec (equivalent_module_spec);
928+ });
929+ }
930+
931+ // / Remove orphans from the vector and return the removed modules.
932+ ModuleList RemoveOrphansFromVector (llvm::SmallVectorImpl<ModuleSP> &vec) {
933+ // remove_if moves the elements that match the condition to the end of the
934+ // container, and returns an iterator to the first element that was moved.
935+ auto *to_remove_start = llvm::remove_if (vec, [](const ModuleSP &module ) {
936+ return module .use_count () == kUseCountOrphaned ;
937+ });
938+
939+ ModuleList to_remove;
940+ for (ModuleSP *it = to_remove_start; it != vec.end (); ++it)
941+ to_remove.Append (*it);
942+
943+ vec.erase (to_remove_start, vec.end ());
944+ return to_remove;
945+ }
946+
947+ // / Remove orphans that exist in both the map and list. This does not remove
948+ // / any orphans that exist exclusively on the list.
949+ // /
950+ // / The mutex must be locked by the caller.
951+ int RemoveOrphansFromMapAndList () {
952+ // Modules might hold shared pointers to other modules, so removing one
953+ // module might orphan other modules. Keep removing modules until
954+ // there are no further modules that can be removed.
955+ int remove_count = 0 ;
956+ int previous_remove_count;
957+ do {
958+ previous_remove_count = remove_count;
959+ for (auto &[name, vec] : m_name_to_modules) {
960+ if (vec.empty ())
961+ continue ;
962+ ModuleList to_remove = RemoveOrphansFromVector (vec);
963+ remove_count += to_remove.GetSize ();
964+ m_list.Remove (to_remove);
965+ }
966+ // Break when fixed-point is reached.
967+ } while (previous_remove_count != remove_count);
968+
969+ return remove_count;
970+ }
971+
972+ ModuleList m_list;
973+
974+ // / A hash map from a module's filename to all the modules that share that
975+ // / filename, for fast module lookups by name.
976+ llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1 >> m_name_to_modules;
977+
978+ // / The use count of a module held only by m_list and m_name_to_modules.
979+ static constexpr long kUseCountOrphaned = 2 ;
980+ };
981+
758982struct SharedModuleListInfo {
759983 ModuleList module_list;
760984 ModuleListProperties module_list_properties;
0 commit comments