[llvm] [Orc][LibResolver] Refactor resolver internals and simplify symbol resolution. (PR #169161)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 26 20:32:30 PST 2025
https://github.com/SahilPatidar updated https://github.com/llvm/llvm-project/pull/169161
>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 01/11] [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 02/11] 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")
>From 61c039654af22861df7824bea532bfd1a089157b Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Mon, 24 Nov 2025 15:01:40 +0530
Subject: [PATCH 03/11] Refactor
---
llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp | 3 ---
1 file changed, 3 deletions(-)
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index a33ed08be136e..88725b5a60273 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -233,9 +233,6 @@ 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) {
>From 999bb5d2bd9dfb307bc4bc3873a16641a43c3ac4 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Wed, 26 Nov 2025 15:45:39 +0530
Subject: [PATCH 04/11] Refactor LibraryScanner
---
.../Orc/TargetProcess/LibraryResolver.h | 57 --------
.../Orc/TargetProcess/LibraryScanner.h | 4 +-
.../Orc/TargetProcess/LibraryScanner.cpp | 125 +++++++++---------
3 files changed, 64 insertions(+), 122 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
index 4990d83651a69..b8b61bf445167 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
@@ -363,63 +363,6 @@ 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
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index 88ccfe30dd649..3e6299c101a77 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -456,10 +456,10 @@ class LibraryScanner {
LibraryManager &LibMgr;
ShouldScanFn ShouldScanCall;
- std::optional<std::string> shouldScan(StringRef FilePath);
+ bool shouldScan(StringRef FilePath);
Expected<LibraryDepsInfo> extractDeps(StringRef FilePath);
- void handleLibrary(StringRef P, PathType K, int level = 1);
+ void handleLibrary(StringRef FilePath, PathType K, int level = 1);
void scanBaseDir(LibrarySearchPath *U);
};
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index 88725b5a60273..e634ecb3ef820 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -957,88 +957,53 @@ Expected<LibraryDepsInfo> LibraryScanner::extractDeps(StringRef FilePath) {
FilePath.str().c_str());
}
-std::optional<std::string> LibraryScanner::shouldScan(StringRef FilePath) {
- std::error_code EC;
-
+bool LibraryScanner::shouldScan(StringRef FilePath) {
LLVM_DEBUG(dbgs() << "[shouldScan] Checking: " << FilePath << "\n";);
- // [1] Check file existence early
- if (!sys::fs::exists(FilePath)) {
- LLVM_DEBUG(dbgs() << " -> Skipped: file does not exist.\n";);
-
- return std::nullopt;
- }
-
- // [2] Resolve to canonical path
- auto CanonicalPathOpt = ScanHelper.resolve(FilePath, EC);
- if (EC || !CanonicalPathOpt) {
- LLVM_DEBUG(dbgs() << " -> Skipped: failed to resolve path (EC="
- << EC.message() << ").\n";);
-
- return std::nullopt;
- }
-
- const std::string &CanonicalPath = *CanonicalPathOpt;
- LLVM_DEBUG(dbgs() << " -> Canonical path: " << CanonicalPath << "\n");
-
- // [3] Check if it's a directory — skip directories
- if (sys::fs::is_directory(CanonicalPath)) {
- LLVM_DEBUG(dbgs() << " -> Skipped: path is a directory.\n";);
-
- return std::nullopt;
- }
-
LibraryPathCache &Cache = ScanHelper.getCache();
- // [4] Skip if we've already seen this path (via cache)
- if (Cache.hasSeen(CanonicalPath)) {
+ // [1] Skip if we've already seen this path (via cache)
+ if (Cache.hasSeen(FilePath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: already seen.\n";);
-
- return std::nullopt;
+ return false;
}
- // [5] Already tracked in LibraryManager?
- if (LibMgr.hasLibrary(CanonicalPath)) {
+ // [2] Already tracked in LibraryManager?
+ if (LibMgr.hasLibrary(FilePath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: already tracked by LibraryManager.\n";);
- return std::nullopt;
+ return false;
}
- // [6] Skip if it's not a shared library.
- if (!DylibPathValidator::isSharedLibrary(CanonicalPath)) {
+ // [3] Skip if it's not a shared library.
+ if (!DylibPathValidator::isSharedLibrary(FilePath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: not a shared library.\n";);
- return std::nullopt;
+ return false;
}
// Mark seen this path
- Cache.markSeen(CanonicalPath);
+ Cache.markSeen(FilePath.str());
- // [7] Run user-defined hook (default: always true)
- if (!ShouldScanCall(CanonicalPath)) {
+ // [4] Run user-defined hook (default: always true)
+ if (!ShouldScanCall(FilePath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: user-defined hook rejected.\n";);
-
- return std::nullopt;
+ return false;
}
- LLVM_DEBUG(dbgs() << " -> Accepted: ready to scan " << CanonicalPath
- << "\n";);
- return CanonicalPath;
+ LLVM_DEBUG(dbgs() << " -> Accepted: ready to scan " << FilePath << "\n";);
+ return true;
}
void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
LLVM_DEBUG(dbgs() << "LibraryScanner::handleLibrary: Scanning: " << FilePath
<< ", level=" << level << "\n";);
- auto CanonPathOpt = shouldScan(FilePath);
- if (!CanonPathOpt) {
+ if (!shouldScan(FilePath)) {
LLVM_DEBUG(dbgs() << " Skipped (shouldScan returned false): " << FilePath
<< "\n";);
-
return;
}
- const std::string CanonicalPath = *CanonPathOpt;
- auto DepsOrErr = extractDeps(CanonicalPath);
+ auto DepsOrErr = extractDeps(FilePath);
if (!DepsOrErr) {
- LLVM_DEBUG(dbgs() << " Failed to extract deps for: " << CanonicalPath
- << "\n";);
+ LLVM_DEBUG(dbgs() << " Failed to extract deps for: " << FilePath << "\n";);
handleError(DepsOrErr.takeError());
return;
}
@@ -1058,15 +1023,15 @@ void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
});
if (Deps.isPIE && level == 0) {
- LLVM_DEBUG(dbgs() << " Skipped PIE executable at top level: "
- << CanonicalPath << "\n";);
+ LLVM_DEBUG(dbgs() << " Skipped PIE executable at top level: " << FilePath
+ << "\n";);
return;
}
- bool Added = LibMgr.addLibrary(CanonicalPath, K);
+ bool Added = LibMgr.addLibrary(FilePath.str(), K);
if (!Added) {
- LLVM_DEBUG(dbgs() << " Already added: " << CanonicalPath << "\n";);
+ LLVM_DEBUG(dbgs() << " Already added: " << FilePath << "\n";);
return;
}
@@ -1074,7 +1039,7 @@ void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
if (Deps.rpath.empty() && Deps.runPath.empty()) {
LLVM_DEBUG(
dbgs() << "LibraryScanner::handleLibrary: Skipping deps (Heuristic1): "
- << CanonicalPath << "\n";);
+ << FilePath << "\n";);
return;
}
@@ -1084,20 +1049,20 @@ void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
return std::all_of(Paths.begin(), Paths.end(), [&](StringRef P) {
LLVM_DEBUG(dbgs() << " Checking isTrackedBasePath : " << P << "\n";);
return ScanHelper.isTrackedBasePath(
- DylibResolver::resolvelinkerFlag(P, CanonicalPath));
+ DylibResolver::resolvelinkerFlag(P, FilePath));
});
};
if (allTracked(Deps.rpath) && allTracked(Deps.runPath)) {
LLVM_DEBUG(
dbgs() << "LibraryScanner::handleLibrary: Skipping deps (Heuristic2): "
- << CanonicalPath << "\n";);
+ << FilePath << "\n";);
return;
}
DylibPathValidator Validator(ScanHelper.getPathResolver());
DylibResolver Resolver(Validator);
- Resolver.configure(CanonicalPath,
+ Resolver.configure(FilePath,
{{Deps.rpath, SearchPathType::RPath},
{ScanHelper.getSearchPaths(), SearchPathType::UsrOrSys},
{Deps.runPath, SearchPathType::RunPath}});
@@ -1138,8 +1103,42 @@ void LibraryScanner::scanBaseDir(LibrarySearchPath *SP) {
auto Status = *Entry.status();
if (sys::fs::is_regular_file(Status) || sys::fs::is_symlink_file(Status)) {
LLVM_DEBUG(dbgs() << " Found file: " << Entry.path() << "\n";);
+
+ std::string FinalPath;
+ bool IsSymlink = sys::fs::is_symlink_file(Status);
+
+ // Resolve symlink
+ if (IsSymlink) {
+ LLVM_DEBUG(dbgs() << " Symlink → resolving...\n");
+
+ auto CanonicalOpt = ScanHelper.resolve(Entry.path(), EC);
+ if (EC || !CanonicalOpt) {
+ LLVM_DEBUG(dbgs() << " -> Skipped: resolve failed (EC="
+ << EC.message() << ")\n");
+ continue;
+ }
+
+ FinalPath = std::move(*CanonicalOpt);
+
+ LLVM_DEBUG(dbgs() << " Canonical: " << FinalPath << "\n");
+
+ } else {
+ // make absolute
+ SmallString<256> Abs(Entry.path());
+ sys::fs::make_absolute(Abs);
+ FinalPath = Abs.str().str();
+
+ LLVM_DEBUG(dbgs() << " Regular: absolute = " << FinalPath << "\n");
+ }
+
+ // Check if it's a directory — skip directories
+ if (sys::fs::is_directory(Status)) {
+ LLVM_DEBUG(dbgs() << " -> Skipped: path is a directory.\n";);
+ continue;
+ }
+
// async support ?
- handleLibrary(Entry.path(), SP->Kind);
+ handleLibrary(FinalPath, SP->Kind);
}
}
>From 0afae12b64a1447c5fc4cd19447a3a47e897662d Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Thu, 4 Dec 2025 14:31:40 +0530
Subject: [PATCH 05/11] Refactor Scanner: improve cache
---
.../Orc/TargetProcess/LibraryScanner.h | 18 +-
.../Orc/TargetProcess/LibraryScanner.cpp | 183 +++++++++---------
.../Orc/LibraryResolverTest.cpp | 8 +-
3 files changed, 111 insertions(+), 98 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index 3e6299c101a77..ce523287a979f 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -187,9 +187,15 @@ class DylibSubstitutor {
/// checks whether they point to valid shared libraries.
class DylibPathValidator {
public:
- DylibPathValidator(PathResolver &PR) : LibPathResolver(PR) {}
+ DylibPathValidator(PathResolver &PR, LibraryPathCache &LC)
+ : LibPathResolver(PR), LibPathCache(LC) {}
static bool isSharedLibrary(StringRef Path);
+ bool isSharedLibraryCached(StringRef Path) const {
+ if (LibPathCache.hasSeen(Path))
+ return true;
+ return isSharedLibrary(Path);
+ }
std::optional<std::string> normalize(StringRef Path) const {
std::error_code ec;
@@ -202,11 +208,13 @@ class DylibPathValidator {
/// Validate the given path as a shared library.
std::optional<std::string> validate(StringRef Path) const {
+ if (LibPathCache.hasSeen(Path))
+ return Path.str();
auto realOpt = normalize(Path);
if (!realOpt)
return std::nullopt;
- if (!isSharedLibrary(*realOpt))
+ if (!isSharedLibraryCached(*realOpt))
return std::nullopt;
return realOpt;
@@ -214,6 +222,7 @@ class DylibPathValidator {
private:
PathResolver &LibPathResolver;
+ LibraryPathCache &LibPathCache;
};
enum class SearchPathType {
@@ -232,6 +241,7 @@ class SearchPathResolver {
SearchPathResolver(const SearchPathConfig &Cfg,
StringRef PlaceholderPrefix = "")
: Kind(Cfg.type), PlaceholderPrefix(PlaceholderPrefix) {
+ Paths.reserve(Cfg.Paths.size());
for (auto &path : Cfg.Paths)
Paths.emplace_back(path.str());
}
@@ -456,10 +466,10 @@ class LibraryScanner {
LibraryManager &LibMgr;
ShouldScanFn ShouldScanCall;
- bool shouldScan(StringRef FilePath);
+ bool shouldScan(StringRef FilePath, bool IsResolvingDep = false);
Expected<LibraryDepsInfo> extractDeps(StringRef FilePath);
- void handleLibrary(StringRef FilePath, PathType K, int level = 1);
+ void handleLibrary(StringRef FilePath, PathType K, int level = 0);
void scanBaseDir(LibrarySearchPath *U);
};
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index e634ecb3ef820..025da92d01f21 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -49,113 +49,116 @@ void handleError(Error Err, StringRef context = "") {
}));
}
-bool ObjectFileLoader::isArchitectureCompatible(const object::ObjectFile &Obj) {
- Triple HostTriple(sys::getProcessTriple());
- Triple ObjTriple = Obj.makeTriple();
-
- LLVM_DEBUG({
- dbgs() << "Host triple: " << HostTriple.str()
- << ", Object triple: " << ObjTriple.str() << "\n";
- });
+static std::string getHostFileFormatName() {
+ static const std::string HostFormat = []() -> std::string {
+ auto ObjOrErr = object::ObjectFile::createObjectFile(
+ sys::fs::getMainExecutable(nullptr, nullptr));
- if (ObjTriple.getArch() != Triple::UnknownArch &&
- HostTriple.getArch() != ObjTriple.getArch())
- return false;
+ if (!ObjOrErr) {
+ return "Unknown";
+ }
- if (ObjTriple.getOS() != Triple::UnknownOS &&
- HostTriple.getOS() != ObjTriple.getOS())
- return false;
+ return (*ObjOrErr).getBinary()->getFileFormatName().str();
+ }();
- if (ObjTriple.getEnvironment() != Triple::UnknownEnvironment &&
- HostTriple.getEnvironment() != Triple::UnknownEnvironment &&
- HostTriple.getEnvironment() != ObjTriple.getEnvironment())
- return false;
+ return HostFormat;
+}
- return true;
+bool ObjectFileLoader::isArchitectureCompatible(const object::ObjectFile &Obj) {
+ return Obj.getFileFormatName() == getHostFileFormatName();
}
Expected<object::OwningBinary<object::ObjectFile>>
ObjectFileLoader::loadObjectFileWithOwnership(StringRef FilePath) {
LLVM_DEBUG(dbgs() << "ObjectFileLoader: Attempting to open file " << FilePath
<< "\n";);
- auto BinOrErr = object::createBinary(FilePath);
- if (!BinOrErr) {
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: Failed to open file " << FilePath
- << "\n";);
- return BinOrErr.takeError();
- }
+ if (auto ObjOrErr =
+ object::ObjectFile::createObjectFile(FilePath)) {
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: Successfully opened file " << FilePath
- << "\n";);
+ LLVM_DEBUG(dbgs() << "ObjectFileLoader: Detected object file\n";);
- auto OwningBin = BinOrErr->takeBinary();
- object::Binary *Bin = OwningBin.first.get();
+ auto OwningBin = std::move(*ObjOrErr);
- if (Bin->isArchive()) {
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: File is an archive, not supported: "
- << FilePath << "\n";);
- return createStringError(std::errc::invalid_argument,
- "Archive files are not supported: %s",
- FilePath.str().c_str());
- }
+ if (!isArchitectureCompatible(*OwningBin.getBinary())) {
+ LLVM_DEBUG(dbgs() << "ObjectFileLoader: Incompatible architecture: "
+ << FilePath << "\n";);
+ return createStringError(inconvertibleErrorCode(),
+ "Incompatible object file: %s",
+ FilePath.str().c_str());
+ }
+
+ LLVM_DEBUG(dbgs() << "ObjectFileLoader: Object file is compatible\n";);
+ return std::move(OwningBin);
+ } else {
#if defined(__APPLE__)
- if (auto *UB = dyn_cast<object::MachOUniversalBinary>(Bin)) {
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: Detected Mach-O universal binary: "
+ consumeError(ObjOrErr.takeError());
+ auto BinOrErr = object::createBinary(FilePath);
+ if (!BinOrErr) {
+ LLVM_DEBUG(dbgs() << "ObjectFileLoader: Failed to open file " << FilePath
+ << "\n";);
+ return BinOrErr.takeError();
+ }
+
+ LLVM_DEBUG(dbgs() << "ObjectFileLoader: Successfully opened file "
<< FilePath << "\n";);
- for (auto ObjForArch : UB->objects()) {
- auto ObjOrErr = ObjForArch.getAsObjectFile();
- if (!ObjOrErr) {
- LLVM_DEBUG(
- dbgs()
- << "ObjectFileLoader: Skipping invalid architecture slice\n";);
- consumeError(ObjOrErr.takeError());
- continue;
- }
+ auto OwningBin = BinOrErr->takeBinary();
+ object::Binary *Bin = OwningBin.first.get();
- std::unique_ptr<object::ObjectFile> Obj = std::move(ObjOrErr.get());
- if (isArchitectureCompatible(*Obj)) {
- LLVM_DEBUG(
- dbgs() << "ObjectFileLoader: Found compatible object slice\n";);
+ if (Bin->isArchive()) {
+ LLVM_DEBUG(
+ dbgs() << "ObjectFileLoader: File is an archive, not supported: "
+ << FilePath << "\n";);
+ return createStringError(std::errc::invalid_argument,
+ "Archive files are not supported: %s",
+ FilePath.str().c_str());
+ }
- return object::OwningBinary<object::ObjectFile>(
- std::move(Obj), std::move(OwningBin.second));
+ if (auto *UB = dyn_cast<object::MachOUniversalBinary>(Bin)) {
+ LLVM_DEBUG(
+ dbgs() << "ObjectFileLoader: Detected Mach-O universal binary: "
+ << FilePath << "\n";);
+ for (auto ObjForArch : UB->objects()) {
+ auto ObjOrErr = ObjForArch.getAsObjectFile();
+ if (!ObjOrErr) {
+ LLVM_DEBUG(dbgs() << "ObjectFileLoader: Skipping invalid "
+ "architecture slice\n";);
+
+ consumeError(ObjOrErr.takeError());
+ continue;
+ }
- } else {
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: Incompatible architecture "
- "slice skipped\n";);
+ std::unique_ptr<object::ObjectFile> Obj = std::move(ObjOrErr.get());
+ if (isArchitectureCompatible(*Obj)) {
+ LLVM_DEBUG(
+ dbgs() << "ObjectFileLoader: Found compatible object slice\n";);
+
+ return object::OwningBinary<object::ObjectFile>(
+ std::move(Obj), std::move(OwningBin.second));
+
+ } else {
+ LLVM_DEBUG(dbgs() << "ObjectFileLoader: Incompatible architecture "
+ "slice skipped\n";);
+ }
}
+ LLVM_DEBUG(dbgs() << "ObjectFileLoader: No compatible slices found in "
+ "universal binary\n";);
+ return createStringError(inconvertibleErrorCode(),
+ "No compatible object found in fat binary: %s",
+ FilePath.str().c_str());
}
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: No compatible slices found in "
- "universal binary\n";);
- return createStringError(inconvertibleErrorCode(),
- "No compatible object found in fat binary: %s",
- FilePath.str().c_str());
- }
-#endif
-
- auto ObjOrErr =
- object::ObjectFile::createObjectFile(Bin->getMemoryBufferRef());
- if (!ObjOrErr) {
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: Failed to create object file\n";);
return ObjOrErr.takeError();
- }
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: Detected object file\n";);
-
- std::unique_ptr<object::ObjectFile> Obj = std::move(*ObjOrErr);
- if (!isArchitectureCompatible(*Obj)) {
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: Incompatible architecture: "
- << FilePath << "\n";);
- return createStringError(inconvertibleErrorCode(),
- "Incompatible object file: %s",
- FilePath.str().c_str());
+#else
+ LLVM_DEBUG(dbgs() << "ObjectFileLoader: Failed to open file " << FilePath
+ << "\n";);
+ return ObjOrErr.takeError();
+#endif
}
- LLVM_DEBUG(dbgs() << "ObjectFileLoader: Object file is compatible\n";);
-
- return object::OwningBinary<object::ObjectFile>(std::move(Obj),
- std::move(OwningBin.second));
+ return createStringError(inconvertibleErrorCode(),
+ "Not a compatible object file : %s",
+ FilePath.str().c_str());
}
template <class ELFT>
@@ -271,6 +274,7 @@ bool DylibPathValidator::isSharedLibrary(StringRef Path) {
consumeError(ObjOrErr.takeError());
return false;
}
+
return isSharedLibraryObject(ObjOrErr.get());
}
@@ -957,7 +961,7 @@ Expected<LibraryDepsInfo> LibraryScanner::extractDeps(StringRef FilePath) {
FilePath.str().c_str());
}
-bool LibraryScanner::shouldScan(StringRef FilePath) {
+bool LibraryScanner::shouldScan(StringRef FilePath, bool IsResolvingDep) {
LLVM_DEBUG(dbgs() << "[shouldScan] Checking: " << FilePath << "\n";);
LibraryPathCache &Cache = ScanHelper.getCache();
@@ -968,13 +972,13 @@ bool LibraryScanner::shouldScan(StringRef FilePath) {
}
// [2] Already tracked in LibraryManager?
- if (LibMgr.hasLibrary(FilePath)) {
+ /*if (LibMgr.hasLibrary(FilePath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: already tracked by LibraryManager.\n";);
return false;
- }
+ }*/
// [3] Skip if it's not a shared library.
- if (!DylibPathValidator::isSharedLibrary(FilePath)) {
+ if (!IsResolvingDep && !DylibPathValidator::isSharedLibrary(FilePath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: not a shared library.\n";);
return false;
}
@@ -995,7 +999,7 @@ bool LibraryScanner::shouldScan(StringRef FilePath) {
void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
LLVM_DEBUG(dbgs() << "LibraryScanner::handleLibrary: Scanning: " << FilePath
<< ", level=" << level << "\n";);
- if (!shouldScan(FilePath)) {
+ if (!shouldScan(FilePath, level > 0)) {
LLVM_DEBUG(dbgs() << " Skipped (shouldScan returned false): " << FilePath
<< "\n";);
return;
@@ -1060,7 +1064,8 @@ void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
return;
}
- DylibPathValidator Validator(ScanHelper.getPathResolver());
+ DylibPathValidator Validator(ScanHelper.getPathResolver(),
+ ScanHelper.getCache());
DylibResolver Resolver(Validator);
Resolver.configure(FilePath,
{{Deps.rpath, SearchPathType::RPath},
@@ -1071,7 +1076,6 @@ void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
auto DepFullOpt = Resolver.resolve(Dep);
if (!DepFullOpt) {
LLVM_DEBUG(dbgs() << " Failed to resolve dep: " << Dep << "\n";);
-
continue;
}
LLVM_DEBUG(dbgs() << " Resolved dep to: " << *DepFullOpt << "\n";);
@@ -1157,5 +1161,4 @@ void LibraryScanner::scanNext(PathType K, size_t BatchSize) {
scanBaseDir(const_cast<LibrarySearchPath *>(SP));
}
}
-
} // end namespace llvm::orc
diff --git a/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp b/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp
index 441344b281411..11be6be0f531f 100644
--- a/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp
@@ -619,7 +619,7 @@ TEST_F(LibraryResolverIT, ResolveFromUsrOrSystemPaths) {
auto LibPathCache = std::make_shared<LibraryPathCache>();
auto PResolver = std::make_shared<PathResolver>(LibPathCache);
- DylibPathValidator validator(*PResolver);
+ DylibPathValidator validator(*PResolver, *LibPathCache);
std::vector<std::string> Paths = {"/foo/bar/", "temp/foo", libdir("C"),
libdir("A"), libdir("B"), libdir("Z")};
@@ -671,7 +671,7 @@ TEST_F(LibraryResolverIT, ResolveViaLoaderPathAndRPathSubstitution) {
auto LibPathCache = std::make_shared<LibraryPathCache>();
auto PResolver = std::make_shared<PathResolver>(LibPathCache);
- DylibPathValidator validator(*PResolver);
+ DylibPathValidator validator(*PResolver, *LibPathCache);
std::vector<std::string> Paths = {"@loader_path/../A", "@loader_path/../B",
"@loader_path/../C", "@loader_path/../Z"};
@@ -715,9 +715,9 @@ TEST_F(LibraryResolverIT, ResolveViaLoaderPathAndRPathSubstitution) {
#if defined(__linux__)
TEST_F(LibraryResolverIT, ResolveViaOriginAndRPathSubstitution) {
auto LibPathCache = std::make_shared<LibraryPathCache>();
- auto PResolver = std::make_shared<PathResolver>(LibPathCache);
+ auto PResolver = std::make_shared<PathResolver>(LibPathCach);
- DylibPathValidator validator(*PResolver);
+ DylibPathValidator validator(*PResolver, *LibPathCache);
// On Linux, $ORIGIN works like @loader_path
std::vector<std::string> Paths = {"$ORIGIN/../A", "$ORIGIN/../B",
>From 3494c57ecd3d07ad0f7d2eaf7a3f656918c581a1 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Fri, 5 Dec 2025 11:22:49 +0530
Subject: [PATCH 06/11] Fix format
---
.../ExecutionEngine/Orc/TargetProcess/LibraryResolver.h | 1 +
.../ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp | 9 ++++-----
.../ExecutionEngine/Orc/LibraryResolverTest.cpp | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
index b8b61bf445167..93ef7ed5db9ac 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
@@ -24,6 +24,7 @@
namespace llvm {
namespace orc {
+
class LibraryManager;
enum class LibState : uint8_t { Unloaded = 0, Loaded = 1, Queried = 2 };
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index 025da92d01f21..e74568e6bc673 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -65,15 +65,14 @@ static std::string getHostFileFormatName() {
}
bool ObjectFileLoader::isArchitectureCompatible(const object::ObjectFile &Obj) {
- return Obj.getFileFormatName() == getHostFileFormatName();
+ return Obj.getFileFormatName() == getHostFileFormatName();
}
Expected<object::OwningBinary<object::ObjectFile>>
ObjectFileLoader::loadObjectFileWithOwnership(StringRef FilePath) {
LLVM_DEBUG(dbgs() << "ObjectFileLoader: Attempting to open file " << FilePath
<< "\n";);
- if (auto ObjOrErr =
- object::ObjectFile::createObjectFile(FilePath)) {
+ if (auto ObjOrErr = object::ObjectFile::createObjectFile(FilePath)) {
LLVM_DEBUG(dbgs() << "ObjectFileLoader: Detected object file\n";);
@@ -157,8 +156,8 @@ ObjectFileLoader::loadObjectFileWithOwnership(StringRef FilePath) {
}
return createStringError(inconvertibleErrorCode(),
- "Not a compatible object file : %s",
- FilePath.str().c_str());
+ "Not a compatible object file : %s",
+ FilePath.str().c_str());
}
template <class ELFT>
diff --git a/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp b/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp
index 11be6be0f531f..557e869f9ca93 100644
--- a/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp
@@ -715,7 +715,7 @@ TEST_F(LibraryResolverIT, ResolveViaLoaderPathAndRPathSubstitution) {
#if defined(__linux__)
TEST_F(LibraryResolverIT, ResolveViaOriginAndRPathSubstitution) {
auto LibPathCache = std::make_shared<LibraryPathCache>();
- auto PResolver = std::make_shared<PathResolver>(LibPathCach);
+ auto PResolver = std::make_shared<PathResolver>(LibPathCache);
DylibPathValidator validator(*PResolver, *LibPathCache);
>From 711e3970d5c384fd165f071b38083f20ad58724a Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Wed, 10 Dec 2025 11:26:14 +0530
Subject: [PATCH 07/11] add comments
---
.../ExecutionEngine/Orc/TargetProcess/LibraryResolver.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
index 93ef7ed5db9ac..28271d3390b80 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
@@ -86,6 +86,10 @@ class LibraryInfo {
mutable std::shared_mutex Mtx;
};
+// The LibraryCursor iterates through a list of LibraryInfo pointers,
+// returning only those libraries that match a specified LibState. LibraryIndex
+// provides these lists based on PathType, and the cursor filters them as it
+// iterates.
class LibraryCursor {
public:
LibraryCursor(const std::vector<const LibraryInfo *> &L, LibState S)
@@ -109,6 +113,8 @@ class LibraryCursor {
size_t Pos = 0; // cursor position
};
+// LibraryIndex keeps libraries grouped by PathType and lets you
+// get a cursor to walk through libraries of a specific type/state.
class LibraryIndex {
friend LibraryManager;
>From 736bb5993f95aafd3ff37f1f04472ebab4483d47 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Thu, 18 Dec 2025 15:48:41 +0530
Subject: [PATCH 08/11] Add cache for object file
---
.../Orc/TargetProcess/LibraryScanner.h | 132 ++++++++++++------
.../Orc/TargetProcess/LibraryScanner.cpp | 119 ++++++++--------
2 files changed, 143 insertions(+), 108 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index ce523287a979f..d42f9b6240861 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -178,7 +178,81 @@ class DylibSubstitutor {
}
private:
- StringMap<std::string> Placeholders;
+ SmallVector<std::pair<std::string, std::string>> Placeholders;
+};
+
+/// Loads an object file and provides access to it.
+///
+/// Owns the underlying `ObjectFile` and ensures it is valid.
+/// Any errors encountered during construction are stored and
+/// returned when attempting to access the file.
+class ObjectFileLoader {
+public:
+ /// Construct an object file loader from the given path.
+ explicit ObjectFileLoader(StringRef Path) {
+ auto ObjOrErr = loadObjectFileWithOwnership(Path);
+ if (ObjOrErr)
+ Obj = std::move(*ObjOrErr);
+ else {
+ consumeError(std::move(Err));
+ Err = ObjOrErr.takeError();
+ }
+ }
+
+ ObjectFileLoader(const ObjectFileLoader &) = delete;
+ ObjectFileLoader &operator=(const ObjectFileLoader &) = delete;
+
+ ObjectFileLoader(ObjectFileLoader &&) = default;
+ ObjectFileLoader &operator=(ObjectFileLoader &&) = default;
+
+ /// Get the loaded object file, or return an error if loading failed.
+ Expected<object::ObjectFile &> getObjectFile() {
+ if (Err) {
+ // allow the error to be taken only once
+ if (ErrorTaken)
+ return createStringError(inconvertibleErrorCode(),
+ "error already taken");
+
+ ErrorTaken = true;
+ return std::move(Err);
+ }
+ return *Obj.getBinary();
+ }
+
+ static bool isArchitectureCompatible(const object::ObjectFile &Obj);
+
+private:
+ object::OwningBinary<object::ObjectFile> Obj;
+ Error Err = Error::success();
+ bool ErrorTaken = false;
+
+ static Expected<object::OwningBinary<object::ObjectFile>>
+ loadObjectFileWithOwnership(StringRef FilePath);
+};
+
+class ObjFileCache {
+public:
+ void insert(StringRef Path, ObjectFileLoader &&Loader) {
+ Cache.insert({Path, std::move(Loader)});
+ }
+
+ // Take ownership
+ std::optional<ObjectFileLoader> take(StringRef Path) {
+ std::unique_lock<std::shared_mutex> Lock(Mtx);
+ auto It = Cache.find(Path);
+ if (It == Cache.end())
+ return std::nullopt;
+
+ ObjectFileLoader L = std::move(It->second);
+ Cache.erase(It);
+ return std::move(L);
+ }
+
+ bool contains(StringRef Path) const { return Cache.count(Path) != 0; }
+
+private:
+ mutable std::shared_mutex Mtx;
+ StringMap<ObjectFileLoader> Cache;
};
/// Validates and normalizes dynamic library paths.
@@ -187,10 +261,11 @@ class DylibSubstitutor {
/// checks whether they point to valid shared libraries.
class DylibPathValidator {
public:
- DylibPathValidator(PathResolver &PR, LibraryPathCache &LC)
- : LibPathResolver(PR), LibPathCache(LC) {}
+ DylibPathValidator(PathResolver &PR, LibraryPathCache &LC,
+ ObjFileCache *ObjCache = nullptr)
+ : LibPathResolver(PR), LibPathCache(LC), ObjCache(ObjCache) {}
- static bool isSharedLibrary(StringRef Path);
+ bool isSharedLibrary(StringRef Path) const;
bool isSharedLibraryCached(StringRef Path) const {
if (LibPathCache.hasSeen(Path))
return true;
@@ -223,6 +298,7 @@ class DylibPathValidator {
private:
PathResolver &LibPathResolver;
LibraryPathCache &LibPathCache;
+ mutable ObjFileCache *ObjCache;
};
enum class SearchPathType {
@@ -390,47 +466,6 @@ class LibraryScanHelper {
std::deque<StringRef> UnscannedSys;
};
-/// Loads an object file and provides access to it.
-///
-/// Owns the underlying `ObjectFile` and ensures it is valid.
-/// Any errors encountered during construction are stored and
-/// returned when attempting to access the file.
-class ObjectFileLoader {
-public:
- /// Construct an object file loader from the given path.
- explicit ObjectFileLoader(StringRef Path) {
- auto ObjOrErr = loadObjectFileWithOwnership(Path);
- if (ObjOrErr)
- Obj = std::move(*ObjOrErr);
- else {
- consumeError(std::move(Err));
- Err = ObjOrErr.takeError();
- }
- }
-
- ObjectFileLoader(const ObjectFileLoader &) = delete;
- ObjectFileLoader &operator=(const ObjectFileLoader &) = delete;
-
- ObjectFileLoader(ObjectFileLoader &&) = default;
- ObjectFileLoader &operator=(ObjectFileLoader &&) = default;
-
- /// Get the loaded object file, or return an error if loading failed.
- Expected<object::ObjectFile &> getObjectFile() {
- if (Err)
- return std::move(Err);
- return *Obj.getBinary();
- }
-
- static bool isArchitectureCompatible(const object::ObjectFile &Obj);
-
-private:
- object::OwningBinary<object::ObjectFile> Obj;
- Error Err = Error::success();
-
- static Expected<object::OwningBinary<object::ObjectFile>>
- loadObjectFileWithOwnership(StringRef FilePath);
-};
-
/// Scans libraries, resolves dependencies, and registers them.
class LibraryScanner {
public:
@@ -439,7 +474,9 @@ class LibraryScanner {
LibraryScanner(
LibraryScanHelper &H, LibraryManager &LibMgr,
ShouldScanFn ShouldScanCall = [](StringRef path) { return true; })
- : ScanHelper(H), LibMgr(LibMgr),
+ : ObjCache(ObjFileCache()), ScanHelper(H), LibMgr(LibMgr),
+ Validator(ScanHelper.getPathResolver(), ScanHelper.getCache(),
+ &ObjCache),
ShouldScanCall(std::move(ShouldScanCall)) {}
void scanNext(PathType Kind, size_t batchSize = 1);
@@ -462,11 +499,14 @@ class LibraryScanner {
};
private:
+ ObjFileCache ObjCache;
LibraryScanHelper &ScanHelper;
LibraryManager &LibMgr;
+ DylibPathValidator Validator;
ShouldScanFn ShouldScanCall;
bool shouldScan(StringRef FilePath, bool IsResolvingDep = false);
+
Expected<LibraryDepsInfo> extractDeps(StringRef FilePath);
void handleLibrary(StringRef FilePath, PathType K, int level = 0);
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index e74568e6bc673..3ad0a39902934 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -49,23 +49,16 @@ void handleError(Error Err, StringRef context = "") {
}));
}
-static std::string getHostFileFormatName() {
- static const std::string HostFormat = []() -> std::string {
- auto ObjOrErr = object::ObjectFile::createObjectFile(
- sys::fs::getMainExecutable(nullptr, nullptr));
-
- if (!ObjOrErr) {
- return "Unknown";
- }
-
- return (*ObjOrErr).getBinary()->getFileFormatName().str();
- }();
+bool ObjectFileLoader::isArchitectureCompatible(const object::ObjectFile &Obj) {
+ static const llvm::Triple HostTriple(llvm::sys::getProcessTriple());
+ Obj.getTripleObjectFormat();
+ if (HostTriple.getArch() != Obj.getArch())
+ return false;
- return HostFormat;
-}
+ if (Obj.getTripleObjectFormat() != HostTriple.getObjectFormat())
+ return false;
-bool ObjectFileLoader::isArchitectureCompatible(const object::ObjectFile &Obj) {
- return Obj.getFileFormatName() == getHostFileFormatName();
+ return true;
}
Expected<object::OwningBinary<object::ObjectFile>>
@@ -217,7 +210,7 @@ bool isSharedLibraryObject(object::ObjectFile &Obj) {
return false;
}
-bool DylibPathValidator::isSharedLibrary(StringRef Path) {
+bool DylibPathValidator::isSharedLibrary(StringRef Path) const {
LLVM_DEBUG(dbgs() << "Checking if path is a shared library: " << Path
<< "\n";);
@@ -235,25 +228,13 @@ bool DylibPathValidator::isSharedLibrary(StringRef Path) {
if (MagicCode == file_magic::archive)
return false;
- // Universal binary handling.
-#if defined(__APPLE__)
- if (MagicCode == file_magic::macho_universal_binary) {
- ObjectFileLoader ObjLoader(Path);
- auto ObjOrErr = ObjLoader.getObjectFile();
- if (!ObjOrErr) {
- consumeError(ObjOrErr.takeError());
- return false;
- }
- return isSharedLibraryObject(ObjOrErr.get());
- }
-#endif
-
// Object file inspection for PE/COFF, ELF, and Mach-O
bool NeedsObjectInspection =
#if defined(_WIN32)
(MagicCode == file_magic::pecoff_executable);
#elif defined(__APPLE__)
- (MagicCode == file_magic::macho_fixed_virtual_memory_shared_lib ||
+ (MagicCode == file_magic::macho_universal_binary ||
+ MagicCode == file_magic::macho_fixed_virtual_memory_shared_lib ||
MagicCode == file_magic::macho_dynamically_linked_shared_lib ||
MagicCode == file_magic::macho_dynamically_linked_shared_lib_stub);
#elif defined(LLVM_ON_UNIX)
@@ -266,20 +247,25 @@ bool DylibPathValidator::isSharedLibrary(StringRef Path) {
#error "Unsupported platform."
#endif
- if (NeedsObjectInspection) {
- ObjectFileLoader ObjLoader(Path);
- auto ObjOrErr = ObjLoader.getObjectFile();
- if (!ObjOrErr) {
- consumeError(ObjOrErr.takeError());
- return false;
- }
+ if (!NeedsObjectInspection) {
+ LLVM_DEBUG(dbgs() << "Path is not identified as a shared library: " << Path
+ << "\n";);
+ return false;
+ }
- return isSharedLibraryObject(ObjOrErr.get());
+ ObjectFileLoader ObjLoader(Path);
+ auto ObjOrErr = ObjLoader.getObjectFile();
+ if (!ObjOrErr) {
+ consumeError(ObjOrErr.takeError());
+ return false;
}
- LLVM_DEBUG(dbgs() << "Path is not identified as a shared library: " << Path
- << "\n";);
- return false;
+ bool IsShared = isSharedLibraryObject(ObjOrErr.get());
+
+ if (IsShared && ObjCache)
+ ObjCache->insert(Path, std::move(ObjLoader));
+
+ return IsShared;
}
void DylibSubstitutor::configure(StringRef LoaderPath) {
@@ -296,10 +282,10 @@ void DylibSubstitutor::configure(StringRef LoaderPath) {
}
#ifdef __APPLE__
- Placeholders["@loader_path"] = std::string(LoaderDir);
- Placeholders["@executable_path"] = std::string(ExecPath);
-#else
- Placeholders["$origin"] = std::string(LoaderDir);
+ Placeholders.push_back({"@loader_path", std::string(LoaderDir)});
+ Placeholders.push_back({"@executable_path", std::string(ExecPath)});
+ #else
+ Placeholders.push_back({"$origin", std::string(LoaderDir)});
#endif
}
@@ -423,7 +409,6 @@ DylibResolverImpl::resolve(StringRef LibStem, bool VariateLibStem) const {
if (auto Norm = tryWithExtensions(LibStem)) {
LLVM_DEBUG(dbgs() << " -> Resolved via tryWithExtensions: " << *Norm
<< "\n";);
-
return Norm;
}
}
@@ -440,7 +425,7 @@ mode_t PathResolver::lstatCached(StringRef Path) {
return *Cache;
// Not cached: perform lstat and store
- struct stat buf{};
+ struct stat buf {};
mode_t st_mode = (lstat(Path.str().c_str(), &buf) == -1) ? 0 : buf.st_mode;
LibPathCache->insert_lstat(Path, st_mode);
@@ -922,18 +907,8 @@ Expected<LibraryDepsInfo> parseELFDeps(const object::ELFObjectFileBase &Obj) {
return createStringError(std::errc::not_supported, "Unknown ELF format");
}
-Expected<LibraryDepsInfo> LibraryScanner::extractDeps(StringRef FilePath) {
- LLVM_DEBUG(dbgs() << "extractDeps: Attempting to open file " << FilePath
- << "\n";);
-
- ObjectFileLoader ObjLoader(FilePath);
- auto ObjOrErr = ObjLoader.getObjectFile();
- if (!ObjOrErr) {
- LLVM_DEBUG(dbgs() << "extractDeps: Failed to open " << FilePath << "\n";);
- return ObjOrErr.takeError();
- }
-
- object::ObjectFile *Obj = &ObjOrErr.get();
+Expected<LibraryDepsInfo> parseDependencies(StringRef FilePath,
+ object::ObjectFile *Obj) {
if (auto *elfObj = dyn_cast<object::ELFObjectFileBase>(Obj)) {
LLVM_DEBUG(dbgs() << "extractDeps: File " << FilePath
@@ -960,6 +935,28 @@ Expected<LibraryDepsInfo> LibraryScanner::extractDeps(StringRef FilePath) {
FilePath.str().c_str());
}
+Expected<LibraryDepsInfo> LibraryScanner::extractDeps(StringRef FilePath) {
+ LLVM_DEBUG(dbgs() << "extractDeps: Attempting to open file " << FilePath
+ << "\n";);
+ // check cache first
+ if (auto Cached = ObjCache.take(FilePath)) {
+ auto ObjOrErr = Cached->getObjectFile();
+ if (!ObjOrErr)
+ return ObjOrErr.takeError();
+ return parseDependencies(FilePath, &*ObjOrErr);
+ }
+
+ // fall back to normal loading
+ ObjectFileLoader ObjLoader(FilePath);
+ auto ObjOrErr = ObjLoader.getObjectFile();
+ if (!ObjOrErr) {
+ LLVM_DEBUG(dbgs() << "extractDeps: Failed to open " << FilePath << "\n";);
+ return ObjOrErr.takeError();
+ }
+
+ return parseDependencies(FilePath, &*ObjOrErr);
+}
+
bool LibraryScanner::shouldScan(StringRef FilePath, bool IsResolvingDep) {
LLVM_DEBUG(dbgs() << "[shouldScan] Checking: " << FilePath << "\n";);
@@ -977,7 +974,7 @@ bool LibraryScanner::shouldScan(StringRef FilePath, bool IsResolvingDep) {
}*/
// [3] Skip if it's not a shared library.
- if (!IsResolvingDep && !DylibPathValidator::isSharedLibrary(FilePath)) {
+ if (!IsResolvingDep && !Validator.isSharedLibrary(FilePath)) {
LLVM_DEBUG(dbgs() << " -> Skipped: not a shared library.\n";);
return false;
}
@@ -1063,8 +1060,6 @@ void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
return;
}
- DylibPathValidator Validator(ScanHelper.getPathResolver(),
- ScanHelper.getCache());
DylibResolver Resolver(Validator);
Resolver.configure(FilePath,
{{Deps.rpath, SearchPathType::RPath},
>From 63f3667e2a2d4299763805a08d51f3a36dc67e8d Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Thu, 25 Dec 2025 15:25:40 +0530
Subject: [PATCH 09/11] Improve resolution logic: add ELF hash check, replace
set with vector, and refactor code
---
.../Orc/TargetProcess/LibraryResolver.h | 98 ++++++------
.../Orc/TargetProcess/LibraryScanner.h | 4 +-
.../Orc/TargetProcess/LibraryResolver.cpp | 146 ++++++++++++------
.../Orc/TargetProcess/LibraryScanner.cpp | 8 +-
.../Orc/LibraryResolverTest.cpp | 12 +-
5 files changed, 170 insertions(+), 98 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
index 28271d3390b80..4f8b9b8f21a55 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
@@ -350,13 +350,14 @@ struct SymbolEnumeratorOptions {
IgnoreUndefined = 1 << 0,
IgnoreWeak = 1 << 1,
IgnoreIndirect = 1 << 2,
- IgnoreHidden = 1 << 3,
- IgnoreNonGlobal = 1 << 4
+ IgnoreNonGlobal = 1 << 3,
+ IgnoreHidden = 1 << 4,
+ IgnoreNonExported = 1 << 5
};
static SymbolEnumeratorOptions defaultOptions() {
- return {Filter::IgnoreUndefined | Filter::IgnoreWeak |
- Filter::IgnoreIndirect};
+ return {Filter::IgnoreUndefined | Filter::IgnoreHidden |
+ Filter::IgnoreNonGlobal};
}
uint32_t FilterFlags = Filter::None;
};
@@ -399,79 +400,88 @@ class LibraryResolver {
class SymbolQuery {
public:
/// Holds the result for a single symbol.
- struct Result {
+ struct Entry {
std::string Name;
std::string ResolvedLibPath;
};
private:
mutable std::shared_mutex Mtx;
- StringMap<Result> Results;
+ SmallVector<Entry, 24> Entries;
std::atomic<size_t> ResolvedCount = 0;
public:
- explicit SymbolQuery(const std::vector<std::string> &Symbols) {
- for (const auto &s : Symbols) {
- if (!Results.contains(s))
- Results.insert({s, Result{s, ""}});
+ explicit SymbolQuery(ArrayRef<StringRef> Symbols) {
+ for (const auto &S : Symbols) {
+ if (!contains(S))
+ Entries.push_back({S.str(), ""});
}
}
+ bool contains(StringRef Name) const {
+ return llvm::any_of(Entries,
+ [&](const Entry &E) { return E.Name == Name; });
+ }
+
SmallVector<StringRef> getUnresolvedSymbols() const {
SmallVector<StringRef> Unresolved;
std::shared_lock<std::shared_mutex> Lock(Mtx);
- for (const auto &[name, res] : Results) {
- if (res.ResolvedLibPath.empty())
- Unresolved.push_back(name);
+ for (const auto &E : Entries) {
+ if (E.ResolvedLibPath.empty())
+ Unresolved.push_back(E.Name);
}
return Unresolved;
}
void resolve(StringRef Sym, const std::string &LibPath) {
- std::unique_lock<std::shared_mutex> Lock(Mtx);
- auto It = Results.find(Sym);
- if (It != Results.end() && It->second.ResolvedLibPath.empty()) {
- It->second.ResolvedLibPath = LibPath;
- ResolvedCount.fetch_add(1, std::memory_order_relaxed);
+ std::unique_lock Lock(Mtx);
+ for (auto &E : Entries) {
+ if (E.Name == Sym && E.ResolvedLibPath.empty()) {
+ E.ResolvedLibPath = LibPath;
+ ResolvedCount.fetch_add(1, std::memory_order_relaxed);
+ return;
+ }
}
}
bool allResolved() const {
- return ResolvedCount.load(std::memory_order_relaxed) == Results.size();
+ return ResolvedCount.load(std::memory_order_relaxed) == Entries.size();
}
bool hasUnresolved() const {
- return ResolvedCount.load(std::memory_order_relaxed) < Results.size();
+ return ResolvedCount.load(std::memory_order_relaxed) < Entries.size();
}
std::optional<StringRef> getResolvedLib(StringRef Sym) const {
- std::shared_lock<std::shared_mutex> Lock(Mtx);
- auto It = Results.find(Sym);
- if (It != Results.end() && !It->second.ResolvedLibPath.empty())
- return StringRef(It->second.ResolvedLibPath);
+ std::shared_lock Lock(Mtx);
+ for (const auto &E : Entries)
+ if (E.Name == Sym && !E.ResolvedLibPath.empty())
+ return E.ResolvedLibPath;
return std::nullopt;
}
bool isResolved(StringRef Sym) const {
- std::shared_lock<std::shared_mutex> Lock(Mtx);
- auto It = Results.find(Sym.str());
- return It != Results.end() && !It->second.ResolvedLibPath.empty();
+ std::shared_lock Lock(Mtx);
+ for (const auto &E : Entries)
+ if (E.Name == Sym && !E.ResolvedLibPath.empty())
+ return true;
+ return false;
}
- std::vector<const Result *> getAllResults() const {
+ std::vector<const Entry *> getAllResults() const {
std::shared_lock<std::shared_mutex> Lock(Mtx);
- std::vector<const Result *> Out;
- Out.reserve(Results.size());
- for (const auto &[_, res] : Results)
- Out.push_back(&res);
+ std::vector<const Entry *> Out;
+ Out.reserve(Entries.size());
+ for (const auto &E : Entries)
+ Out.push_back(&E);
return Out;
}
};
struct Setup {
std::vector<std::string> BasePaths;
- std::shared_ptr<LibraryPathCache> Cache;
- std::shared_ptr<PathResolver> PResolver;
+ // std::shared_ptr<LibraryPathCache> Cache;
+ // std::shared_ptr<PathResolver> PResolver;
size_t ScanBatchSize = 0;
@@ -483,17 +493,19 @@ class LibraryResolver {
static Setup
create(std::vector<std::string> BasePaths,
- std::shared_ptr<LibraryPathCache> existingCache = nullptr,
- std::shared_ptr<PathResolver> existingResolver = nullptr,
+ // std::shared_ptr<LibraryPathCache> existingCache = nullptr,
+ // std::shared_ptr<PathResolver> existingResolver = nullptr,
LibraryScanner::ShouldScanFn customShouldScan = nullptr) {
Setup S;
S.BasePaths = std::move(BasePaths);
- S.Cache =
- existingCache ? existingCache : std::make_shared<LibraryPathCache>();
+ // S.Cache =
+ // existingCache ? existingCache :
+ // std::make_shared<LibraryPathCache>();
- S.PResolver = existingResolver ? existingResolver
- : std::make_shared<PathResolver>(S.Cache);
+ // S.PResolver = existingResolver ? existingResolver
+ // :
+ // std::make_shared<PathResolver>(S.Cache);
if (customShouldScan)
S.ShouldScanCall = std::move(customShouldScan);
@@ -521,7 +533,7 @@ class LibraryResolver {
});
}
- void searchSymbolsInLibraries(std::vector<std::string> &SymList,
+ void searchSymbolsInLibraries(ArrayRef<StringRef> SymList,
OnSearchComplete OnComplete,
const SearchConfig &Config = SearchConfig());
@@ -531,11 +543,11 @@ class LibraryResolver {
void resolveSymbolsInLibrary(LibraryInfo *Lib, SymbolQuery &Q,
const SymbolEnumeratorOptions &Opts);
+ LibraryManager LibMgr;
std::shared_ptr<LibraryPathCache> LibPathCache;
std::shared_ptr<PathResolver> LibPathResolver;
LibraryScanHelper ScanHelper;
BloomFilterBuilder FB;
- LibraryManager LibMgr;
LibraryScanner::ShouldScanFn ShouldScanCall;
size_t scanBatchSize;
};
@@ -571,7 +583,7 @@ class LibraryResolutionDriver {
LR->scanLibrariesIfNeeded(PK, BatchSize);
}
- void resolveSymbols(std::vector<std::string> Symbols,
+ void resolveSymbols(ArrayRef<StringRef> Symbols,
LibraryResolver::OnSearchComplete OnCompletion,
const SearchConfig &Config = SearchConfig());
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index d42f9b6240861..690ddf3a966a1 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -424,14 +424,14 @@ class LibraryScanHelper {
addBasePath(const std::string &P,
PathType Kind =
PathType::Unknown); // Add a canonical directory for scanning
- std::vector<const LibrarySearchPath *> getNextBatch(PathType Kind,
+ SmallVector<const LibrarySearchPath *> getNextBatch(PathType Kind,
size_t batchSize);
bool leftToScan(PathType K) const;
void resetToScan();
bool isTrackedBasePath(StringRef P) const;
- std::vector<const LibrarySearchPath *> getAllUnits() const;
+ SmallVector<const LibrarySearchPath *> getAllUnits() const;
SmallVector<StringRef> getSearchPaths() const {
SmallVector<StringRef> SearchPaths;
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
index 4e68501cbfc4a..52b2cd8cb9fd8 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
@@ -21,22 +21,21 @@
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/DJB.h"
#include "llvm/Support/Error.h"
#include <mutex>
-#include <thread>
#define DEBUG_TYPE "orc-resolver"
namespace llvm::orc {
LibraryResolver::LibraryResolver(const LibraryResolver::Setup &S)
- : LibPathCache(S.Cache ? S.Cache : std::make_shared<LibraryPathCache>()),
- LibPathResolver(S.PResolver
- ? S.PResolver
- : std::make_shared<PathResolver>(LibPathCache)),
+ : LibMgr(LibraryManager()),
+ LibPathCache(std::make_shared<LibraryPathCache>()),
+ LibPathResolver(std::make_shared<PathResolver>(LibPathCache)),
ScanHelper(S.BasePaths, LibPathCache, LibPathResolver),
- FB(S.FilterBuilder), LibMgr(),
+ FB(S.FilterBuilder),
ShouldScanCall(S.ShouldScanCall ? S.ShouldScanCall
: [](StringRef) -> bool { return true; }),
scanBatchSize(S.ScanBatchSize) {
@@ -66,10 +65,9 @@ void LibraryResolutionDriver::markLibraryUnLoaded(StringRef Path) {
}
void LibraryResolutionDriver::resolveSymbols(
- std::vector<std::string> Syms,
- LibraryResolver::OnSearchComplete OnCompletion,
+ ArrayRef<StringRef> Symbols, LibraryResolver::OnSearchComplete OnCompletion,
const SearchConfig &Config) {
- LR->searchSymbolsInLibraries(Syms, std::move(OnCompletion), Config);
+ LR->searchSymbolsInLibraries(Symbols, std::move(OnCompletion), Config);
}
static bool shouldIgnoreSymbol(const object::SymbolRef &Sym,
@@ -86,6 +84,15 @@ static bool shouldIgnoreSymbol(const object::SymbolRef &Sym,
if ((IgnoreFlags & Filter::IgnoreUndefined) &&
(Flags & object::SymbolRef::SF_Undefined))
return true;
+ if ((IgnoreFlags & Filter::IgnoreNonExported) &&
+ !(Flags & object::SymbolRef::SF_Exported))
+ return true;
+ if ((IgnoreFlags & Filter::IgnoreNonGlobal) &&
+ !(Flags & object::SymbolRef::SF_Global))
+ return true;
+ if ((IgnoreFlags & Filter::IgnoreHidden) &&
+ (Flags & object::SymbolRef::SF_Hidden))
+ return true;
if ((IgnoreFlags & Filter::IgnoreIndirect) &&
(Flags & object::SymbolRef::SF_Indirect))
return true;
@@ -172,22 +179,52 @@ bool SymbolEnumerator::enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
return SymbolEnumerator::enumerateSymbols(&ObjOrErr.get(), OnEach, Opts);
}
-class SymbolSearchContext {
-public:
- SymbolSearchContext(SymbolQuery &Q) : Q(Q) {}
-
- bool hasSearched(const LibraryInfo *Lib) const { return Searched.count(Lib); }
-
- void markSearched(const LibraryInfo *Lib) { Searched.insert(Lib); }
-
- inline bool allResolved() const { return Q.allResolved(); }
-
- SymbolQuery &query() { return Q; }
+static StringRef GetGnuHashSection(llvm::object::ObjectFile *file) {
+ for (auto S : file->sections()) {
+ StringRef name = llvm::cantFail(S.getName());
+ if (name == ".gnu.hash") {
+ return llvm::cantFail(S.getContents());
+ }
+ }
+ return "";
+}
-private:
- SymbolQuery &Q;
- DenseSet<const LibraryInfo *> Searched;
-};
+/// Bloom filter is a stochastic data structure which can tell us if a symbol
+/// name does not exist in a library with 100% certainty. If it tells us it
+/// exists this may not be true:
+/// https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2
+///
+/// ELF has this optimization in the new linkers by default, It is stored in the
+/// gnu.hash section of the object file.
+///
+///\returns true if the symbol may be in the library.
+static bool MayExistInElfObjectFile(llvm::object::ObjectFile *soFile,
+ StringRef Sym) {
+ assert(soFile->isELF() && "Not ELF");
+
+ uint32_t hash = djbHash(Sym);
+ // Compute the platform bitness -- either 64 or 32.
+ const unsigned bits = 8 * soFile->getBytesInAddress();
+
+ StringRef contents = GetGnuHashSection(soFile);
+ if (contents.size() < 16)
+ // We need to search if the library doesn't have .gnu.hash section!
+ return true;
+ const char *hashContent = contents.data();
+
+ // See https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/ for .gnu.hash
+ // table layout.
+ uint32_t maskWords = *reinterpret_cast<const uint32_t *>(hashContent + 8);
+ uint32_t shift2 = *reinterpret_cast<const uint32_t *>(hashContent + 12);
+ uint32_t hash2 = hash >> shift2;
+ uint32_t n = (hash / bits) % maskWords;
+
+ const char *bloomfilter = hashContent + 16;
+ const char *hash_pos = bloomfilter + n * (bits / 8); // * (Bits / 8)
+ uint64_t word = *reinterpret_cast<const uint64_t *>(hash_pos);
+ uint64_t bitmask = ((1ULL << (hash % bits)) | (1ULL << (hash2 % bits)));
+ return (bitmask & word) == bitmask;
+}
void LibraryResolver::resolveSymbolsInLibrary(
LibraryInfo *Lib, SymbolQuery &UnresolvedSymbols,
@@ -206,16 +243,16 @@ void LibraryResolver::resolveSymbolsInLibrary(
const auto &Unresolved = UnresolvedSymbols.getUnresolvedSymbols();
LLVM_DEBUG(dbgs() << "Total unresolved symbols : " << Unresolved.size()
<< "\n";);
- DenseSet<StringRef> CandidateSet;
- CandidateSet.reserve(Unresolved.size());
+
+ // Build candidate vector
+ SmallVector<StringRef, 24> CandidateVec;
+ CandidateVec.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);
+ CandidateVec.push_back(Sym);
}
- if (CandidateSet.empty()) {
+ if (CandidateVec.empty()) {
LLVM_DEBUG(dbgs() << "No symbol Exist "
" in library: "
<< Lib->getFullPath() << "\n";);
@@ -225,7 +262,6 @@ void LibraryResolver::resolveSymbolsInLibrary(
bool BuildingFilter = !Lib->hasFilter();
ObjectFileLoader ObjLoader(Lib->getFullPath());
-
auto ObjOrErr = ObjLoader.getObjectFile();
if (!ObjOrErr) {
std::string ErrMsg;
@@ -237,30 +273,47 @@ void LibraryResolver::resolveSymbolsInLibrary(
}
object::ObjectFile *Obj = &ObjOrErr.get();
+ if (BuildingFilter && Obj->isELF()) {
+
+ erase_if(CandidateVec,
+ [&](StringRef C) { return !MayExistInElfObjectFile(Obj, C); });
+ if (CandidateVec.empty())
+ return;
+ }
- SmallVector<StringRef, 512> SymbolVec;
+ SmallVector<StringRef, 256> SymbolVec;
LLVM_DEBUG(dbgs() << "Enumerating symbols in library: " << Lib->getFullPath()
<< "\n";);
+
SymbolEnumerator::enumerateSymbols(
Obj,
[&](StringRef S) {
- // If buildingFilter, collect for filter construction.
- if (BuildingFilter) {
+ // Collect symbols if we're building a filter
+ if (BuildingFilter)
SymbolVec.push_back(S);
- }
- auto It = CandidateSet.find(S);
- if (It != CandidateSet.end()) {
- // Resolve symbol and remove from remaining set
+
+ // auto It = std::lower_bound(CandidateVec.begin(),
+ // CandidateVec.end(), S);
+ auto It = std::find(CandidateVec.begin(), CandidateVec.end(), S);
+ if (It != CandidateVec.end() && *It == S) {
+ // Resolve and remove from CandidateVec
LLVM_DEBUG(dbgs() << "Symbol '" << S << "' resolved in library: "
<< Lib->getFullPath() << "\n";);
- UnresolvedSymbols.resolve(*It, Lib->getFullPath());
+ UnresolvedSymbols.resolve(S, Lib->getFullPath());
HadAnySym = true;
- // EARLY STOP — everything matched
+ CandidateVec.erase(It);
+
+ // EARLY STOP — if nothing remains, stop enumeration
+ if (!BuildingFilter && CandidateVec.empty()) {
+ return EnumerateResult::Stop;
+ }
+ // Also stop if UnresolvedSymbols has no more unresolved symbols
if (!BuildingFilter && !UnresolvedSymbols.hasUnresolved())
return EnumerateResult::Stop;
}
+
return EnumerateResult::Continue;
},
Opts);
@@ -286,9 +339,9 @@ void LibraryResolver::resolveSymbolsInLibrary(
Lib->setState(LibState::Queried);
}
-void LibraryResolver::searchSymbolsInLibraries(
- std::vector<std::string> &SymbolList, OnSearchComplete OnComplete,
- const SearchConfig &Config) {
+void LibraryResolver::searchSymbolsInLibraries(ArrayRef<StringRef> SymbolList,
+ OnSearchComplete OnComplete,
+ const SearchConfig &Config) {
SymbolQuery Q(SymbolList);
using LibraryType = PathType;
@@ -296,9 +349,8 @@ void LibraryResolver::searchSymbolsInLibraries(
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()) {
+ while (!Q.allResolved()) {
const LibraryInfo *Lib = Cur.nextValidLib();
// Cursor not valid?
if (!Lib) {
@@ -308,9 +360,9 @@ void LibraryResolver::searchSymbolsInLibraries(
}
// can use Async here?
- resolveSymbolsInLibrary(const_cast<LibraryInfo *>(Lib), Ctx.query(),
+ resolveSymbolsInLibrary(const_cast<LibraryInfo *>(Lib), Q,
Config.Options);
- if (Ctx.allResolved())
+ if (Q.allResolved())
break;
}
};
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index 3ad0a39902934..d3c540971747d 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -678,9 +678,9 @@ void LibraryScanHelper::addBasePath(const std::string &Path, PathType K) {
}
}
-std::vector<const LibrarySearchPath *>
+SmallVector<const LibrarySearchPath *>
LibraryScanHelper::getNextBatch(PathType K, size_t BatchSize) {
- std::vector<const LibrarySearchPath *> Result;
+ SmallVector<const LibrarySearchPath *> Result;
auto &Queue = (K == PathType::User) ? UnscannedUsr : UnscannedSys;
std::unique_lock<std::shared_mutex> Lock(Mtx);
@@ -736,9 +736,9 @@ void LibraryScanHelper::resetToScan() {
}
}
-std::vector<const LibrarySearchPath *> LibraryScanHelper::getAllUnits() const {
+SmallVector<const LibrarySearchPath *> LibraryScanHelper::getAllUnits() const {
std::shared_lock<std::shared_mutex> Lock(Mtx);
- std::vector<const LibrarySearchPath *> Result;
+ SmallVector<const LibrarySearchPath *> Result;
Result.reserve(LibSearchPaths.size());
for (const auto &[_, SP] : LibSearchPaths) {
Result.push_back(SP.get());
diff --git a/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp b/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp
index 557e869f9ca93..54237e5279df0 100644
--- a/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/LibraryResolverTest.cpp
@@ -309,6 +309,14 @@ static bool endsWith(const std::string &s, const std::string &suffix) {
return std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
}
+static llvm::SmallVector<llvm::StringRef, 16>
+toRefs(const std::vector<std::string> &Syms) {
+ llvm::SmallVector<llvm::StringRef, 16> R;
+ for (auto &S : Syms)
+ R.push_back(S);
+ return R;
+}
+
TEST_F(LibraryResolverIT, EnumerateSymbols_ExportsOnly_DefaultFlags) {
const std::string libC = lib("C");
SymbolEnumeratorOptions Opts = SymbolEnumeratorOptions::defaultOptions();
@@ -384,7 +392,7 @@ TEST_F(LibraryResolverIT, DriverResolvesSymbolsToCorrectLibraries) {
platformSymbolName("sayZ")};
bool CallbackRan = false;
- Driver->resolveSymbols(Syms, [&](SymbolQuery &Q) {
+ Driver->resolveSymbols(toRefs(Syms), [&](SymbolQuery &Q) {
CallbackRan = true;
// sayA should resolve to A.dylib
@@ -435,7 +443,7 @@ TEST_F(LibraryResolverIT, ResolveManySymbols) {
platformSymbolName("sayA"), platformSymbolName("sayB")};
bool CallbackRan = false;
- Driver->resolveSymbols(Syms, [&](SymbolQuery &Q) {
+ Driver->resolveSymbols(toRefs(Syms), [&](SymbolQuery &Q) {
CallbackRan = true;
EXPECT_TRUE(Q.isResolved(platformSymbolName("sayA")));
EXPECT_TRUE(Q.isResolved(platformSymbolName("sayB")));
>From 77c2ee1ec2a46b278a9426251689a08b2222a615 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Fri, 26 Dec 2025 15:30:21 +0530
Subject: [PATCH 10/11] Refactor: simplify getUnresolvedSymbol to create
CandidateVec directly and some other small improvment
---
.../Orc/TargetProcess/LibraryResolver.h | 8 ++---
.../Orc/TargetProcess/LibraryScanner.h | 7 +++--
.../Orc/TargetProcess/LibraryResolver.cpp | 30 ++++++++-----------
.../Orc/TargetProcess/LibraryScanner.cpp | 25 +++++-----------
4 files changed, 28 insertions(+), 42 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
index 4f8b9b8f21a55..871d3512af322 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
@@ -423,14 +423,14 @@ class LibraryResolver {
[&](const Entry &E) { return E.Name == Name; });
}
- SmallVector<StringRef> getUnresolvedSymbols() const {
- SmallVector<StringRef> Unresolved;
+ using SymbolFilterFn = unique_function<bool(StringRef)>;
+ void getUnresolvedSymbols(SmallVectorImpl<StringRef> &Unresolved,
+ SymbolFilterFn Allow) const {
std::shared_lock<std::shared_mutex> Lock(Mtx);
for (const auto &E : Entries) {
- if (E.ResolvedLibPath.empty())
+ if (E.ResolvedLibPath.empty() && Allow(E.Name))
Unresolved.push_back(E.Name);
}
- return Unresolved;
}
void resolve(StringRef Sym, const std::string &LibPath) {
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index 690ddf3a966a1..abfcbee1d2e5c 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -424,14 +424,15 @@ class LibraryScanHelper {
addBasePath(const std::string &P,
PathType Kind =
PathType::Unknown); // Add a canonical directory for scanning
- SmallVector<const LibrarySearchPath *> getNextBatch(PathType Kind,
- size_t batchSize);
+
+ void getNextBatch(PathType Kind, size_t batchSize,
+ SmallVectorImpl<const LibrarySearchPath *> &Out);
bool leftToScan(PathType K) const;
void resetToScan();
bool isTrackedBasePath(StringRef P) const;
- SmallVector<const LibrarySearchPath *> getAllUnits() const;
+ bool hasSearchPath() const { return !LibSearchPaths.empty(); }
SmallVector<StringRef> getSearchPaths() const {
SmallVector<StringRef> SearchPaths;
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
index 52b2cd8cb9fd8..69b920ff3f665 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
@@ -40,7 +40,7 @@ LibraryResolver::LibraryResolver(const LibraryResolver::Setup &S)
: [](StringRef) -> bool { return true; }),
scanBatchSize(S.ScanBatchSize) {
- if (ScanHelper.getAllUnits().empty()) {
+ if (!ScanHelper.hasSearchPath()) {
LLVM_DEBUG(dbgs() << "Warning: No base paths provided for scanning.\n");
}
}
@@ -227,12 +227,11 @@ static bool MayExistInElfObjectFile(llvm::object::ObjectFile *soFile,
}
void LibraryResolver::resolveSymbolsInLibrary(
- LibraryInfo *Lib, SymbolQuery &UnresolvedSymbols,
- const SymbolEnumeratorOptions &Opts) {
+ LibraryInfo *Lib, SymbolQuery &Query, const SymbolEnumeratorOptions &Opts) {
LLVM_DEBUG(dbgs() << "Checking unresolved symbols "
<< " in library : " << Lib->getFileName() << "\n";);
- if (!UnresolvedSymbols.hasUnresolved()) {
+ if (!Query.hasUnresolved()) {
LLVM_DEBUG(dbgs() << "Skipping library: " << Lib->getFullPath()
<< " — unresolved symbols exist.\n";);
return;
@@ -240,18 +239,15 @@ void LibraryResolver::resolveSymbolsInLibrary(
bool HadAnySym = false;
- const auto &Unresolved = UnresolvedSymbols.getUnresolvedSymbols();
- LLVM_DEBUG(dbgs() << "Total unresolved symbols : " << Unresolved.size()
- << "\n";);
-
// Build candidate vector
SmallVector<StringRef, 24> CandidateVec;
- CandidateVec.reserve(Unresolved.size());
- for (const auto &Sym : Unresolved) {
- if (!Lib->hasFilter() || Lib->mayContain(Sym))
- CandidateVec.push_back(Sym);
- }
+ Query.getUnresolvedSymbols(CandidateVec, [&](StringRef S) {
+ return !Lib->hasFilter() || Lib->mayContain(S);
+ });
+
+ LLVM_DEBUG(dbgs() << "Total candidate symbols : " << CandidateVec.size()
+ << "\n";);
if (CandidateVec.empty()) {
LLVM_DEBUG(dbgs() << "No symbol Exist "
" in library: "
@@ -300,17 +296,17 @@ void LibraryResolver::resolveSymbolsInLibrary(
// Resolve and remove from CandidateVec
LLVM_DEBUG(dbgs() << "Symbol '" << S << "' resolved in library: "
<< Lib->getFullPath() << "\n";);
- UnresolvedSymbols.resolve(S, Lib->getFullPath());
+ Query.resolve(S, Lib->getFullPath());
HadAnySym = true;
-
- CandidateVec.erase(It);
+ *It = CandidateVec.back();
+ CandidateVec.pop_back();
// EARLY STOP — if nothing remains, stop enumeration
if (!BuildingFilter && CandidateVec.empty()) {
return EnumerateResult::Stop;
}
// Also stop if UnresolvedSymbols has no more unresolved symbols
- if (!BuildingFilter && !UnresolvedSymbols.hasUnresolved())
+ if (!BuildingFilter && !Query.hasUnresolved())
return EnumerateResult::Stop;
}
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index d3c540971747d..80a33c41bf6e6 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -284,7 +284,7 @@ void DylibSubstitutor::configure(StringRef LoaderPath) {
#ifdef __APPLE__
Placeholders.push_back({"@loader_path", std::string(LoaderDir)});
Placeholders.push_back({"@executable_path", std::string(ExecPath)});
- #else
+#else
Placeholders.push_back({"$origin", std::string(LoaderDir)});
#endif
}
@@ -425,7 +425,7 @@ mode_t PathResolver::lstatCached(StringRef Path) {
return *Cache;
// Not cached: perform lstat and store
- struct stat buf {};
+ struct stat buf{};
mode_t st_mode = (lstat(Path.str().c_str(), &buf) == -1) ? 0 : buf.st_mode;
LibPathCache->insert_lstat(Path, st_mode);
@@ -678,9 +678,9 @@ void LibraryScanHelper::addBasePath(const std::string &Path, PathType K) {
}
}
-SmallVector<const LibrarySearchPath *>
-LibraryScanHelper::getNextBatch(PathType K, size_t BatchSize) {
- SmallVector<const LibrarySearchPath *> Result;
+void LibraryScanHelper::getNextBatch(
+ PathType K, size_t BatchSize,
+ SmallVectorImpl<const LibrarySearchPath *> &Result) {
auto &Queue = (K == PathType::User) ? UnscannedUsr : UnscannedSys;
std::unique_lock<std::shared_mutex> Lock(Mtx);
@@ -697,8 +697,6 @@ LibraryScanHelper::getNextBatch(PathType K, size_t BatchSize) {
}
Queue.pop_front();
}
-
- return Result;
}
bool LibraryScanHelper::isTrackedBasePath(StringRef Path) const {
@@ -736,16 +734,6 @@ void LibraryScanHelper::resetToScan() {
}
}
-SmallVector<const LibrarySearchPath *> LibraryScanHelper::getAllUnits() const {
- std::shared_lock<std::shared_mutex> Lock(Mtx);
- SmallVector<const LibrarySearchPath *> Result;
- Result.reserve(LibSearchPaths.size());
- for (const auto &[_, SP] : LibSearchPaths) {
- Result.push_back(SP.get());
- }
- return Result;
-}
-
std::string LibraryScanHelper::resolveCanonical(StringRef Path,
std::error_code &EC) const {
auto Canon = LibPathResolver->resolve(Path, EC);
@@ -1148,7 +1136,8 @@ void LibraryScanner::scanNext(PathType K, size_t BatchSize) {
<< BatchSize << " for kind "
<< (K == PathType::User ? "User" : "System") << "\n";);
- auto SearchPaths = ScanHelper.getNextBatch(K, BatchSize);
+ SmallVector<const LibrarySearchPath *> SearchPaths;
+ ScanHelper.getNextBatch(K, BatchSize, SearchPaths);
for (const auto *SP : SearchPaths) {
LLVM_DEBUG(dbgs() << " Scanning unit with basePath: " << SP->BasePath
<< "\n";);
>From c6d1b85c4bb8894bebb0d67811bdb34a6639879f Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 27 Dec 2025 10:02:04 +0530
Subject: [PATCH 11/11] Fix compiler error
---
.../ExecutionEngine/Orc/TargetProcess/LibraryResolver.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
index 871d3512af322..045d259d4ecbb 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
@@ -434,7 +434,7 @@ class LibraryResolver {
}
void resolve(StringRef Sym, const std::string &LibPath) {
- std::unique_lock Lock(Mtx);
+ std::unique_lock<std::shared_mutex> Lock(Mtx);
for (auto &E : Entries) {
if (E.Name == Sym && E.ResolvedLibPath.empty()) {
E.ResolvedLibPath = LibPath;
@@ -453,7 +453,7 @@ class LibraryResolver {
}
std::optional<StringRef> getResolvedLib(StringRef Sym) const {
- std::shared_lock Lock(Mtx);
+ std::shared_lock<std::shared_mutex> Lock(Mtx);
for (const auto &E : Entries)
if (E.Name == Sym && !E.ResolvedLibPath.empty())
return E.ResolvedLibPath;
@@ -461,7 +461,7 @@ class LibraryResolver {
}
bool isResolved(StringRef Sym) const {
- std::shared_lock Lock(Mtx);
+ std::shared_lock<std::shared_mutex> Lock(Mtx);
for (const auto &E : Entries)
if (E.Name == Sym && !E.ResolvedLibPath.empty())
return true;
More information about the llvm-commits
mailing list