[llvm] [Orc][LibResolver] Refactor resolver internals and simplify symbol resolution. (PR #169161)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 22 02:49:53 PST 2025
https://github.com/SahilPatidar created https://github.com/llvm/llvm-project/pull/169161
- Replace getLibraries() with cursor-based iteration.
- Simplify search logic and handle new libraries during scanning.
- Make symbol resolution faster with single enumeration and early exit.
>From 1d31d7a2be8a3a4ce2369746dc1e1e25073607b7 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 22 Nov 2025 15:55:51 +0530
Subject: [PATCH 1/2] [Orc][LibResolver] Refactor resolver internals and
simplify symbol resolution
---
.../Orc/TargetProcess/LibraryResolver.h | 290 ++++++++++++------
.../Orc/TargetProcess/LibraryScanner.h | 10 +-
.../Orc/TargetProcess/LibraryResolver.cpp | 257 ++++++++--------
.../Orc/TargetProcess/LibraryScanner.cpp | 48 +--
4 files changed, 358 insertions(+), 247 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
index 79cfc4832fe9a..e12bf84ed4e63 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
@@ -24,81 +24,136 @@
namespace llvm {
namespace orc {
+class LibraryManager;
-/// Manages library metadata and state for symbol resolution.
-///
-/// Tracks libraries by load state and kind (user/system), and stores
-/// associated Bloom filters and hash maps to speed up symbol lookups.
-/// Thread-safe for concurrent access.
-class LibraryManager {
+enum class LibState : uint8_t { Unloaded = 0, Loaded = 1, Queried = 2 };
+
+class LibraryInfo {
public:
- enum class LibState : uint8_t { Unloaded = 0, Loaded = 1, Queried = 2 };
+ LibraryInfo(const LibraryInfo &) = delete;
+ LibraryInfo &operator=(const LibraryInfo &) = delete;
- class LibraryInfo {
- public:
- LibraryInfo(const LibraryInfo &) = delete;
- LibraryInfo &operator=(const LibraryInfo &) = delete;
+ LibraryInfo(std::string FilePath, LibState S, PathType K,
+ std::optional<BloomFilter> Filter = std::nullopt)
+ : FilePath(std::move(FilePath)), S(S), K(K), Filter(std::move(Filter)) {}
- LibraryInfo(std::string FilePath, LibState S, PathType K,
- std::optional<BloomFilter> Filter = std::nullopt)
- : FilePath(std::move(FilePath)), S(S), K(K), Filter(std::move(Filter)) {
- }
+ StringRef getBasePath() const { return sys::path::parent_path(FilePath); }
+ StringRef getFileName() const { return sys::path::filename(FilePath); }
- StringRef getBasePath() const { return sys::path::parent_path(FilePath); }
- StringRef getFileName() const { return sys::path::filename(FilePath); }
+ std::string getFullPath() const { return FilePath; }
- std::string getFullPath() const { return FilePath; }
+ void setFilter(BloomFilter F) {
+ std::lock_guard<std::shared_mutex> Lock(Mtx);
+ if (Filter)
+ return;
+ Filter.emplace(std::move(F));
+ }
- void setFilter(BloomFilter F) {
- std::lock_guard<std::shared_mutex> Lock(Mtx);
- if (Filter)
- return;
- Filter.emplace(std::move(F));
- }
+ void ensureFilterBuilt(const BloomFilterBuilder &FB,
+ ArrayRef<StringRef> Symbols) {
+ std::lock_guard<std::shared_mutex> Lock(Mtx);
+ if (Filter)
+ return;
+ Filter.emplace(FB.build(Symbols));
+ }
- void ensureFilterBuilt(const BloomFilterBuilder &FB,
- ArrayRef<StringRef> Symbols) {
- std::lock_guard<std::shared_mutex> Lock(Mtx);
- if (Filter)
- return;
- Filter.emplace(FB.build(Symbols));
- }
+ bool mayContain(StringRef Symbol) const {
+ assert(hasFilter());
+ std::shared_lock<std::shared_mutex> Lock(Mtx);
+ return Filter->mayContain(Symbol);
+ }
- bool mayContain(StringRef Symbol) const {
- assert(hasFilter());
- std::shared_lock<std::shared_mutex> Lock(Mtx);
- return Filter->mayContain(Symbol);
- }
+ bool hasFilter() const {
+ std::shared_lock<std::shared_mutex> Lock(Mtx);
+ return Filter.has_value();
+ }
- bool hasFilter() const {
- std::shared_lock<std::shared_mutex> Lock(Mtx);
- return Filter.has_value();
- }
+ LibState getState() const { return S.load(); }
+ PathType getKind() const { return K; }
- LibState getState() const { return S.load(); }
- PathType getKind() const { return K; }
+ void setState(LibState s) { S.store(s); }
- void setState(LibState s) { S.store(s); }
+ bool operator==(const LibraryInfo &other) const {
+ return FilePath == other.FilePath;
+ }
+
+private:
+ std::string FilePath;
+ std::atomic<LibState> S;
+ PathType K;
+ std::optional<BloomFilter> Filter;
+ mutable std::shared_mutex Mtx;
+};
- bool operator==(const LibraryInfo &other) const {
- return FilePath == other.FilePath;
+class LibraryCursor {
+public:
+ LibraryCursor(const std::vector<const LibraryInfo *> &L, LibState S)
+ : Lists(L), S(S) {}
+
+ const LibraryInfo *nextValidLib() {
+ while (Pos < Lists.size()) {
+ const LibraryInfo *Lib = Lists[Pos++];
+ if (Lib->getState() == S)
+ return Lib;
}
- private:
- std::string FilePath;
- std::atomic<LibState> S;
- PathType K;
- std::optional<BloomFilter> Filter;
- mutable std::shared_mutex Mtx;
- };
+ return nullptr;
+ }
+
+ bool hasMoreValidLib() const { return Pos < Lists.size(); }
+private:
+ const std::vector<const LibraryInfo *> &Lists;
+ LibState S;
+ size_t Pos = 0; // cursor position
+};
+
+class LibraryIndex {
+ friend LibraryManager;
+
+public:
+ LibraryCursor getCursor(PathType K, LibState S) const {
+ static std::vector<const LibraryInfo *> Empty;
+ auto It = Lists.find(K);
+ if (It == Lists.end())
+ return LibraryCursor(Empty, S);
+
+ return LibraryCursor(It->second, S);
+ }
+
+ bool hasLibLeftFor(PathType K, uint32_t Idx) const {
+ auto It = Lists.find(K);
+ if (It == Lists.end())
+ return false;
+
+ const auto &L = It->second;
+ return L.size() > Idx;
+ }
+
+private:
+ void addLibrary(const LibraryInfo *Lib) {
+ Lists[Lib->getKind()].push_back(Lib);
+ }
+
+ void clear() { Lists.clear(); }
+
+ DenseMap<PathType, std::vector<const LibraryInfo *>> Lists;
+};
+
+/// Manages library metadata and state for symbol resolution.
+///
+/// Tracks libraries by load state and kind (user/system), and stores
+/// associated Bloom filters and hash maps to speed up symbol lookups.
+/// Thread-safe for concurrent access.
+class LibraryManager {
+public:
/// A read-only view of libraries filtered by state and kind.
///
/// Lets you loop over only the libraries in a map that match a given State
/// and PathType.
class FilteredView {
public:
- using Map = StringMap<std::shared_ptr<LibraryInfo>>;
+ using Map = StringMap<std::unique_ptr<LibraryInfo>>;
using Iterator = Map::const_iterator;
class FilterIterator {
public:
@@ -111,9 +166,7 @@ class LibraryManager {
return it != other.it;
}
- const std::shared_ptr<LibraryInfo> &operator*() const {
- return it->second;
- }
+ const LibraryInfo &operator*() const { return *it->second; }
FilterIterator &operator++() {
++it;
@@ -151,7 +204,8 @@ class LibraryManager {
};
private:
- StringMap<std::shared_ptr<LibraryInfo>> Libraries;
+ LibraryIndex Index;
+ StringMap<std::unique_ptr<LibraryInfo>> Libraries;
mutable std::shared_mutex Mtx;
public:
@@ -165,9 +219,11 @@ class LibraryManager {
std::unique_lock<std::shared_mutex> Lock(Mtx);
if (Libraries.count(Path) > 0)
return false;
- Libraries.insert({std::move(Path),
- std::make_shared<LibraryInfo>(Path, LibState::Unloaded,
- Kind, std::move(Filter))});
+ std::unique_ptr<LibraryInfo> Lib = std::make_unique<LibraryInfo>(
+ Path, LibState::Unloaded, Kind, std::move(Filter));
+ const LibraryInfo *Ptr = Lib.get();
+ Libraries.insert({Path, std::move(Lib)});
+ Index.addLibrary(Ptr);
return true;
}
@@ -192,16 +248,22 @@ class LibraryManager {
It->second->setState(LibState::Loaded);
}
+ void markUnloaded(StringRef Path) {
+ std::unique_lock<std::shared_mutex> Lock(Mtx);
+ if (auto It = Libraries.find(Path); It != Libraries.end())
+ It->second->setState(LibState::Unloaded);
+ }
+
void markQueried(StringRef Path) {
std::unique_lock<std::shared_mutex> Lock(Mtx);
if (auto It = Libraries.find(Path); It != Libraries.end())
It->second->setState(LibState::Queried);
}
- std::shared_ptr<LibraryInfo> getLibrary(StringRef Path) {
+ const LibraryInfo *getLibrary(StringRef Path) const {
std::shared_lock<std::shared_mutex> Lock(Mtx);
if (auto It = Libraries.find(Path); It != Libraries.end())
- return It->second;
+ return It->second.get();
return nullptr;
}
@@ -212,7 +274,7 @@ class LibraryManager {
using LibraryFilterFn = std::function<bool(const LibraryInfo &)>;
void getLibraries(LibState S, PathType K,
- std::vector<std::shared_ptr<LibraryInfo>> &Outs,
+ std::vector<const LibraryInfo *> &Outs,
LibraryFilterFn Filter = nullptr) const {
std::shared_lock<std::shared_mutex> Lock(Mtx);
for (const auto &[_, Entry] : Libraries) {
@@ -221,12 +283,16 @@ class LibraryManager {
continue;
if (Filter && !Filter(Info))
continue;
- Outs.push_back(Entry);
+ Outs.push_back(&Info);
}
}
+ LibraryCursor getCursor(PathType K, LibState S) const {
+ return Index.getCursor(K, S);
+ }
+
void forEachLibrary(const LibraryVisitor &visitor) const {
- std::unique_lock<std::shared_mutex> Lock(Mtx);
+ std::shared_lock<std::shared_mutex> Lock(Mtx);
for (const auto &[_, entry] : Libraries) {
if (!visitor(*entry))
break;
@@ -253,23 +319,21 @@ class LibraryManager {
}
};
-using LibraryInfo = LibraryManager::LibraryInfo;
-
struct SearchPlanEntry {
- LibraryManager::LibState State; // Loaded, Queried, Unloaded
- PathType Type; // User, System
+ LibState State; // Loaded, Queried, Unloaded
+ PathType Type; // User, System
};
struct SearchPolicy {
std::vector<SearchPlanEntry> Plan;
static SearchPolicy defaultPlan() {
- return {{{LibraryManager::LibState::Loaded, PathType::User},
- {LibraryManager::LibState::Queried, PathType::User},
- {LibraryManager::LibState::Unloaded, PathType::User},
- {LibraryManager::LibState::Loaded, PathType::System},
- {LibraryManager::LibState::Queried, PathType::System},
- {LibraryManager::LibState::Unloaded, PathType::System}}};
+ return {{{LibState::Loaded, PathType::User},
+ {LibState::Queried, PathType::User},
+ {LibState::Unloaded, PathType::User},
+ {LibState::Loaded, PathType::System},
+ {LibState::Queried, PathType::System},
+ {LibState::Unloaded, PathType::System}}};
}
};
@@ -299,6 +363,63 @@ struct SearchConfig {
Options(SymbolEnumeratorOptions::defaultOptions()) {}
};
+// class SearchSession {
+// std::mutex Mtx;
+// std::condition_variable Cv;
+
+// int ActiveSearchers = 0;
+// int ActiveScanners = 0;
+
+// public:
+// // Called by each search before work begins
+// void beginSearch() {
+// std::unique_lock<std::mutex> lock(Mtx);
+
+// // Wait if scanning is happening
+// Cv.wait(lock, [&] { return ActiveScanners == 0; });
+
+// ActiveSearchers++;
+// }
+
+// // Called after search completes
+// void endSearch() {
+// std::unique_lock<std::mutex> lock(Mtx);
+// ActiveSearchers--;
+// if (ActiveSearchers == 0)
+// Cv.notify_all();
+// }
+
+// void beginScan() {
+// std::unique_lock<std::mutex> lock(Mtx);
+
+// // Block until NO searchers are active
+// Cv.wait(lock, [&] { return ActiveSearchers == 0; });
+
+// ActiveScanners++;
+// }
+
+// // Scanner finished
+// void endScan() {
+// std::unique_lock<std::mutex> lock(Mtx);
+// ActiveScanners--;
+// if (ActiveScanners == 0)
+// Cv.notify_all(); // wake pending searchers
+// }
+
+// // RAII
+// struct SearchGuard {
+// SearchSession &S;
+// SearchGuard(SearchSession &s) : S(s) { S.beginSearch(); }
+// ~SearchGuard() { S.endSearch(); }
+// };
+
+// struct ScanGuard {
+// SearchSession &S;
+// ScanGuard(SearchSession &s) : S(s) { S.beginScan(); }
+// ~ScanGuard() { S.endScan(); }
+// };
+// };
+
/// Scans libraries and resolves Symbols across user and system paths.
///
/// Supports symbol enumeration and filtering via SymbolEnumerator, and tracks
@@ -314,6 +435,8 @@ class LibraryResolver {
using OnEachSymbolFn = std::function<EnumerateResult(StringRef Sym)>;
+ static bool enumerateSymbols(object::ObjectFile *Obj, OnEachSymbolFn OnEach,
+ const SymbolEnumeratorOptions &Opts);
static bool enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
const SymbolEnumeratorOptions &Opts);
};
@@ -442,9 +565,7 @@ class LibraryResolver {
<< " ({Type : ("
<< (Lib.getKind() == PathType::User ? "User" : "System")
<< ") }, { State : "
- << (Lib.getState() == LibraryManager::LibState::Loaded
- ? "Loaded"
- : "Unloaded")
+ << (Lib.getState() == LibState::Loaded ? "Loaded" : "Unloaded")
<< "})\n";
return true;
});
@@ -456,15 +577,8 @@ class LibraryResolver {
private:
bool scanLibrariesIfNeeded(PathType K, size_t BatchSize = 0);
- void resolveSymbolsInLibrary(LibraryInfo &Lib, SymbolQuery &Q,
+ void resolveSymbolsInLibrary(LibraryInfo *Lib, SymbolQuery &Q,
const SymbolEnumeratorOptions &Opts);
- bool
- symbolExistsInLibrary(const LibraryInfo &Lib, StringRef Sym,
- std::vector<std::string> *MatchedSymbols = nullptr);
-
- bool symbolExistsInLibrary(const LibraryInfo &Lib, StringRef SymName,
- std::vector<std::string> *AllSymbols,
- const SymbolEnumeratorOptions &Opts);
std::shared_ptr<LibraryPathCache> LibPathCache;
std::shared_ptr<PathResolver> LibPathResolver;
@@ -485,8 +599,8 @@ class LibraryResolutionDriver {
create(const LibraryResolver::Setup &S);
void addScanPath(const std::string &Path, PathType Kind);
- bool markLibraryLoaded(StringRef Path);
- bool markLibraryUnLoaded(StringRef Path);
+ void markLibraryLoaded(StringRef Path);
+ void markLibraryUnLoaded(StringRef Path);
bool isLibraryLoaded(StringRef Path) const {
return LR->LibMgr.isLoaded(Path);
}
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index 61aefbda35337..88ccfe30dd649 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -338,14 +338,14 @@ class LibraryScanHelper {
addBasePath(const std::string &P,
PathType Kind =
PathType::Unknown); // Add a canonical directory for scanning
- std::vector<std::shared_ptr<LibrarySearchPath>>
- getNextBatch(PathType Kind, size_t batchSize);
+ std::vector<const LibrarySearchPath *> getNextBatch(PathType Kind,
+ size_t batchSize);
bool leftToScan(PathType K) const;
void resetToScan();
bool isTrackedBasePath(StringRef P) const;
- std::vector<std::shared_ptr<LibrarySearchPath>> getAllUnits() const;
+ std::vector<const LibrarySearchPath *> getAllUnits() const;
SmallVector<StringRef> getSearchPaths() const {
SmallVector<StringRef> SearchPaths;
@@ -374,7 +374,7 @@ class LibraryScanHelper {
std::shared_ptr<LibraryPathCache> LibPathCache;
std::shared_ptr<PathResolver> LibPathResolver;
- StringMap<std::shared_ptr<LibrarySearchPath>>
+ StringMap<std::unique_ptr<LibrarySearchPath>>
LibSearchPaths; // key: canonical path
std::deque<StringRef> UnscannedUsr;
std::deque<StringRef> UnscannedSys;
@@ -461,7 +461,7 @@ class LibraryScanner {
void handleLibrary(StringRef P, PathType K, int level = 1);
- void scanBaseDir(std::shared_ptr<LibrarySearchPath> U);
+ void scanBaseDir(LibrarySearchPath *U);
};
using LibraryDepsInfo = LibraryScanner::LibraryDepsInfo;
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
index 7e1d5285463c7..510598538d643 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
@@ -57,24 +57,12 @@ void LibraryResolutionDriver::addScanPath(const std::string &Path, PathType K) {
LR->ScanHelper.addBasePath(Path, K);
}
-bool LibraryResolutionDriver::markLibraryLoaded(StringRef Path) {
- auto Lib = LR->LibMgr.getLibrary(Path);
- if (!Lib)
- return false;
-
- Lib->setState(LibraryManager::LibState::Loaded);
-
- return true;
+void LibraryResolutionDriver::markLibraryLoaded(StringRef Path) {
+ LR->LibMgr.markLoaded(Path);
}
-bool LibraryResolutionDriver::markLibraryUnLoaded(StringRef Path) {
- auto Lib = LR->LibMgr.getLibrary(Path);
- if (!Lib)
- return false;
-
- Lib->setState(LibraryManager::LibState::Unloaded);
-
- return true;
+void LibraryResolutionDriver::markLibraryUnLoaded(StringRef Path) {
+ LR->LibMgr.markUnloaded(Path);
}
void LibraryResolutionDriver::resolveSymbols(
@@ -108,25 +96,12 @@ static bool shouldIgnoreSymbol(const object::SymbolRef &Sym,
return false;
}
-bool SymbolEnumerator::enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
+bool SymbolEnumerator::enumerateSymbols(object::ObjectFile *Obj,
+ OnEachSymbolFn OnEach,
const SymbolEnumeratorOptions &Opts) {
- if (Path.empty())
+ if (!Obj)
return false;
- ObjectFileLoader ObjLoader(Path);
-
- auto ObjOrErr = ObjLoader.getObjectFile();
- if (!ObjOrErr) {
- std::string ErrMsg;
- handleAllErrors(ObjOrErr.takeError(),
- [&](const ErrorInfoBase &EIB) { ErrMsg = EIB.message(); });
- LLVM_DEBUG(dbgs() << "Failed loading object file: " << Path
- << "\nError: " << ErrMsg << "\n");
- return false;
- }
-
- object::ObjectFile *Obj = &ObjOrErr.get();
-
auto processSymbolRange =
[&](object::ObjectFile::symbol_iterator_range Range) -> EnumerateResult {
for (const auto &Sym : Range) {
@@ -180,6 +155,23 @@ bool SymbolEnumerator::enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
return true;
}
+bool SymbolEnumerator::enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
+ const SymbolEnumeratorOptions &Opts) {
+ ObjectFileLoader ObjLoader(Path);
+
+ auto ObjOrErr = ObjLoader.getObjectFile();
+ if (!ObjOrErr) {
+ std::string ErrMsg;
+ handleAllErrors(ObjOrErr.takeError(),
+ [&](const ErrorInfoBase &EIB) { ErrMsg = EIB.message(); });
+ LLVM_DEBUG(dbgs() << "Failed loading object file: " << Path
+ << "\nError: " << ErrMsg << "\n");
+ return false;
+ }
+
+ return SymbolEnumerator::enumerateSymbols(&ObjOrErr.get(), OnEach, Opts);
+}
+
class SymbolSearchContext {
public:
SymbolSearchContext(SymbolQuery &Q) : Q(Q) {}
@@ -198,80 +190,100 @@ class SymbolSearchContext {
};
void LibraryResolver::resolveSymbolsInLibrary(
- LibraryInfo &Lib, SymbolQuery &UnresolvedSymbols,
+ LibraryInfo *Lib, SymbolQuery &UnresolvedSymbols,
const SymbolEnumeratorOptions &Opts) {
LLVM_DEBUG(dbgs() << "Checking unresolved symbols "
- << " in library : " << Lib.getFileName() << "\n";);
- StringSet<> DiscoveredSymbols;
+ << " in library : " << Lib->getFileName() << "\n";);
if (!UnresolvedSymbols.hasUnresolved()) {
- LLVM_DEBUG(dbgs() << "Skipping library: " << Lib.getFullPath()
+ LLVM_DEBUG(dbgs() << "Skipping library: " << Lib->getFullPath()
<< " — unresolved symbols exist.\n";);
return;
}
- bool HasEnumerated = false;
- auto enumerateSymbolsIfNeeded = [&]() {
- if (HasEnumerated)
- return;
+ bool HadAnySym = false;
- HasEnumerated = true;
+ const auto &Unresolved = UnresolvedSymbols.getUnresolvedSymbols();
+ LLVM_DEBUG(dbgs() << "Total unresolved symbols : " << Unresolved.size()
+ << "\n";);
+ DenseSet<StringRef> CandidateSet;
+ CandidateSet.reserve(Unresolved.size());
+ for (const auto &Sym : Unresolved) {
+ LLVM_DEBUG(dbgs() << "Checking symbol '" << Sym
+ << "' in filter: " << Lib->getFullPath() << "\n";);
+ if (!Lib->hasFilter() || Lib->mayContain(Sym))
+ CandidateSet.insert(Sym);
+ }
- LLVM_DEBUG(dbgs() << "Enumerating symbols in library: " << Lib.getFullPath()
- << "\n";);
- SymbolEnumerator::enumerateSymbols(
- Lib.getFullPath(),
- [&](StringRef sym) {
- DiscoveredSymbols.insert(sym);
- return EnumerateResult::Continue;
- },
- Opts);
- };
+ if (CandidateSet.empty()) {
+ LLVM_DEBUG(dbgs() << "No symbol Exist "
+ " in library: "
+ << Lib->getFullPath() << "\n";);
+ return;
+ }
+
+ bool BuildingFilter = !Lib->hasFilter();
- if (!Lib.hasFilter()) {
- LLVM_DEBUG(dbgs() << "Building filter for library: " << Lib.getFullPath()
+ ObjectFileLoader ObjLoader(Lib->getFullPath());
+
+ auto ObjOrErr = ObjLoader.getObjectFile();
+ if (!ObjOrErr) {
+ std::string ErrMsg;
+ handleAllErrors(ObjOrErr.takeError(),
+ [&](const ErrorInfoBase &EIB) { ErrMsg = EIB.message(); });
+ LLVM_DEBUG(dbgs() << "Failed loading object file: " << Lib->getFullPath()
+ << "\nError: " << ErrMsg << "\n");
+ return;
+ }
+
+ object::ObjectFile *Obj = &ObjOrErr.get();
+
+ SmallVector<StringRef, 512> SymbolVec;
+
+ LLVM_DEBUG(dbgs() << "Enumerating symbols in library: " << Lib->getFullPath()
+ << "\n";);
+ SymbolEnumerator::enumerateSymbols(
+ Obj,
+ [&](StringRef S) {
+ // If buildingFilter, collect for filter construction.
+ if (BuildingFilter) {
+ SymbolVec.push_back(S);
+ }
+ auto It = CandidateSet.find(S);
+ if (It != CandidateSet.end()) {
+ // Resolve symbol and remove from remaining set
+ LLVM_DEBUG(dbgs() << "Symbol '" << S << "' resolved in library: "
+ << Lib->getFullPath() << "\n";);
+ UnresolvedSymbols.resolve(*It, Lib->getFullPath());
+ HadAnySym = true;
+
+ // EARLY STOP — everything matched
+ if (!BuildingFilter && !UnresolvedSymbols.hasUnresolved())
+ return EnumerateResult::Stop;
+ }
+ return EnumerateResult::Continue;
+ },
+ Opts);
+
+ if (BuildingFilter) {
+ LLVM_DEBUG(dbgs() << "Building filter for library: " << Lib->getFullPath()
<< "\n";);
- enumerateSymbolsIfNeeded();
- if (DiscoveredSymbols.empty()) {
- LLVM_DEBUG(dbgs() << " No symbols and remove library : "
- << Lib.getFullPath() << "\n";);
- LibMgr.removeLibrary(Lib.getFullPath());
+ if (SymbolVec.empty()) {
+ LLVM_DEBUG(dbgs() << " Skip : No symbols found in : "
+ << Lib->getFullPath() << "\n";);
return;
}
- SmallVector<StringRef> SymbolVec;
- SymbolVec.reserve(DiscoveredSymbols.size());
- for (const auto &KV : DiscoveredSymbols)
- SymbolVec.push_back(KV.first());
- Lib.ensureFilterBuilt(FB, SymbolVec);
+ Lib->ensureFilterBuilt(FB, SymbolVec);
LLVM_DEBUG({
- dbgs() << "DiscoveredSymbols : " << DiscoveredSymbols.size() << "\n";
- for (const auto &KV : DiscoveredSymbols)
- dbgs() << "DiscoveredSymbols : " << KV.first() << "\n";
+ dbgs() << "DiscoveredSymbols : " << SymbolVec.size() << "\n";
+ for (const auto &S : SymbolVec)
+ dbgs() << "DiscoveredSymbols : " << S << "\n";
});
}
- const auto &Unresolved = UnresolvedSymbols.getUnresolvedSymbols();
- bool HadAnySym = false;
- LLVM_DEBUG(dbgs() << "Total unresolved symbols : " << Unresolved.size()
- << "\n";);
- for (const auto &Sym : Unresolved) {
- if (Lib.mayContain(Sym)) {
- LLVM_DEBUG(dbgs() << "Checking symbol '" << Sym
- << "' in library: " << Lib.getFullPath() << "\n";);
- enumerateSymbolsIfNeeded();
- if (DiscoveredSymbols.count(Sym) > 0) {
- LLVM_DEBUG(dbgs() << " Resolved symbol: " << Sym
- << " in library: " << Lib.getFullPath() << "\n";);
- UnresolvedSymbols.resolve(Sym, Lib.getFullPath());
- HadAnySym = true;
- }
- }
- }
-
- using LibraryState = LibraryManager::LibState;
- if (HadAnySym && Lib.getState() != LibraryState::Loaded)
- Lib.setState(LibraryState::Queried);
+ if (HadAnySym && Lib->getState() != LibState::Loaded)
+ Lib->setState(LibState::Queried);
}
void LibraryResolver::searchSymbolsInLibraries(
@@ -279,30 +291,41 @@ void LibraryResolver::searchSymbolsInLibraries(
const SearchConfig &Config) {
SymbolQuery Q(SymbolList);
- using LibraryState = LibraryManager::LibState;
using LibraryType = PathType;
- auto tryResolveFrom = [&](LibraryState S, LibraryType K) {
+ auto tryResolveFrom = [&](LibState S, LibraryType K) {
LLVM_DEBUG(dbgs() << "Trying resolve from state=" << static_cast<int>(S)
<< " type=" << static_cast<int>(K) << "\n";);
SymbolSearchContext Ctx(Q);
+ LibraryCursor Cur = LibMgr.getCursor(K, S);
while (!Ctx.allResolved()) {
- std::vector<std::shared_ptr<LibraryInfo>> Libs;
- LibMgr.getLibraries(S, K, Libs, [&](const LibraryInfo &Lib) {
- return !Ctx.hasSearched(&Lib);
- });
-
- if (Libs.empty() && !scanLibrariesIfNeeded(K, scanBatchSize))
- break; // no more new libs to scan
+ const LibraryInfo *Lib = Cur.nextValidLib();
+ // Cursor not valid?
+ if (!Lib) {
+ bool NewLibAdded = false;
+
+ // Scan as long as there is paths to scan
+ while (ScanHelper.leftToScan(K)) {
+ scanLibrariesIfNeeded(K, scanBatchSize);
+
+ // NOW check any new libraries added
+ if (Cur.hasMoreValidLib()) {
+ NewLibAdded = true;
+ break;
+ }
+ }
- for (auto &Lib : Libs) {
- // can use Async here?
- resolveSymbolsInLibrary(*Lib, Ctx.query(), Config.Options);
- Ctx.markSearched(Lib.get());
+ if (!NewLibAdded)
+ break; // No new libs found
- if (Ctx.allResolved())
- return;
+ continue; // Try to resolve next library
}
+
+ // can use Async here?
+ resolveSymbolsInLibrary(const_cast<LibraryInfo *>(Lib), Ctx.query(),
+ Config.Options);
+ if (Ctx.allResolved())
+ break;
}
};
@@ -334,34 +357,4 @@ bool LibraryResolver::scanLibrariesIfNeeded(PathType PK, size_t BatchSize) {
Scanner.scanNext(PK, BatchSize);
return true;
}
-
-bool LibraryResolver::symbolExistsInLibrary(const LibraryInfo &Lib,
- StringRef SymName,
- std::vector<std::string> *AllSyms) {
- SymbolEnumeratorOptions Opts;
- return symbolExistsInLibrary(Lib, SymName, AllSyms, Opts);
-}
-
-bool LibraryResolver::symbolExistsInLibrary(
- const LibraryInfo &Lib, StringRef SymName,
- std::vector<std::string> *AllSyms, const SymbolEnumeratorOptions &Opts) {
- bool Found = false;
-
- SymbolEnumerator::enumerateSymbols(
- Lib.getFullPath(),
- [&](StringRef Sym) {
- if (AllSyms)
- AllSyms->emplace_back(Sym.str());
-
- if (Sym == SymName) {
- Found = true;
- }
-
- return EnumerateResult::Continue;
- },
- Opts);
-
- return Found;
-}
-
} // end namespace llvm::orc
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index 96f0b66adec92..a33ed08be136e 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -233,6 +233,9 @@ bool DylibPathValidator::isSharedLibrary(StringRef Path) {
if (MagicCode == file_magic::archive)
return false;
+ if (MagicCode == file_magic::elf_shared_object)
+ return true;
+
// Universal binary handling.
#if defined(__APPLE__)
if (MagicCode == file_magic::macho_universal_binary) {
@@ -676,8 +679,8 @@ void LibraryScanHelper::addBasePath(const std::string &Path, PathType K) {
return;
}
K = K == PathType::Unknown ? classifyKind(Canon) : K;
- auto SP = std::make_shared<LibrarySearchPath>(Canon, K);
- LibSearchPaths[Canon] = SP;
+ LibSearchPaths[Canon] = std::make_unique<LibrarySearchPath>(Canon, K);
+ auto &SP = LibSearchPaths[Canon];
if (K == PathType::User) {
LLVM_DEBUG(dbgs() << "LibraryScanHelper::addBasePath: Added User path: "
@@ -690,9 +693,9 @@ void LibraryScanHelper::addBasePath(const std::string &Path, PathType K) {
}
}
-std::vector<std::shared_ptr<LibrarySearchPath>>
+std::vector<const LibrarySearchPath *>
LibraryScanHelper::getNextBatch(PathType K, size_t BatchSize) {
- std::vector<std::shared_ptr<LibrarySearchPath>> Result;
+ std::vector<const LibrarySearchPath *> Result;
auto &Queue = (K == PathType::User) ? UnscannedUsr : UnscannedSys;
std::unique_lock<std::shared_mutex> Lock(Mtx);
@@ -704,7 +707,7 @@ LibraryScanHelper::getNextBatch(PathType K, size_t BatchSize) {
auto &SP = It->second;
ScanState Expected = ScanState::NotScanned;
if (SP->State.compare_exchange_strong(Expected, ScanState::Scanning)) {
- Result.push_back(SP);
+ Result.push_back(SP.get());
}
}
Queue.pop_front();
@@ -748,13 +751,12 @@ void LibraryScanHelper::resetToScan() {
}
}
-std::vector<std::shared_ptr<LibrarySearchPath>>
-LibraryScanHelper::getAllUnits() const {
+std::vector<const LibrarySearchPath *> LibraryScanHelper::getAllUnits() const {
std::shared_lock<std::shared_mutex> Lock(Mtx);
- std::vector<std::shared_ptr<LibrarySearchPath>> Result;
+ std::vector<const LibrarySearchPath *> Result;
Result.reserve(LibSearchPaths.size());
for (const auto &[_, SP] : LibSearchPaths) {
- Result.push_back(SP);
+ Result.push_back(SP.get());
}
return Result;
}
@@ -989,26 +991,29 @@ std::optional<std::string> LibraryScanner::shouldScan(StringRef FilePath) {
return std::nullopt;
}
- // [4] Skip if it's not a shared library.
- if (!DylibPathValidator::isSharedLibrary(CanonicalPath)) {
- LLVM_DEBUG(dbgs() << " -> Skipped: not a shared library.\n";);
- return std::nullopt;
- }
-
- // [5] Skip if we've already seen this path (via cache)
- if (ScanHelper.hasSeenOrMark(CanonicalPath)) {
+ LibraryPathCache &Cache = ScanHelper.getCache();
+ // [4] Skip if we've already seen this path (via cache)
+ if (Cache.hasSeen(CanonicalPath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: already seen.\n";);
return std::nullopt;
}
- // [6] Already tracked in LibraryManager?
+ // [5] Already tracked in LibraryManager?
if (LibMgr.hasLibrary(CanonicalPath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: already tracked by LibraryManager.\n";);
+ return std::nullopt;
+ }
+ // [6] Skip if it's not a shared library.
+ if (!DylibPathValidator::isSharedLibrary(CanonicalPath)) {
+ LLVM_DEBUG(dbgs() << " -> Skipped: not a shared library.\n";);
return std::nullopt;
}
+ // Mark seen this path
+ Cache.markSeen(CanonicalPath);
+
// [7] Run user-defined hook (default: always true)
if (!ShouldScanCall(CanonicalPath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: user-defined hook rejected.\n";);
@@ -1113,7 +1118,7 @@ void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
}
}
-void LibraryScanner::scanBaseDir(std::shared_ptr<LibrarySearchPath> SP) {
+void LibraryScanner::scanBaseDir(LibrarySearchPath *SP) {
if (!sys::fs::is_directory(SP->BasePath) || SP->BasePath.empty()) {
LLVM_DEBUG(
dbgs() << "LibraryScanner::scanBaseDir: Invalid or empty basePath: "
@@ -1150,11 +1155,10 @@ void LibraryScanner::scanNext(PathType K, size_t BatchSize) {
<< (K == PathType::User ? "User" : "System") << "\n";);
auto SearchPaths = ScanHelper.getNextBatch(K, BatchSize);
- for (auto &SP : SearchPaths) {
+ for (const auto *SP : SearchPaths) {
LLVM_DEBUG(dbgs() << " Scanning unit with basePath: " << SP->BasePath
<< "\n";);
-
- scanBaseDir(SP);
+ scanBaseDir(const_cast<LibrarySearchPath *>(SP));
}
}
>From 4f1f103435b035e8645e540ba6bb67cfa7d02751 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 22 Nov 2025 16:16:18 +0530
Subject: [PATCH 2/2] Refactor searchSymbolsInLibraries
---
.../Orc/TargetProcess/LibraryResolver.h | 1 +
.../Orc/TargetProcess/LibraryResolver.cpp | 31 +++++++++----------
2 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
index e12bf84ed4e63..4990d83651a69 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
@@ -577,6 +577,7 @@ class LibraryResolver {
private:
bool scanLibrariesIfNeeded(PathType K, size_t BatchSize = 0);
+ bool scanForNewLibraries(PathType K, LibraryCursor &Cur);
void resolveSymbolsInLibrary(LibraryInfo *Lib, SymbolQuery &Q,
const SymbolEnumeratorOptions &Opts);
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
index 510598538d643..4e68501cbfc4a 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
@@ -302,22 +302,8 @@ void LibraryResolver::searchSymbolsInLibraries(
const LibraryInfo *Lib = Cur.nextValidLib();
// Cursor not valid?
if (!Lib) {
- bool NewLibAdded = false;
-
- // Scan as long as there is paths to scan
- while (ScanHelper.leftToScan(K)) {
- scanLibrariesIfNeeded(K, scanBatchSize);
-
- // NOW check any new libraries added
- if (Cur.hasMoreValidLib()) {
- NewLibAdded = true;
- break;
- }
- }
-
- if (!NewLibAdded)
- break; // No new libs found
-
+ if (!scanForNewLibraries(K, Cur))
+ break; // nothing new was added
continue; // Try to resolve next library
}
@@ -346,6 +332,19 @@ void LibraryResolver::searchSymbolsInLibraries(
OnComplete(Q);
}
+bool LibraryResolver::scanForNewLibraries(PathType K, LibraryCursor &Cur) {
+ while (ScanHelper.leftToScan(K)) {
+ scanLibrariesIfNeeded(K, scanBatchSize);
+
+ // Check if scanning added new libraries
+ if (Cur.hasMoreValidLib())
+ return true;
+ }
+
+ // No new libraries were added
+ return false;
+}
+
bool LibraryResolver::scanLibrariesIfNeeded(PathType PK, size_t BatchSize) {
LLVM_DEBUG(dbgs() << "LibraryResolver::scanLibrariesIfNeeded: Scanning for "
<< (PK == PathType::User ? "User" : "System")
More information about the llvm-commits
mailing list