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

via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 4 02:15:56 PST 2025


https://github.com/SahilPatidar updated https://github.com/llvm/llvm-project/pull/169161

>From 1d31d7a2be8a3a4ce2369746dc1e1e25073607b7 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 22 Nov 2025 15:55:51 +0530
Subject: [PATCH 1/5] [Orc][LibResolver] Refactor resolver internals and
 simplify symbol resolution

---
 .../Orc/TargetProcess/LibraryResolver.h       | 290 ++++++++++++------
 .../Orc/TargetProcess/LibraryScanner.h        |  10 +-
 .../Orc/TargetProcess/LibraryResolver.cpp     | 257 ++++++++--------
 .../Orc/TargetProcess/LibraryScanner.cpp      |  48 +--
 4 files changed, 358 insertions(+), 247 deletions(-)

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

>From 4f1f103435b035e8645e540ba6bb67cfa7d02751 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 22 Nov 2025 16:16:18 +0530
Subject: [PATCH 2/5] 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 3/5] 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 4/5] 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 5/5] 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",



More information about the llvm-commits mailing list