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

via llvm-commits llvm-commits at lists.llvm.org
Sat Nov 22 02:49:53 PST 2025


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

- Replace getLibraries() with cursor-based iteration.
- Simplify search logic and handle new libraries during scanning.
- Make symbol resolution faster with single enumeration and early exit.

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

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

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

>From 4f1f103435b035e8645e540ba6bb67cfa7d02751 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 22 Nov 2025 16:16:18 +0530
Subject: [PATCH 2/2] Refactor searchSymbolsInLibraries

---
 .../Orc/TargetProcess/LibraryResolver.h       |  1 +
 .../Orc/TargetProcess/LibraryResolver.cpp     | 31 +++++++++----------
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
index e12bf84ed4e63..4990d83651a69 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h
@@ -577,6 +577,7 @@ class LibraryResolver {
 
 private:
   bool scanLibrariesIfNeeded(PathType K, size_t BatchSize = 0);
+  bool scanForNewLibraries(PathType K, LibraryCursor &Cur);
   void resolveSymbolsInLibrary(LibraryInfo *Lib, SymbolQuery &Q,
                                const SymbolEnumeratorOptions &Opts);
 
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
index 510598538d643..4e68501cbfc4a 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryResolver.cpp
@@ -302,22 +302,8 @@ void LibraryResolver::searchSymbolsInLibraries(
       const LibraryInfo *Lib = Cur.nextValidLib();
       // Cursor not valid?
       if (!Lib) {
-        bool NewLibAdded = false;
-
-        // Scan as long as there is paths to scan
-        while (ScanHelper.leftToScan(K)) {
-          scanLibrariesIfNeeded(K, scanBatchSize);
-
-          // NOW check any new libraries added
-          if (Cur.hasMoreValidLib()) {
-            NewLibAdded = true;
-            break;
-          }
-        }
-
-        if (!NewLibAdded)
-          break; // No new libs found
-
+        if (!scanForNewLibraries(K, Cur))
+          break;  // nothing new was added
         continue; // Try to resolve next library
       }
 
@@ -346,6 +332,19 @@ void LibraryResolver::searchSymbolsInLibraries(
   OnComplete(Q);
 }
 
+bool LibraryResolver::scanForNewLibraries(PathType K, LibraryCursor &Cur) {
+  while (ScanHelper.leftToScan(K)) {
+    scanLibrariesIfNeeded(K, scanBatchSize);
+
+    // Check if scanning added new libraries
+    if (Cur.hasMoreValidLib())
+      return true;
+  }
+
+  // No new libraries were added
+  return false;
+}
+
 bool LibraryResolver::scanLibrariesIfNeeded(PathType PK, size_t BatchSize) {
   LLVM_DEBUG(dbgs() << "LibraryResolver::scanLibrariesIfNeeded: Scanning for "
                     << (PK == PathType::User ? "User" : "System")



More information about the llvm-commits mailing list