Skip to content

Commit fb002b7

Browse files
authored
Merge pull request #11608 from augusto2112/cp-shared-module
[lldb] Cherry pick SharedModuleList commits
2 parents b455b8b + ab65bf8 commit fb002b7

File tree

3 files changed

+255
-20
lines changed

3 files changed

+255
-20
lines changed

lldb/include/lldb/Core/ModuleList.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ class ModuleList {
477477

478478
size_t Remove(ModuleList &module_list);
479479

480-
bool RemoveIfOrphaned(const Module *module_ptr);
480+
bool RemoveIfOrphaned(const lldb::ModuleWP module_ptr);
481481

482482
size_t RemoveOrphans(bool mandatory);
483483

@@ -531,7 +531,7 @@ class ModuleList {
531531

532532
static size_t RemoveOrphanSharedModules(bool mandatory);
533533

534-
static bool RemoveSharedModuleIfOrphaned(const Module *module_ptr);
534+
static bool RemoveSharedModuleIfOrphaned(const lldb::ModuleWP module_ptr);
535535

536536
/// Applies 'callback' to each module in this ModuleList.
537537
/// If 'callback' returns false, iteration terminates.
@@ -575,6 +575,9 @@ class ModuleList {
575575

576576
Notifier *m_notifier = nullptr;
577577

578+
/// An orphaned module that lives only in the ModuleList has a count of 1.
579+
static constexpr long kUseCountModuleListOrphaned = 1;
580+
578581
public:
579582
typedef LockingAdaptedIterable<std::recursive_mutex, collection>
580583
ModuleIterable;

lldb/source/Core/ModuleList.cpp

Lines changed: 248 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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

10191022
namespace {
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+
10201253
struct 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

10471280
bool 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

13231555
bool ModuleList::LoadScriptingResourcesInTarget(Target *target,

lldb/source/Target/Target.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,9 +2600,9 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec,
26002600
m_images.Append(module_sp, notify);
26012601

26022602
for (ModuleSP &old_module_sp : replaced_modules) {
2603-
Module *old_module_ptr = old_module_sp.get();
2603+
auto old_module_wp = old_module_sp->weak_from_this();
26042604
old_module_sp.reset();
2605-
ModuleList::RemoveSharedModuleIfOrphaned(old_module_ptr);
2605+
ModuleList::RemoveSharedModuleIfOrphaned(old_module_wp);
26062606
}
26072607
} else
26082608
module_sp.reset();

0 commit comments

Comments
 (0)