@@ -755,6 +755,230 @@ size_t ModuleList::GetIndexForModule(const Module *module) const {
755
755
}
756
756
757
757
namespace {
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
+
758
982
struct SharedModuleListInfo {
759
983
ModuleList module_list;
760
984
ModuleListProperties module_list_properties;
0 commit comments