[llvm] [Orc][LibResolver] Refactor resolver internals and simplify symbol resolution. (PR #169161)

Vassil Vassilev via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 2 01:06:03 PST 2026


https://github.com/vgvassilev 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