[llvm] r332541 - [ORC] Rewrite the VSO symbol table yet again. Update related utilities.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Wed May 16 15:24:30 PDT 2018


Author: lhames
Date: Wed May 16 15:24:30 2018
New Revision: 332541

URL: http://llvm.org/viewvc/llvm-project?rev=332541&view=rev
Log:
[ORC] Rewrite the VSO symbol table yet again. Update related utilities.

VSOs now track dependencies for materializing symbols. Each symbol must have its
dependencies registered with the VSO prior to finalization. Usually this will
involve registering the dependencies returned in
AsynchronousSymbolQuery::ResolutionResults for queries made while linking the
symbols being materialized.

Queries against symbols are notified that a symbol is ready once it and all of
its transitive dependencies are finalized, allowing compilation work to be
broken up and moved between threads without queries returning until their
symbols fully safe to access / execute.

Related utilities (VSO, MaterializationUnit, MaterializationResponsibility) are
updated to support dependence tracking and more explicitly track responsibility
for symbols from the point of definition until they are finalized.

Modified:
    llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h
    llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h
    llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h
    llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h
    llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h
    llvm/trunk/examples/Kaleidoscope/include/KaleidoscopeJIT.h
    llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h
    llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
    llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h
    llvm/trunk/include/llvm/ExecutionEngine/Orc/Legacy.h
    llvm/trunk/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h
    llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp
    llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp
    llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
    llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
    llvm/trunk/tools/lli/OrcLazyJIT.h
    llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp
    llvm/trunk/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp
    llvm/trunk/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp

Modified: llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h (original)
+++ llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h Wed May 16 15:24:30 2018
@@ -48,6 +48,7 @@ private:
 public:
   KaleidoscopeJIT()
       : Resolver(createLegacyLookupResolver(
+            ES,
             [this](const std::string &Name) -> JITSymbol {
               if (auto Sym = CompileLayer.findSymbol(Name, false))
                 return Sym;

Modified: llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h (original)
+++ llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h Wed May 16 15:24:30 2018
@@ -58,6 +58,7 @@ private:
 public:
   KaleidoscopeJIT()
       : Resolver(createLegacyLookupResolver(
+            ES,
             [this](const std::string &Name) -> JITSymbol {
               if (auto Sym = OptimizeLayer.findSymbol(Name, false))
                 return Sym;

Modified: llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h (original)
+++ llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h Wed May 16 15:24:30 2018
@@ -98,6 +98,7 @@ public:
 
     // Build a resolver and associate it with the new key.
     Resolvers[K] = createLegacyLookupResolver(
+        ES,
         [this](const std::string &Name) -> JITSymbol {
           if (auto Sym = CompileLayer.findSymbol(Name, false))
             return Sym;

Modified: llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h (original)
+++ llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h Wed May 16 15:24:30 2018
@@ -91,6 +91,7 @@ private:
 public:
   KaleidoscopeJIT()
       : Resolver(createLegacyLookupResolver(
+            ES,
             [this](const std::string &Name) -> JITSymbol {
               if (auto Sym = IndirectStubsMgr->findStub(Name, false))
                 return Sym;

Modified: llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h (original)
+++ llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h Wed May 16 15:24:30 2018
@@ -97,6 +97,7 @@ private:
 public:
   KaleidoscopeJIT(MyRemote &Remote)
       : Resolver(createLegacyLookupResolver(
+            ES,
             [this](const std::string &Name) -> JITSymbol {
               if (auto Sym = IndirectStubsMgr->findStub(Name, false))
                 return Sym;

Modified: llvm/trunk/examples/Kaleidoscope/include/KaleidoscopeJIT.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/examples/Kaleidoscope/include/KaleidoscopeJIT.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/examples/Kaleidoscope/include/KaleidoscopeJIT.h (original)
+++ llvm/trunk/examples/Kaleidoscope/include/KaleidoscopeJIT.h Wed May 16 15:24:30 2018
@@ -45,6 +45,7 @@ public:
 
   KaleidoscopeJIT()
       : Resolver(createLegacyLookupResolver(
+            ES,
             [this](const std::string &Name) {
               return ObjectLayer.findSymbol(Name, true);
             },

Modified: llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h Wed May 16 15:24:30 2018
@@ -174,6 +174,9 @@ public:
   /// Return the flags for this symbol.
   JITSymbolFlags getFlags() const { return Flags; }
 
+  /// Set the flags for this symbol.
+  void setFlags(JITSymbolFlags Flags) { this->Flags = std::move(Flags); }
+
 private:
   JITTargetAddress Address = 0;
   JITSymbolFlags Flags;

Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h Wed May 16 15:24:30 2018
@@ -490,10 +490,11 @@ private:
           return LD.BackingResolver->lookupFlags(SymbolFlags,
                                                  *NotFoundViaLegacyLookup);
         },
-        [&LD, LegacyLookup](std::shared_ptr<AsynchronousSymbolQuery> Query,
-                            SymbolNameSet Symbols) {
+        [this, &LD,
+         LegacyLookup](std::shared_ptr<AsynchronousSymbolQuery> Query,
+                       SymbolNameSet Symbols) {
           auto NotFoundViaLegacyLookup =
-              lookupWithLegacyFn(*Query, Symbols, LegacyLookup);
+              lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
           return LD.BackingResolver->lookup(Query, NotFoundViaLegacyLookup);
         });
 
@@ -647,10 +648,10 @@ private:
           return LD.BackingResolver->lookupFlags(SymbolFlags,
                                                  *NotFoundViaLegacyLookup);
         },
-        [&LD, LegacyLookup](std::shared_ptr<AsynchronousSymbolQuery> Q,
-                            SymbolNameSet Symbols) {
+        [this, &LD, LegacyLookup](std::shared_ptr<AsynchronousSymbolQuery> Q,
+                                  SymbolNameSet Symbols) {
           auto NotFoundViaLegacyLookup =
-              lookupWithLegacyFn(*Q, Symbols, LegacyLookup);
+              lookupWithLegacyFn(ES, *Q, Symbols, LegacyLookup);
           return LD.BackingResolver->lookup(Q,
                                             std::move(NotFoundViaLegacyLookup));
         });

Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h Wed May 16 15:24:30 2018
@@ -27,6 +27,10 @@ namespace llvm {
 namespace orc {
 
 // Forward declare some classes.
+class AsynchronousSymbolQuery;
+class ExecutionSession;
+class MaterializationUnit;
+class MaterializationResponsibility;
 class VSO;
 
 /// VModuleKey provides a unique identifier (allocated and managed by
@@ -55,6 +59,13 @@ raw_ostream &operator<<(raw_ostream &OS,
 
 /// A base class for materialization failures that allows the failing
 ///        symbols to be obtained for logging.
+using SymbolDependenceMap = std::map<VSO *, SymbolNameSet>;
+
+/// Render a SymbolDependendeMap.
+raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
+
+/// A base class for materialization failures that allows the failing
+/// symbols to be obtained for logging.
 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
 public:
   static char ID;
@@ -91,14 +102,252 @@ private:
   SymbolNameSet Symbols;
 };
 
+/// Tracks responsibility for materialization, and mediates interactions between
+/// MaterializationUnits and VSOs.
+///
+/// An instance of this class is passed to MaterializationUnits when their
+/// materialize method is called. It allows MaterializationUnits to resolve and
+/// finalize symbols, or abandon materialization by notifying any unmaterialized
+/// symbols of an error.
+class MaterializationResponsibility {
+public:
+  /// Create a MaterializationResponsibility for the given VSO and
+  ///        initial symbols.
+  MaterializationResponsibility(VSO &V, SymbolFlagsMap SymbolFlags);
+
+  MaterializationResponsibility(MaterializationResponsibility &&) = default;
+  MaterializationResponsibility &
+  operator=(MaterializationResponsibility &&) = default;
+
+  /// Destruct a MaterializationResponsibility instance. In debug mode
+  ///        this asserts that all symbols being tracked have been either
+  ///        finalized or notified of an error.
+  ~MaterializationResponsibility();
+
+  /// Returns the target VSO that these symbols are being materialized
+  ///        into.
+  const VSO &getTargetVSO() const { return V; }
+
+  /// Resolves the given symbols. Individual calls to this method may
+  ///        resolve a subset of the symbols, but all symbols must have been
+  ///        resolved prior to calling finalize.
+  void resolve(const SymbolMap &Symbols);
+
+  /// Finalizes all symbols tracked by this instance.
+  void finalize();
+
+  /// Adds new symbols to the VSO and this responsibility instance.
+  ///        VSO entries start out in the materializing state.
+  ///
+  ///   This method can be used by materialization units that want to add
+  /// additional symbols at materialization time (e.g. stubs, compile
+  /// callbacks, metadata).
+  Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
+
+  /// Notify all unfinalized symbols that an error has occurred.
+  /// This will remove all symbols covered by this MaterializationResponsibilty
+  /// from V, and send an error to any queries waiting on these symbols.
+  void failMaterialization(std::function<Error()> GenerateError);
+
+  /// Transfers responsibility to the given MaterializationUnit for all
+  /// symbols defined by that MaterializationUnit. This allows
+  /// materializers to break up work based on run-time information (e.g.
+  /// by introspecting which symbols have actually been looked up and
+  /// materializing only those).
+  void delegate(std::unique_ptr<MaterializationUnit> MU);
+
+  /// Add dependencies for the symbols in this dylib.
+  void addDependencies(const SymbolDependenceMap &Dependencies);
+
+private:
+  VSO &V;
+  SymbolFlagsMap SymbolFlags;
+};
+
+/// A MaterializationUnit represents a set of symbol definitions that can
+///        be materialized as a group, or individually discarded (when
+///        overriding definitions are encountered).
+///
+/// MaterializationUnits are used when providing lazy definitions of symbols to
+/// VSOs. The VSO will call materialize when the address of a symbol is
+/// requested via the lookup method. The VSO will call discard if a stronger
+/// definition is added or already present.
+class MaterializationUnit {
+public:
+  MaterializationUnit(SymbolFlagsMap SymbolFlags)
+      : SymbolFlags(std::move(SymbolFlags)) {}
+
+  virtual ~MaterializationUnit() {}
+
+  /// Return the set of symbols that this source provides.
+  const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
+
+  /// Called by materialization dispatchers (see
+  /// ExecutionSession::DispatchMaterializationFunction) to trigger
+  /// materialization of this MaterializationUnit.
+  void doMaterialize(VSO &V) {
+    materialize(MaterializationResponsibility(V, std::move(SymbolFlags)));
+  }
+
+  /// Called by VSOs to notify MaterializationUnits that the given symbol has
+  /// been overridden.
+  void doDiscard(const VSO &V, SymbolStringPtr Name) {
+    SymbolFlags.erase(Name);
+    discard(V, std::move(Name));
+  }
+
+private:
+  virtual void anchor();
+
+  /// Implementations of this method should materialize all symbols
+  ///        in the materialzation unit, except for those that have been
+  ///        previously discarded.
+  virtual void materialize(MaterializationResponsibility R) = 0;
+
+  /// Implementations of this method should discard the given symbol
+  ///        from the source (e.g. if the source is an LLVM IR Module and the
+  ///        symbol is a function, delete the function body or mark it available
+  ///        externally).
+  virtual void discard(const VSO &V, SymbolStringPtr Name) = 0;
+
+  SymbolFlagsMap SymbolFlags;
+};
+
+/// A MaterializationUnit implementation for pre-existing absolute symbols.
+///
+/// All symbols will be resolved and marked ready as soon as the unit is
+/// materialized.
+class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
+public:
+  AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols);
+
+private:
+  void materialize(MaterializationResponsibility R) override;
+  void discard(const VSO &V, SymbolStringPtr Name) override;
+  static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
+
+  SymbolMap Symbols;
+};
+
+/// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
+/// Useful for inserting absolute symbols into a VSO. E.g.:
+/// \code{.cpp}
+///   VSO &V = ...;
+///   SymbolStringPtr Foo = ...;
+///   JITEvaluatedSymbol FooSym = ...;
+///   if (auto Err = V.define(absoluteSymbols({{Foo, FooSym}})))
+///     return Err;
+/// \endcode
+///
+inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
+absoluteSymbols(SymbolMap Symbols) {
+  return llvm::make_unique<AbsoluteSymbolsMaterializationUnit>(
+      std::move(Symbols));
+}
+
+/// Base utilities for ExecutionSession.
+class ExecutionSessionBase {
+public:
+  /// For reporting errors.
+  using ErrorReporter = std::function<void(Error)>;
+
+  /// For dispatching MaterializationUnit::materialize calls.
+  using DispatchMaterializationFunction =
+      std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> MU)>;
+
+  /// Construct an ExecutionSessionBase.
+  ///
+  /// SymbolStringPools may be shared between ExecutionSessions.
+  ExecutionSessionBase(std::shared_ptr<SymbolStringPool> SSP = nullptr)
+      : SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {}
+
+  /// Returns the SymbolStringPool for this ExecutionSession.
+  SymbolStringPool &getSymbolStringPool() const { return *SSP; }
+
+  /// Run the given lambda with the session mutex locked.
+  template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
+    std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
+    return F();
+  }
+
+  /// Set the error reporter function.
+  ExecutionSessionBase &setErrorReporter(ErrorReporter ReportError) {
+    this->ReportError = std::move(ReportError);
+    return *this;
+  }
+
+  /// Set the materialization dispatch function.
+  ExecutionSessionBase &setDispatchMaterialization(
+      DispatchMaterializationFunction DispatchMaterialization) {
+    this->DispatchMaterialization = std::move(DispatchMaterialization);
+    return *this;
+  }
+
+  /// Report a error for this execution session.
+  ///
+  /// Unhandled errors can be sent here to log them.
+  void reportError(Error Err) { ReportError(std::move(Err)); }
+
+  /// Allocate a module key for a new module to add to the JIT.
+  VModuleKey allocateVModule() { return ++LastKey; }
+
+  /// Return a module key to the ExecutionSession so that it can be
+  ///        re-used. This should only be done once all resources associated
+  ///        with the original key have been released.
+  void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
+  }
+
+  /// Cause the given query to fail with the given Error.
+  ///
+  /// This should only be used by legacy APIs and will be deprecated in the
+  /// future.
+  void failQuery(AsynchronousSymbolQuery &Q, Error Err);
+
+  /// Materialize the given unit.
+  void dispatchMaterialization(VSO &V,
+                               std::unique_ptr<MaterializationUnit> MU) {
+    DispatchMaterialization(V, std::move(MU));
+  }
+
+private:
+  static void logErrorsToStdErr(Error Err) {
+    logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
+  }
+
+  static void
+  materializeOnCurrentThread(VSO &V, std::unique_ptr<MaterializationUnit> MU) {
+    MU->doMaterialize(V);
+  }
+
+  mutable std::recursive_mutex SessionMutex;
+  std::shared_ptr<SymbolStringPool> SSP;
+  VModuleKey LastKey = 0;
+  ErrorReporter ReportError = logErrorsToStdErr;
+  DispatchMaterializationFunction DispatchMaterialization =
+      materializeOnCurrentThread;
+};
+
 /// A symbol query that returns results via a callback when results are
 ///        ready.
 ///
 /// makes a callback when all symbols are available.
 class AsynchronousSymbolQuery {
+  friend class ExecutionSessionBase;
+  friend class VSO;
+
 public:
+  class ResolutionResult {
+  public:
+    ResolutionResult(SymbolMap Symbols, const SymbolDependenceMap &Dependencies)
+        : Symbols(std::move(Symbols)), Dependencies(Dependencies) {}
+
+    SymbolMap Symbols;
+    const SymbolDependenceMap &Dependencies;
+  };
+
   /// Callback to notify client that symbols have been resolved.
-  using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
+  using SymbolsResolvedCallback =
+      std::function<void(Expected<ResolutionResult>)>;
 
   /// Callback to notify client that symbols are ready for execution.
   using SymbolsReadyCallback = std::function<void(Error)>;
@@ -109,36 +358,45 @@ public:
                           SymbolsResolvedCallback NotifySymbolsResolved,
                           SymbolsReadyCallback NotifySymbolsReady);
 
-  /// Notify client that the query failed.
-  ///
-  /// If the notify-resolved callback has not been made yet, then it is called
-  /// with the given error, and the notify-finalized callback is never made.
-  ///
-  /// If the notify-resolved callback has already been made then then the
-  /// notify-finalized callback is called with the given error.
-  ///
-  /// It is illegal to call setFailed after both callbacks have been made.
-  void notifyMaterializationFailed(Error Err);
-
   /// Set the resolved symbol information for the given symbol name.
+  void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym);
+
+  /// Returns true if all symbols covered by this query have been
+  ///        resolved.
+  bool isFullyResolved() const { return NotYetResolvedCount == 0; }
+
+  /// Call the NotifySymbolsResolved callback.
   ///
-  /// If this symbol was the last one not resolved, this will trigger a call to
-  /// the notify-finalized callback passing the completed sybol map.
-  void resolve(SymbolStringPtr Name, JITEvaluatedSymbol Sym);
+  /// This should only be called if all symbols covered by the query have been
+  /// resolved.
+  void handleFullyResolved();
 
   /// Notify the query that a requested symbol is ready for execution.
+  void notifySymbolReady();
+
+  /// Returns true if all symbols covered by this query are ready.
+  bool isFullyReady() const { return NotYetReadyCount == 0; }
+
+  /// Calls the NotifySymbolsReady callback.
   ///
-  /// This decrements the query's internal count of not-yet-ready symbols. If
-  /// this call to notifySymbolFinalized sets the counter to zero, it will call
-  /// the notify-finalized callback with Error::success as the value.
-  void finalizeSymbol();
+  /// This should only be called if all symbols covered by this query are ready.
+  void handleFullyReady();
 
 private:
-  SymbolMap Symbols;
-  size_t OutstandingResolutions = 0;
-  size_t OutstandingFinalizations = 0;
+  void addQueryDependence(VSO &V, SymbolStringPtr Name);
+
+  void removeQueryDependence(VSO &V, const SymbolStringPtr &Name);
+
+  void handleFailed(Error Err);
+
+  void detach();
+
   SymbolsResolvedCallback NotifySymbolsResolved;
   SymbolsReadyCallback NotifySymbolsReady;
+  SymbolDependenceMap QueryRegistrations;
+  SymbolMap ResolvedSymbols;
+  size_t NotYetResolvedCount;
+  size_t NotYetReadyCount;
 };
 
 /// SymbolResolver is a composable interface for looking up symbol flags
@@ -206,311 +464,191 @@ createSymbolResolver(LookupFlagsFn &&Loo
       std::forward<LookupFlagsFn>(LookupFlags), std::forward<LookupFn>(Lookup));
 }
 
-/// Tracks responsibility for materialization.
-///
-/// An instance of this class is passed to MaterializationUnits when their
-/// materialize method is called. It allows MaterializationUnits to resolve and
-/// finalize symbols, or abandon materialization by notifying any unmaterialized
-/// symbols of an error.
-class MaterializationResponsibility {
-public:
-  /// Create a MaterializationResponsibility for the given VSO and
-  ///        initial symbols.
-  MaterializationResponsibility(VSO &V, SymbolFlagsMap SymbolFlags);
-
-  MaterializationResponsibility(MaterializationResponsibility &&) = default;
-  MaterializationResponsibility &
-  operator=(MaterializationResponsibility &&) = default;
-
-  /// Destruct a MaterializationResponsibility instance. In debug mode
-  ///        this asserts that all symbols being tracked have been either
-  ///        finalized or notified of an error.
-  ~MaterializationResponsibility();
-
-  /// Returns the target VSO that these symbols are being materialized
-  ///        into.
-  const VSO &getTargetVSO() const { return V; }
-
-  /// Resolves the given symbols. Individual calls to this method may
-  ///        resolve a subset of the symbols, but all symbols must have been
-  ///        resolved prior to calling finalize.
-  void resolve(const SymbolMap &Symbols);
-
-  /// Finalizes all symbols tracked by this instance.
-  void finalize();
-
-  /// Notify all unfinalized symbols that an error has occurred.
-  ///        This method should be called if materialization of any symbol is
-  ///        abandoned.
-  void notifyMaterializationFailed();
-
-  /// Transfers responsibility for the given symbols to a new
-  ///        MaterializationResponsibility class. This is useful if a
-  ///        MaterializationUnit wants to transfer responsibility for a subset
-  ///        of symbols to another MaterializationUnit or utility.
-  MaterializationResponsibility delegate(SymbolNameSet Symbols);
-
-private:
-  VSO &V;
-  SymbolFlagsMap SymbolFlags;
-};
-
-/// A MaterializationUnit represents a set of symbol definitions that can
-///        be materialized as a group, or individually discarded (when
-///        overriding definitions are encountered).
-///
-/// MaterializationUnits are used when providing lazy definitions of symbols to
-/// VSOs. The VSO will call materialize when the address of a symbol is
-/// requested via the lookup method. The VSO will call discard if a stronger
-/// definition is added or already present.
-class MaterializationUnit {
-public:
-  virtual ~MaterializationUnit() {}
-
-  /// Return the set of symbols that this source provides.
-  virtual SymbolFlagsMap getSymbols() = 0;
-
-  /// Implementations of this method should materialize all symbols
-  ///        in the materialzation unit, except for those that have been
-  ///        previously discarded.
-  virtual void materialize(MaterializationResponsibility R) = 0;
-
-  /// Implementations of this method should discard the given symbol
-  ///        from the source (e.g. if the source is an LLVM IR Module and the
-  ///        symbol is a function, delete the function body or mark it available
-  ///        externally).
-  virtual void discard(const VSO &V, SymbolStringPtr Name) = 0;
-
-private:
-  virtual void anchor();
-};
-
-/// Represents a dynamic linkage unit in a JIT process.
+/// A symbol table that supports asynchoronous symbol queries.
 ///
-/// VSO acts as a symbol table (symbol definitions can be set and the dylib
-/// queried to find symbol addresses) and as a key for tracking resources
-/// (since a VSO's address is fixed).
+/// Represents a virtual shared object. Instances can not be copied or moved, so
+/// their addresses may be used as keys for resource management.
+/// VSO state changes must be made via an ExecutionSession to guarantee that
+/// they are synchronized with respect to other VSO operations.
 class VSO {
+  friend class AsynchronousSymbolQuery;
   friend class ExecutionSession;
-  friend class MaterializationResponsibility;
-
 public:
-  enum RelativeLinkageStrength {
-    NewDefinitionIsStronger,
-    DuplicateDefinition,
-    ExistingDefinitionIsStronger
-  };
+  using AsynchronousSymbolQuerySet =
+      std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
 
-  using SetDefinitionsResult =
-      std::map<SymbolStringPtr, RelativeLinkageStrength>;
+  using MaterializationUnitList =
+      std::vector<std::unique_ptr<MaterializationUnit>>;
 
-  struct Materializer {
-  public:
-    Materializer(std::unique_ptr<MaterializationUnit> MU,
-                 MaterializationResponsibility R);
-    void operator()();
-
-  private:
-    std::unique_ptr<MaterializationUnit> MU;
-    MaterializationResponsibility R;
-  };
-
-  using MaterializerList = std::vector<Materializer>;
-
-  struct LookupResult {
-    MaterializerList Materializers;
-    SymbolNameSet UnresolvedSymbols;
-  };
-
-  VSO() = default;
+  using VSOList = std::vector<VSO *>;
 
   VSO(const VSO &) = delete;
   VSO &operator=(const VSO &) = delete;
   VSO(VSO &&) = delete;
   VSO &operator=(VSO &&) = delete;
 
-  /// Compare new linkage with existing linkage.
-  static RelativeLinkageStrength
-  compareLinkage(Optional<JITSymbolFlags> OldFlags, JITSymbolFlags NewFlags);
+  /// Get the name for this VSO.
+  const std::string &getName() const { return VSOName; }
 
-  /// Compare new linkage with an existing symbol's linkage.
-  RelativeLinkageStrength compareLinkage(SymbolStringPtr Name,
-                                         JITSymbolFlags NewFlags) const;
+  /// Get a reference to the ExecutionSession for this VSO.
+  ExecutionSessionBase &getExecutionSession() const { return ES; }
 
-  /// Adds the given symbols to the mapping as resolved, finalized
-  ///        symbols.
-  ///
-  /// FIXME: We can take this by const-ref once symbol-based laziness is
-  ///        removed.
-  Error define(SymbolMap NewSymbols);
+  /// Define all symbols provided by the materialization unit to be part
+  ///        of the given VSO.
+  template <typename UniquePtrToMaterializationUnit>
+  typename std::enable_if<
+      std::is_convertible<
+          typename std::decay<UniquePtrToMaterializationUnit>::type,
+          std::unique_ptr<MaterializationUnit>>::value,
+      Error>::type
+  define(UniquePtrToMaterializationUnit &&MU) {
+    return ES.runSessionLocked([&, this]() -> Error {
+      assert(MU && "Can't define with a null MU");
+
+      if (auto Err = defineImpl(*MU))
+        return Err;
+
+      /// defineImpl succeeded.
+      auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
+      for (auto &KV : UMI->MU->getSymbols())
+        UnmaterializedInfos[KV.first] = UMI;
 
-  /// Adds the given symbols to the mapping as lazy symbols.
-  Error defineLazy(std::unique_ptr<MaterializationUnit> Source);
+      return Error::success();
+    });
+  }
 
-  /// Look up the flags for the given symbols.
-  ///
-  /// Returns the flags for the give symbols, together with the set of symbols
-  /// not found.
-  SymbolNameSet lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Symbols);
+  /// Define a set of symbols already in the materializing state.
+  Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
 
-  /// Apply the given query to the given symbols in this VSO.
-  ///
-  /// For symbols in this VSO that have already been materialized, their address
-  /// will be set in the query immediately.
+  /// Replace the definition of a set of materializing symbols with a new
+  /// MaterializationUnit.
   ///
-  /// For symbols in this VSO that have not been materialized, the query will be
-  /// recorded and the source for those symbols (plus the set of symbols to be
-  /// materialized by that source) will be returned as the MaterializationWork
-  /// field of the LookupResult.
-  ///
-  /// Any symbols not found in this VSO will be returned in the
-  /// UnresolvedSymbols field of the LookupResult.
-  LookupResult lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
-                      SymbolNameSet Symbols);
-
-private:
-  /// Add the given symbol/address mappings to the dylib, but do not
-  ///        mark the symbols as finalized yet.
-  void resolve(const SymbolMap &SymbolValues);
+  /// All symbols being replaced must be in the materializing state. If any
+  /// symbol being replaced has pending queries then the MU will be returned
+  /// for materialization. Otherwise it will be stored in the VSO and all
+  /// symbols covered by MU moved back to the lazy state.
+  void replace(std::unique_ptr<MaterializationUnit> MU);
+
+  /// Record dependencies between symbols in this VSO and symbols in
+  ///        other VSOs.
+  void addDependencies(const SymbolFlagsMap &Dependents,
+                       const SymbolDependenceMap &Dependencies);
+
+  /// Resolve the given symbols.
+  ///
+  /// Returns the list of queries that become fully resolved as a consequence of
+  /// this operation.
+  void resolve(const SymbolMap &Resolved);
 
   /// Finalize the given symbols.
-  void finalize(const SymbolNameSet &SymbolsToFinalize);
+  ///
+  /// Returns the list of queries that become fully ready as a consequence of
+  /// this operation.
+  void finalize(const SymbolFlagsMap &Finalized);
+
+  /// Fail to materialize the given symbols.
+  ///
+  /// Returns the list of queries that fail as a consequence.
+  void notifyFailed(const SymbolFlagsMap &Failed,
+                    std::function<Error()> GenerateError);
+
+  /// Search the given VSO for the symbols in Symbols. If found, store
+  ///        the flags for each symbol in Flags. Returns any unresolved symbols.
+  SymbolNameSet lookupFlags(SymbolFlagsMap &Flags, const SymbolNameSet &Names);
+
+  /// Search the given VSOs in order for the symbols in Symbols. Results
+  ///        (once they become available) will be returned via the given Query.
+  ///
+  /// If any symbol is not found then the unresolved symbols will be returned,
+  /// and the query will not be applied. The Query is not failed and can be
+  /// re-used in a subsequent lookup once the symbols have been added, or
+  /// manually failed.
+  SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
+                       SymbolNameSet Names);
 
-  /// Notify the VSO that the given symbols failed to materialized.
-  void notifyMaterializationFailed(const SymbolNameSet &Names);
+  /// Dump current VSO state to OS.
+  void dump(raw_ostream &OS);
 
-  class UnmaterializedInfo {
-  public:
-    UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU);
-    void discard(VSO &V, SymbolStringPtr Name);
+private:
+  using AsynchronousSymbolQueryList =
+      std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
+
+  struct UnmaterializedInfo {
+    UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
+        : MU(std::move(MU)) {}
 
     std::unique_ptr<MaterializationUnit> MU;
-    SymbolFlagsMap Symbols;
   };
 
-  using UnmaterializedInfoList = std::list<UnmaterializedInfo>;
-
-  using UnmaterializedInfoIterator = UnmaterializedInfoList::iterator;
+  using UnmaterializedInfosMap =
+      std::map<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
 
-  class MaterializingInfo {
-  public:
-    using QueryList = std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
-
-    QueryList PendingResolution;
-    QueryList PendingFinalization;
+  struct MaterializingInfo {
+    AsynchronousSymbolQueryList PendingQueries;
+    SymbolDependenceMap Dependants;
+    SymbolDependenceMap UnfinalizedDependencies;
+    bool IsFinalized = false;
   };
 
-  using MaterializingInfoMap = std::map<SymbolStringPtr, MaterializingInfo>;
+  using MaterializingInfosMap = std::map<SymbolStringPtr, MaterializingInfo>;
 
-  using MaterializingInfoIterator = MaterializingInfoMap::iterator;
+  VSO(ExecutionSessionBase &ES, std::string Name)
+      : ES(ES), VSOName(std::move(Name)) {}
 
-  class SymbolTableEntry {
-  public:
-    SymbolTableEntry(JITSymbolFlags SymbolFlags,
-                     UnmaterializedInfoIterator UnmaterializedInfoItr);
-    SymbolTableEntry(JITSymbolFlags SymbolFlags);
-    SymbolTableEntry(JITEvaluatedSymbol Sym);
-    SymbolTableEntry(SymbolTableEntry &&Other);
-    SymbolTableEntry &operator=(SymbolTableEntry &&Other);
-    ~SymbolTableEntry();
-
-    // Change definition due to override. Only usable prior to materialization.
-    void replaceWith(VSO &V, SymbolStringPtr Name, JITEvaluatedSymbol Sym);
-
-    // Change definition due to override. Only usable prior to materialization.
-    void replaceWith(VSO &V, SymbolStringPtr Name, JITSymbolFlags Flags,
-                     UnmaterializedInfoIterator NewUMII);
-
-    // Abandon old definition and move to materializing state.
-    // There is no need to call notifyMaterializing after this.
-    void replaceMaterializing(VSO &V, SymbolStringPtr Name,
-                              JITSymbolFlags NewFlags);
-
-    // Notify this entry that it is being materialized.
-    void notifyMaterializing();
-
-    // Move entry to resolved state.
-    void resolve(VSO &V, JITEvaluatedSymbol Sym);
-
-    // Move entry to finalized state.
-    void finalize();
-
-    JITSymbolFlags Flags;
-
-    union {
-      JITTargetAddress Address;
-      UnmaterializedInfoIterator UMII;
-    };
+  ExecutionSessionBase &ES;
+  std::string VSOName;
+  SymbolMap Symbols;
+  UnmaterializedInfosMap UnmaterializedInfos;
+  MaterializingInfosMap MaterializingInfos;
 
-  private:
-    void destroy();
-  };
+  Error defineImpl(MaterializationUnit &MU);
 
-  std::map<SymbolStringPtr, SymbolTableEntry> Symbols;
-  UnmaterializedInfoList UnmaterializedInfos;
-  MaterializingInfoMap MaterializingInfos;
+  void detachQueryHelper(AsynchronousSymbolQuery &Q,
+                         const SymbolNameSet &QuerySymbols);
+
+  void transferFinalizedNodeDependencies(MaterializingInfo &DependantMI,
+                                         const SymbolStringPtr &DependantName,
+                                         MaterializingInfo &FinalizedMI);
 };
 
 /// An ExecutionSession represents a running JIT program.
-class ExecutionSession {
+class ExecutionSession : public ExecutionSessionBase {
 public:
   using ErrorReporter = std::function<void(Error)>;
 
+  using DispatchMaterializationFunction =
+      std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> MU)>;
+
   /// Construct an ExecutionEngine.
   ///
   /// SymbolStringPools may be shared between ExecutionSessions.
   ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr)
-    : SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {}
-
-  /// Returns the SymbolStringPool for this ExecutionSession.
-  SymbolStringPool &getSymbolStringPool() const { return *SSP; }
-
-  /// Set the error reporter function.
-  void setErrorReporter(ErrorReporter ReportError) {
-    this->ReportError = std::move(ReportError);
-  }
-
-  /// Report a error for this execution session.
-  ///
-  /// Unhandled errors can be sent here to log them.
-  void reportError(Error Err) { ReportError(std::move(Err)); }
-
-  /// Allocate a module key for a new module to add to the JIT.
-  VModuleKey allocateVModule() { return ++LastKey; }
+      : ExecutionSessionBase(std::move(SSP)) {}
 
-  /// Return a module key to the ExecutionSession so that it can be
-  ///        re-used. This should only be done once all resources associated
-  ////       with the original key have been released.
-  void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ }
-
-public:
-  static void logErrorsToStdErr(Error Err);
+  /// Add a new VSO to this ExecutionSession.
+  VSO &createVSO(std::string Name);
 
-  std::shared_ptr<SymbolStringPool> SSP;
-  VModuleKey LastKey = 0;
-  ErrorReporter ReportError = logErrorsToStdErr;
-};
-
-/// Runs Materializers on the current thread and reports errors to the given
-/// ExecutionSession.
-class MaterializeOnCurrentThread {
-public:
-  void operator()(VSO::Materializer M) { M(); }
+private:
+  std::vector<std::unique_ptr<VSO>> VSOs;
 };
 
-/// Materialization function object wrapper for the lookup method.
-using MaterializationDispatcher = std::function<void(VSO::Materializer M)>;
-
-/// Look up a set of symbols by searching a list of VSOs.
+/// Look up the given names in the given VSOs.
+/// VSOs will be searched in order and no VSO pointer may be null.
+/// All symbols must be found within the given VSOs or an error
+/// will be returned.
 ///
-/// All VSOs in the list should be non-null.
+/// If this lookup is being performed on behalf of a
+/// MaterializationResponsibility then it must be passed in as R
+/// (in order to record the symbol dependencies).
+/// If this lookup is not being performed on behalf of a
+/// MaterializationResponsibility then R should be left null.
 Expected<SymbolMap> lookup(const std::vector<VSO *> &VSOs, SymbolNameSet Names,
-                           MaterializationDispatcher DispatchMaterialization);
+                           MaterializationResponsibility *R);
 
 /// Look up a symbol by searching a list of VSOs.
-Expected<JITEvaluatedSymbol>
-lookup(const std::vector<VSO *> VSOs, SymbolStringPtr Name,
-       MaterializationDispatcher DispatchMaterialization);
+Expected<JITEvaluatedSymbol> lookup(const std::vector<VSO *> VSOs,
+                                    SymbolStringPtr Name,
+                                    MaterializationResponsibility *R);
 
 } // End namespace orc
 } // End namespace llvm

Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/Legacy.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/Legacy.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/Legacy.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/Legacy.h Wed May 16 15:24:30 2018
@@ -22,7 +22,8 @@ namespace orc {
 
 class JITSymbolResolverAdapter : public JITSymbolResolver {
 public:
-  JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R);
+  JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R,
+                           MaterializationResponsibility *MR);
   Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) override;
   Expected<LookupResult> lookup(const LookupSet &Symbols) override;
 
@@ -30,6 +31,7 @@ private:
   ExecutionSession &ES;
   std::set<SymbolStringPtr> ResolvedStrings;
   SymbolResolver &R;
+  MaterializationResponsibility *MR;
 };
 
 /// Use the given legacy-style FindSymbol function (i.e. a function that
@@ -68,27 +70,35 @@ Expected<SymbolNameSet> lookupFlagsWithL
 ///
 /// Useful for implementing lookup bodies that query legacy resolvers.
 template <typename FindSymbolFn>
-SymbolNameSet lookupWithLegacyFn(AsynchronousSymbolQuery &Query,
-                                 const SymbolNameSet &Symbols,
-                                 FindSymbolFn FindSymbol) {
+SymbolNameSet
+lookupWithLegacyFn(ExecutionSession &ES, AsynchronousSymbolQuery &Query,
+                   const SymbolNameSet &Symbols, FindSymbolFn FindSymbol) {
   SymbolNameSet SymbolsNotFound;
+  bool NewSymbolsResolved = false;
 
   for (auto &S : Symbols) {
     if (JITSymbol Sym = FindSymbol(*S)) {
       if (auto Addr = Sym.getAddress()) {
         Query.resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
-        Query.finalizeSymbol();
+        Query.notifySymbolReady();
+        NewSymbolsResolved = true;
       } else {
-        Query.notifyMaterializationFailed(Addr.takeError());
+        ES.failQuery(Query, Addr.takeError());
         return SymbolNameSet();
       }
     } else if (auto Err = Sym.takeError()) {
-      Query.notifyMaterializationFailed(std::move(Err));
+      ES.failQuery(Query, std::move(Err));
       return SymbolNameSet();
     } else
       SymbolsNotFound.insert(S);
   }
 
+  if (NewSymbolsResolved && Query.isFullyResolved())
+    Query.handleFullyResolved();
+
+  if (NewSymbolsResolved && Query.isFullyReady())
+    Query.handleFullyReady();
+
   return SymbolsNotFound;
 }
 
@@ -99,8 +109,9 @@ class LegacyLookupFnResolver final : pub
 public:
   using ErrorReporter = std::function<void(Error)>;
 
-  LegacyLookupFnResolver(LegacyLookupFn LegacyLookup, ErrorReporter ReportError)
-      : LegacyLookup(std::move(LegacyLookup)),
+  LegacyLookupFnResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup,
+                         ErrorReporter ReportError)
+      : ES(ES), LegacyLookup(std::move(LegacyLookup)),
         ReportError(std::move(ReportError)) {}
 
   SymbolNameSet lookupFlags(SymbolFlagsMap &Flags,
@@ -116,20 +127,21 @@ public:
 
   SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
                        SymbolNameSet Symbols) final {
-    return lookupWithLegacyFn(*Query, Symbols, LegacyLookup);
+    return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
   }
 
 private:
+  ExecutionSession &ES;
   LegacyLookupFn LegacyLookup;
   ErrorReporter ReportError;
 };
 
 template <typename LegacyLookupFn>
 std::shared_ptr<LegacyLookupFnResolver<LegacyLookupFn>>
-createLegacyLookupResolver(LegacyLookupFn LegacyLookup,
+createLegacyLookupResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup,
                            std::function<void(Error)> ErrorReporter) {
   return std::make_shared<LegacyLookupFnResolver<LegacyLookupFn>>(
-      std::move(LegacyLookup), std::move(ErrorReporter));
+      ES, std::move(LegacyLookup), std::move(ErrorReporter));
 }
 
 } // End namespace orc

Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h Wed May 16 15:24:30 2018
@@ -124,7 +124,8 @@ private:
     Error finalize() override {
       assert(PFC && "mapSectionAddress called on finalized LinkedObject");
 
-      JITSymbolResolverAdapter ResolverAdapter(PFC->Parent.ES, *PFC->Resolver);
+      JITSymbolResolverAdapter ResolverAdapter(PFC->Parent.ES, *PFC->Resolver,
+                                               nullptr);
       PFC->RTDyld = llvm::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
       PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
 

Modified: llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp Wed May 16 15:24:30 2018
@@ -76,7 +76,7 @@ raw_ostream &operator<<(raw_ostream &OS,
 
 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {
   OS << "{";
-  if (SymbolFlags.empty()) {
+  if (!SymbolFlags.empty()) {
     OS << " {\"" << *SymbolFlags.begin()->first
        << "\": " << SymbolFlags.begin()->second << "}";
     for (auto &KV :
@@ -87,6 +87,18 @@ raw_ostream &operator<<(raw_ostream &OS,
   return OS;
 }
 
+raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) {
+  OS << "{";
+  if (!Deps.empty()) {
+    OS << " { " << Deps.begin()->first->getName() << ": "
+       << Deps.begin()->second << " }";
+    for (auto &KV : make_range(std::next(Deps.begin()), Deps.end()))
+      OS << ", { " << KV.first->getName() << ": " << KV.second << " }";
+  }
+  OS << " }";
+  return OS;
+}
+
 FailedToResolve::FailedToResolve(SymbolNameSet Symbols)
     : Symbols(std::move(Symbols)) {
   assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
@@ -113,57 +125,101 @@ void FailedToFinalize::log(raw_ostream &
   OS << "Failed to finalize symbols: " << Symbols;
 }
 
+void ExecutionSessionBase::failQuery(AsynchronousSymbolQuery &Q, Error Err) {
+  runSessionLocked([&]() -> void {
+    Q.detach();
+    Q.handleFailed(std::move(Err));
+  });
+}
+
 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
     const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
     SymbolsReadyCallback NotifySymbolsReady)
     : NotifySymbolsResolved(std::move(NotifySymbolsResolved)),
       NotifySymbolsReady(std::move(NotifySymbolsReady)) {
-  assert(this->NotifySymbolsResolved &&
-         "Symbols resolved callback must be set");
-  assert(this->NotifySymbolsReady && "Symbols ready callback must be set");
-  OutstandingResolutions = OutstandingFinalizations = Symbols.size();
+  NotYetResolvedCount = NotYetReadyCount = Symbols.size();
+
+  for (auto &S : Symbols)
+    ResolvedSymbols[S] = nullptr;
 }
 
-void AsynchronousSymbolQuery::notifyMaterializationFailed(Error Err) {
-  if (OutstandingResolutions != 0)
+void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name,
+                                      JITEvaluatedSymbol Sym) {
+  auto I = ResolvedSymbols.find(Name);
+  assert(I != ResolvedSymbols.end() &&
+         "Resolving symbol outside the requested set");
+  assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name");
+  I->second = std::move(Sym);
+  --NotYetResolvedCount;
+}
+
+void AsynchronousSymbolQuery::handleFullyResolved() {
+  assert(NotYetResolvedCount == 0 && "Not fully resolved?");
+  assert(NotifySymbolsResolved &&
+         "NotifySymbolsResolved already called or error occurred");
+  NotifySymbolsResolved(
+      ResolutionResult(std::move(ResolvedSymbols), QueryRegistrations));
+  NotifySymbolsResolved = SymbolsResolvedCallback();
+}
+
+void AsynchronousSymbolQuery::notifySymbolReady() {
+  assert(NotYetReadyCount != 0 && "All symbols already finalized");
+  --NotYetReadyCount;
+}
+
+void AsynchronousSymbolQuery::handleFullyReady() {
+  assert(QueryRegistrations.empty() &&
+         "Query is still registered with some symbols");
+  assert(!NotifySymbolsResolved && "Resolution not applied yet");
+  NotifySymbolsReady(Error::success());
+  NotifySymbolsReady = SymbolsReadyCallback();
+}
+
+void AsynchronousSymbolQuery::handleFailed(Error Err) {
+  assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&
+         NotYetResolvedCount == 0 && NotYetReadyCount == 0 &&
+         "Query should already have been abandoned");
+  if (NotifySymbolsResolved)
     NotifySymbolsResolved(std::move(Err));
-  else if (OutstandingFinalizations != 0)
+  else {
+    assert(NotifySymbolsReady && "Failed after both callbacks issued?");
     NotifySymbolsReady(std::move(Err));
-  else
-    consumeError(std::move(Err));
-  OutstandingResolutions = OutstandingFinalizations = 0;
+    NotifySymbolsReady = SymbolsReadyCallback();
+  }
 }
 
-void AsynchronousSymbolQuery::resolve(SymbolStringPtr Name,
-                                      JITEvaluatedSymbol Sym) {
-  // If OutstandingResolutions is zero we must have errored out already. Just
-  // ignore this.
-  if (OutstandingResolutions == 0)
-    return;
-
-  assert(!Symbols.count(Name) && "Symbol has already been assigned an address");
-  Symbols.insert(std::make_pair(std::move(Name), std::move(Sym)));
-  --OutstandingResolutions;
-  if (OutstandingResolutions == 0)
-    NotifySymbolsResolved(std::move(Symbols));
-}
-
-void AsynchronousSymbolQuery::finalizeSymbol() {
-  // If OutstandingFinalizations is zero we must have errored out already. Just
-  // ignore this.
-  if (OutstandingFinalizations == 0)
-    return;
-
-  assert(OutstandingFinalizations > 0 && "All symbols already finalized");
-  --OutstandingFinalizations;
-  if (OutstandingFinalizations == 0)
-    NotifySymbolsReady(Error::success());
+void AsynchronousSymbolQuery::addQueryDependence(VSO &V, SymbolStringPtr Name) {
+  bool Added = QueryRegistrations[&V].insert(std::move(Name)).second;
+  (void)Added;
+  assert(Added && "Duplicate dependence notification?");
+}
+
+void AsynchronousSymbolQuery::removeQueryDependence(
+    VSO &V, const SymbolStringPtr &Name) {
+  auto QRI = QueryRegistrations.find(&V);
+  assert(QRI != QueryRegistrations.end() && "No dependencies registered for V");
+  assert(QRI->second.count(Name) && "No dependency on Name in V");
+  QRI->second.erase(Name);
+  if (QRI->second.empty())
+    QueryRegistrations.erase(QRI);
+}
+
+void AsynchronousSymbolQuery::detach() {
+  ResolvedSymbols.clear();
+  NotYetResolvedCount = 0;
+  NotYetReadyCount = 0;
+  for (auto &KV : QueryRegistrations)
+    KV.first->detachQueryHelper(*this, KV.second);
+  QueryRegistrations.clear();
 }
 
 MaterializationResponsibility::MaterializationResponsibility(
     VSO &V, SymbolFlagsMap SymbolFlags)
     : V(V), SymbolFlags(std::move(SymbolFlags)) {
   assert(!this->SymbolFlags.empty() && "Materializing nothing?");
+
+  for (auto &KV : this->SymbolFlags)
+    KV.second |= JITSymbolFlags::Materializing;
 }
 
 MaterializationResponsibility::~MaterializationResponsibility() {
@@ -172,441 +228,634 @@ MaterializationResponsibility::~Material
 }
 
 void MaterializationResponsibility::resolve(const SymbolMap &Symbols) {
-#ifndef NDEBUG
   for (auto &KV : Symbols) {
     auto I = SymbolFlags.find(KV.first);
     assert(I != SymbolFlags.end() &&
            "Resolving symbol outside this responsibility set");
+    assert(I->second.isMaterializing() && "Duplicate resolution");
+    I->second &= ~JITSymbolFlags::Materializing;
     assert(KV.second.getFlags() == I->second &&
            "Resolving symbol with incorrect flags");
   }
-#endif
+
   V.resolve(Symbols);
 }
 
 void MaterializationResponsibility::finalize() {
-  SymbolNameSet SymbolNames;
+#ifndef NDEBUG
   for (auto &KV : SymbolFlags)
-    SymbolNames.insert(KV.first);
+    assert(!KV.second.isMaterializing() &&
+           "Failed to resolve symbol before finalization");
+#endif // NDEBUG
+
+  V.finalize(SymbolFlags);
   SymbolFlags.clear();
-  V.finalize(SymbolNames);
 }
 
-void MaterializationResponsibility::notifyMaterializationFailed() {
-  SymbolNameSet SymbolNames;
-  for (auto &KV : SymbolFlags)
-    SymbolNames.insert(KV.first);
+Error MaterializationResponsibility::defineMaterializing(
+    const SymbolFlagsMap &NewSymbolFlags) {
+  // Add the given symbols to this responsibility object.
+  // It's ok if we hit a duplicate here: In that case the new version will be
+  // discarded, and the VSO::defineMaterializing method will return a duplicate
+  // symbol error.
+  for (auto &KV : NewSymbolFlags) {
+    auto I = SymbolFlags.insert(KV).first;
+    I->second |= JITSymbolFlags::Materializing;
+  }
+
+  return V.defineMaterializing(NewSymbolFlags);
+}
+
+void MaterializationResponsibility::failMaterialization(
+    std::function<Error()> GenerateError) {
+  V.notifyFailed(SymbolFlags, std::move(GenerateError));
   SymbolFlags.clear();
-  V.notifyMaterializationFailed(SymbolNames);
 }
 
-MaterializationResponsibility
-MaterializationResponsibility::delegate(SymbolNameSet Symbols) {
-  SymbolFlagsMap ExtractedFlags;
+void MaterializationResponsibility::delegate(
+    std::unique_ptr<MaterializationUnit> MU) {
+  for (auto &KV : MU->getSymbols())
+    SymbolFlags.erase(KV.first);
 
-  for (auto &S : Symbols) {
-    auto I = SymbolFlags.find(S);
-    ExtractedFlags.insert(*I);
-    SymbolFlags.erase(I);
-  }
-
-  return MaterializationResponsibility(V, std::move(ExtractedFlags));
+  V.replace(std::move(MU));
 }
 
-VSO::Materializer::Materializer(std::unique_ptr<MaterializationUnit> MU,
-                                MaterializationResponsibility R)
-    : MU(std::move(MU)), R(std::move(R)) {}
-
-void VSO::Materializer::operator()() { MU->materialize(std::move(R)); }
+void MaterializationResponsibility::addDependencies(
+    const SymbolDependenceMap &Dependencies) {
+  V.addDependencies(SymbolFlags, Dependencies);
+}
 
-VSO::UnmaterializedInfo::UnmaterializedInfo(
-    std::unique_ptr<MaterializationUnit> MU)
-    : MU(std::move(MU)), Symbols(this->MU->getSymbols()) {}
+AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
+    SymbolMap Symbols)
+    : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {}
 
-void VSO::UnmaterializedInfo::discard(VSO &V, SymbolStringPtr Name) {
-  assert(MU && "No materializer attached");
-  MU->discard(V, Name);
-  auto I = Symbols.find(Name);
-  assert(I != Symbols.end() && "Symbol not found in this MU");
-  Symbols.erase(I);
+void AbsoluteSymbolsMaterializationUnit::materialize(
+    MaterializationResponsibility R) {
+  R.resolve(Symbols);
+  R.finalize();
 }
 
-VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags,
-                                        UnmaterializedInfoIterator UMII)
-    : Flags(Flags), UMII(std::move(UMII)) {
-  // We *don't* expect isLazy to be set here. That's for the VSO to do.
-  assert(!Flags.isLazy() && "Initial flags include lazy?");
-  assert(!Flags.isMaterializing() && "Initial flags include materializing");
-  this->Flags |= JITSymbolFlags::Lazy;
+void AbsoluteSymbolsMaterializationUnit::discard(const VSO &V,
+                                                 SymbolStringPtr Name) {
+  assert(Symbols.count(Name) && "Symbol is not part of this MU");
+  Symbols.erase(Name);
 }
 
-VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags)
-    : Flags(Flags), Address(0) {
-  // We *don't* expect isMaterializing to be set here. That's for the VSO to do.
-  assert(!Flags.isLazy() && "Initial flags include lazy?");
-  assert(!Flags.isMaterializing() && "Initial flags include materializing");
-  this->Flags |= JITSymbolFlags::Materializing;
+SymbolFlagsMap
+AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) {
+  SymbolFlagsMap Flags;
+  for (const auto &KV : Symbols)
+    Flags[KV.first] = KV.second.getFlags();
+  return Flags;
 }
 
-VSO::SymbolTableEntry::SymbolTableEntry(JITEvaluatedSymbol Sym)
-    : Flags(Sym.getFlags()), Address(Sym.getAddress()) {
-  assert(!Flags.isLazy() && !Flags.isMaterializing() &&
-         "This constructor is for final symbols only");
-}
+Error VSO::defineMaterializing(const SymbolFlagsMap &SymbolFlags) {
+  return ES.runSessionLocked([&]() -> Error {
+    std::vector<SymbolMap::iterator> AddedSyms;
 
-VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other)
-    : Flags(Other.Flags), Address(0) {
-  if (this->Flags.isLazy())
-    UMII = std::move(Other.UMII);
-  else
-    Address = Other.Address;
-}
+    for (auto &KV : SymbolFlags) {
+      SymbolMap::iterator EntryItr;
+      bool Added;
 
-VSO::SymbolTableEntry &VSO::SymbolTableEntry::
-operator=(SymbolTableEntry &&Other) {
-  destroy();
-  Flags = std::move(Other.Flags);
-  if (Other.Flags.isLazy()) {
-    UMII = std::move(Other.UMII);
-  } else
-    Address = Other.Address;
-  return *this;
-}
+      auto NewFlags = KV.second;
+      NewFlags |= JITSymbolFlags::Materializing;
 
-VSO::SymbolTableEntry::~SymbolTableEntry() { destroy(); }
+      std::tie(EntryItr, Added) = Symbols.insert(
+          std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
 
-void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name,
-                                        JITEvaluatedSymbol Sym) {
-  assert(!Flags.isMaterializing() &&
-         "Attempting to replace definition during materialization?");
-  if (Flags.isLazy()) {
-    UMII->discard(V, Name);
-    if (UMII->Symbols.empty())
-      V.UnmaterializedInfos.erase(UMII);
-  }
-  destroy();
-  Flags = Sym.getFlags();
-  Address = Sym.getAddress();
-}
+      if (Added)
+        AddedSyms.push_back(EntryItr);
+      else {
+        // Remove any symbols already added.
+        for (auto &SI : AddedSyms)
+          Symbols.erase(SI);
 
-void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name,
-                                        JITSymbolFlags NewFlags,
-                                        UnmaterializedInfoIterator NewUMII) {
-  assert(!Flags.isMaterializing() &&
-         "Attempting to replace definition during materialization?");
-  if (Flags.isLazy()) {
-    UMII->discard(V, Name);
-    if (UMII->Symbols.empty())
-      V.UnmaterializedInfos.erase(UMII);
-  }
-  destroy();
-  Flags = NewFlags;
-  UMII = std::move(NewUMII);
-}
+        // FIXME: Return all duplicates.
+        return make_error<DuplicateDefinition>(*KV.first);
+      }
+    }
 
-void VSO::SymbolTableEntry::replaceMaterializing(VSO &V, SymbolStringPtr Name,
-                                                 JITSymbolFlags NewFlags) {
-  assert(!NewFlags.isWeak() &&
-         "Can't define a lazy symbol in materializing mode");
-  assert(!NewFlags.isLazy() && !NewFlags.isMaterializing() &&
-         "Flags should not be in lazy or materializing state");
-  if (Flags.isLazy()) {
-    UMII->discard(V, Name);
-    if (UMII->Symbols.empty())
-      V.UnmaterializedInfos.erase(UMII);
-  }
-  destroy();
-  Flags = NewFlags;
-  Flags |= JITSymbolFlags::Materializing;
-  Address = 0;
+    return Error::success();
+  });
 }
 
-void VSO::SymbolTableEntry::notifyMaterializing() {
-  assert(Flags.isLazy() && "Can only start materializing from lazy state");
-  UMII.~UnmaterializedInfoIterator();
-  Flags &= ~JITSymbolFlags::Lazy;
-  Flags |= JITSymbolFlags::Materializing;
-  Address = 0;
-}
+void VSO::replace(std::unique_ptr<MaterializationUnit> MU) {
+  assert(MU != nullptr && "Can not replace with a null MaterializationUnit");
 
-void VSO::SymbolTableEntry::resolve(VSO &V, JITEvaluatedSymbol Sym) {
-  assert(!Flags.isLazy() && Flags.isMaterializing() &&
-         "Can only resolve in materializing state");
-  Flags = Sym.getFlags();
-  Flags |= JITSymbolFlags::Materializing;
-  Address = Sym.getAddress();
-  assert(Address != 0 && "Can not resolve to null");
-}
+  auto MustRunMU =
+      ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> {
 
-void VSO::SymbolTableEntry::finalize() {
-  assert(Address != 0 && "Cannot finalize with null address");
-  assert(Flags.isMaterializing() && !Flags.isLazy() &&
-         "Symbol should be in materializing state");
-  Flags &= ~JITSymbolFlags::Materializing;
+#ifndef NDEBUG
+        for (auto &KV : MU->getSymbols()) {
+          auto SymI = Symbols.find(KV.first);
+          assert(SymI != Symbols.end() && "Replacing unknown symbol");
+          assert(!SymI->second.getFlags().isLazy() &&
+                 SymI->second.getFlags().isMaterializing() &&
+                 "Can not replace symbol that is not materializing");
+          assert(UnmaterializedInfos.count(KV.first) == 0 &&
+                 "Symbol being replaced should have no UnmaterializedInfo");
+          assert(MaterializingInfos.count(KV.first) &&
+                 "Symbol being replaced should have a MaterializingInfo");
+        }
+#endif // NDEBUG
+
+        // If any symbol has pending queries against it then we need to
+        // materialize MU immediately.
+        for (auto &KV : MU->getSymbols())
+          if (!MaterializingInfos[KV.first].PendingQueries.empty())
+            return std::move(MU);
+
+        // Otherwise, make MU responsible for all the symbols.
+        auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
+        for (auto &KV : UMI->MU->getSymbols()) {
+          assert(!KV.second.isLazy() &&
+                 "Lazy flag should be managed internally.");
+          assert(!KV.second.isMaterializing() &&
+                 "Materializing flags should be managed internally.");
+
+          auto SymI = Symbols.find(KV.first);
+          SymI->second.getFlags() = KV.second;
+          SymI->second.getFlags() |= JITSymbolFlags::Lazy;
+          UnmaterializedInfos[KV.first] = UMI;
+        }
+
+        return nullptr;
+      });
+
+  if (MustRunMU)
+    ES.dispatchMaterialization(*this, std::move(MustRunMU));
+}
+
+void VSO::addDependencies(const SymbolFlagsMap &Dependants,
+                          const SymbolDependenceMap &Dependencies) {
+  ES.runSessionLocked([&, this]() {
+    for (auto &KV : Dependants) {
+      const auto &Name = KV.first;
+      assert(Symbols.count(Name) && "Name not in symbol table");
+      assert((Symbols[Name].getFlags().isLazy() ||
+              Symbols[Name].getFlags().isMaterializing()) &&
+             "Symbol is not lazy or materializing");
+
+      auto &MI = MaterializingInfos[Name];
+      assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol");
+
+      for (auto &KV : Dependencies) {
+        assert(KV.first && "Null VSO in dependency?");
+        auto &OtherVSO = *KV.first;
+        auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO];
+
+        for (auto &OtherSymbol : KV.second) {
+          auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol];
+
+          if (OtherMI.IsFinalized)
+            transferFinalizedNodeDependencies(MI, Name, OtherMI);
+          else {
+            OtherMI.Dependants[this].insert(Name);
+            DepsOnOtherVSO.insert(OtherSymbol);
+          }
+        }
+      }
+    }
+  });
 }
 
-void VSO::SymbolTableEntry::destroy() {
-  if (Flags.isLazy())
-    UMII.~UnmaterializedInfoIterator();
-}
+void VSO::resolve(const SymbolMap &Resolved) {
+  auto FullyResolvedQueries = ES.runSessionLocked([&, this]() {
+    AsynchronousSymbolQuerySet FullyResolvedQueries;
+    for (const auto &KV : Resolved) {
+      auto &Name = KV.first;
+      auto Sym = KV.second;
+
+      assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() &&
+             "Materializing flags should be managed internally");
+
+      auto I = Symbols.find(Name);
+
+      assert(I != Symbols.end() && "Symbol not found");
+      assert(!I->second.getFlags().isLazy() &&
+             I->second.getFlags().isMaterializing() &&
+             "Symbol should be materializing");
+      assert(I->second.getAddress() == 0 && "Symbol has already been resolved");
+
+      assert(Sym.getFlags() ==
+                 JITSymbolFlags::stripTransientFlags(I->second.getFlags()) &&
+             "Resolved flags should match the declared flags");
+
+      // Once resolved, symbols can never be weak.
+      Sym.getFlags() = static_cast<JITSymbolFlags::FlagNames>(
+          Sym.getFlags() & ~JITSymbolFlags::Weak);
+      I->second = Sym;
+
+      auto &MI = MaterializingInfos[Name];
+      for (auto &Q : MI.PendingQueries) {
+        Q->resolve(Name, Sym);
+        if (Q->isFullyResolved())
+          FullyResolvedQueries.insert(Q);
+      }
+    }
+
+    return FullyResolvedQueries;
+  });
+
+  for (auto &Q : FullyResolvedQueries) {
+    assert(Q->isFullyResolved() && "Q not fully resolved");
+    Q->handleFullyResolved();
+  }
+}
+
+void VSO::finalize(const SymbolFlagsMap &Finalized) {
+  auto FullyReadyQueries = ES.runSessionLocked([&, this]() {
+    AsynchronousSymbolQuerySet ReadyQueries;
+
+    for (const auto &KV : Finalized) {
+      const auto &Name = KV.first;
+
+      auto MII = MaterializingInfos.find(Name);
+      assert(MII != MaterializingInfos.end() &&
+             "Missing MaterializingInfo entry");
+
+      auto &MI = MII->second;
+
+      // For each dependant, transfer this node's unfinalized dependencies to
+      // it. If the dependant node is fully finalized then notify any pending
+      // queries.
+      for (auto &KV : MI.Dependants) {
+        auto &DependantVSO = *KV.first;
+        for (auto &DependantName : KV.second) {
+          auto DependantMII =
+              DependantVSO.MaterializingInfos.find(DependantName);
+          assert(DependantMII != DependantVSO.MaterializingInfos.end() &&
+                 "Dependant should have MaterializingInfo");
+
+          auto &DependantMI = DependantMII->second;
+
+          // Remove the dependant's dependency on this node.
+          assert(DependantMI.UnfinalizedDependencies[this].count(Name) &&
+                 "Dependant does not count this symbol as a dependency?");
+          DependantMI.UnfinalizedDependencies[this].erase(Name);
+          if (DependantMI.UnfinalizedDependencies[this].empty())
+            DependantMI.UnfinalizedDependencies.erase(this);
+
+          // Transfer unfinalized dependencies from this node to the dependant.
+          DependantVSO.transferFinalizedNodeDependencies(DependantMI,
+                                                         DependantName, MI);
+
+          // If the dependant is finalized and this node was the last of its
+          // unfinalized dependencies then notify any pending queries on the
+          // dependant node.
+          if (DependantMI.IsFinalized &&
+              DependantMI.UnfinalizedDependencies.empty()) {
+            assert(DependantMI.Dependants.empty() &&
+                   "Dependants should be empty by now");
+            for (auto &Q : DependantMI.PendingQueries) {
+              Q->notifySymbolReady();
+              if (Q->isFullyReady())
+                ReadyQueries.insert(Q);
+              Q->removeQueryDependence(DependantVSO, DependantName);
+            }
+
+            // If this dependant node was fully finalized we can erase its
+            // MaterializingInfo and update its materializing state.
+            assert(DependantVSO.Symbols.count(DependantName) &&
+                   "Dependant has no entry in the Symbols table");
+            DependantVSO.Symbols[DependantName].getFlags() &=
+                JITSymbolFlags::Materializing;
+            DependantVSO.MaterializingInfos.erase(DependantMII);
+          }
+        }
+      }
+      MI.Dependants.clear();
+      MI.IsFinalized = true;
 
-VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old,
-                                                 JITSymbolFlags New) {
-  if (Old == None)
-    return llvm::orc::VSO::NewDefinitionIsStronger;
+      if (MI.UnfinalizedDependencies.empty()) {
+        for (auto &Q : MI.PendingQueries) {
+          Q->notifySymbolReady();
+          if (Q->isFullyReady())
+            ReadyQueries.insert(Q);
+          Q->removeQueryDependence(*this, Name);
+        }
+        assert(Symbols.count(Name) &&
+               "Symbol has no entry in the Symbols table");
+        Symbols[Name].getFlags() &= ~JITSymbolFlags::Materializing;
+        MaterializingInfos.erase(MII);
+      }
+    }
 
-  if (Old->isStrong()) {
-    if (New.isStrong())
-      return llvm::orc::VSO::DuplicateDefinition;
-    else
-      return llvm::orc::VSO::ExistingDefinitionIsStronger;
-  } else {
-    if (New.isStrong())
-      return llvm::orc::VSO::NewDefinitionIsStronger;
-    else
-      return llvm::orc::VSO::ExistingDefinitionIsStronger;
+    return ReadyQueries;
+  });
+
+  for (auto &Q : FullyReadyQueries) {
+    assert(Q->isFullyReady() && "Q is not fully ready");
+    Q->handleFullyReady();
   }
 }
 
-VSO::RelativeLinkageStrength
-VSO::compareLinkage(SymbolStringPtr Name, JITSymbolFlags NewFlags) const {
-  auto I = Symbols.find(Name);
-  return compareLinkage(
-      I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags),
-      NewFlags);
-}
+void VSO::notifyFailed(const SymbolFlagsMap &Failed,
+                       std::function<Error()> GenerateError) {
+  auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() {
+    AsynchronousSymbolQuerySet FailedQueries;
+
+    for (auto &KV : Failed) {
+      const auto &Name = KV.first;
+
+      auto I = Symbols.find(Name);
+      assert(I != Symbols.end() && "Symbol not present in this VSO");
+      Symbols.erase(I);
+
+      auto MII = MaterializingInfos.find(Name);
+
+      // If we have not created a MaterializingInfo for this symbol yet then
+      // there is nobody to notify.
+      if (MII == MaterializingInfos.end())
+        continue;
+
+      // Copy all the queries to the FailedQueries list, then abandon them.
+      // This has to be a copy, and the copy has to come before the abandon
+      // operation: Each Q.detach() call will reach back into this
+      // PendingQueries list to remove Q.
+      for (auto &Q : MII->second.PendingQueries)
+        FailedQueries.insert(Q);
 
-Error VSO::define(SymbolMap NewSymbols) {
-  Error Err = Error::success();
-  for (auto &KV : NewSymbols) {
-    auto I = Symbols.find(KV.first);
-    auto LinkageResult = compareLinkage(
-        I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags),
-        KV.second.getFlags());
+      for (auto &Q : FailedQueries)
+        Q->detach();
 
-    // Silently discard weaker definitions.
-    if (LinkageResult == ExistingDefinitionIsStronger)
-      continue;
+      assert(MII->second.PendingQueries.empty() &&
+             "Queries remain after symbol was failed");
 
-    // Report duplicate definition errors.
-    if (LinkageResult == DuplicateDefinition) {
-      Err = joinErrors(std::move(Err),
-                       make_error<orc::DuplicateDefinition>(*KV.first));
-      continue;
+      MaterializingInfos.erase(MII);
     }
 
-    if (I != Symbols.end())
-      I->second.replaceWith(*this, I->first, KV.second);
-    else
-      Symbols.insert(std::make_pair(KV.first, std::move(KV.second)));
-  }
-  return Err;
+    return FailedQueries;
+  });
+
+  for (auto &Q : FailedQueriesToNotify)
+    Q->handleFailed(GenerateError());
 }
 
-Error VSO::defineLazy(std::unique_ptr<MaterializationUnit> MU) {
-  auto UMII = UnmaterializedInfos.insert(UnmaterializedInfos.end(),
-                                         UnmaterializedInfo(std::move(MU)));
+SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags,
+                               const SymbolNameSet &Names) {
+  return ES.runSessionLocked([&, this]() {
+    SymbolNameSet Unresolved;
 
-  Error Err = Error::success();
-  for (auto &KV : UMII->Symbols) {
-    auto I = Symbols.find(KV.first);
+    for (auto &Name : Names) {
+      auto I = Symbols.find(Name);
+      if (I == Symbols.end()) {
+        Unresolved.insert(Name);
+        continue;
+      }
 
-    assert((I == Symbols.end() ||
-            !I->second.Flags.isMaterializing()) &&
-               "Attempt to replace materializing symbol definition");
+      assert(!Flags.count(Name) && "Symbol already present in Flags map");
+      Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags());
+    }
 
-    auto LinkageResult = compareLinkage(
-        I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags),
-        KV.second);
+    return Unresolved;
+  });
+}
 
-    // Discard weaker definitions.
-    if (LinkageResult == ExistingDefinitionIsStronger) {
-      UMII->discard(*this, KV.first);
-      continue;
-    }
+SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
+                          SymbolNameSet Names) {
+  SymbolNameSet Unresolved = std::move(Names);
+  std::vector<std::unique_ptr<MaterializationUnit>> MUs;
+
+  ES.runSessionLocked([&, this]() {
+    for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) {
+      auto TmpI = I++;
+      auto Name = *TmpI;
+
+      // Search for the name in Symbols. Skip it if not found.
+      auto SymI = Symbols.find(Name);
+      if (SymI == Symbols.end())
+        continue;
+
+      // If we found Name in V, remove it frome the Unresolved set and add it
+      // to the dependencies set.
+      Unresolved.erase(TmpI);
+
+      // If the symbol has an address then resolve it.
+      if (SymI->second.getAddress() != 0)
+        Q->resolve(Name, SymI->second);
+
+      // If the symbol is lazy, get the MaterialiaztionUnit for it.
+      if (SymI->second.getFlags().isLazy()) {
+        assert(SymI->second.getAddress() == 0 &&
+               "Lazy symbol should not have a resolved address");
+        assert(!SymI->second.getFlags().isMaterializing() &&
+               "Materializing and lazy should not both be set");
+        auto UMII = UnmaterializedInfos.find(Name);
+        assert(UMII != UnmaterializedInfos.end() &&
+               "Lazy symbol should have UnmaterializedInfo");
+        auto MU = std::move(UMII->second->MU);
+        assert(MU != nullptr && "Materializer should not be null");
+
+        // Kick all symbols associated with this MaterializationUnit into
+        // materializing state.
+        for (auto &KV : MU->getSymbols()) {
+          auto SymK = Symbols.find(KV.first);
+          auto Flags = SymK->second.getFlags();
+          Flags &= ~JITSymbolFlags::Lazy;
+          Flags |= JITSymbolFlags::Materializing;
+          SymK->second.setFlags(Flags);
+          UnmaterializedInfos.erase(KV.first);
+        }
+
+        // Add MU to the list of MaterializationUnits to be materialized.
+        MUs.push_back(std::move(MU));
+      } else if (!SymI->second.getFlags().isMaterializing()) {
+        // The symbol is neither lazy nor materializing. Finalize it and
+        // continue.
+        Q->notifySymbolReady();
+        continue;
+      }
 
-    // Report duplicate definition errors.
-    if (LinkageResult == DuplicateDefinition) {
-      Err = joinErrors(std::move(Err),
-                       make_error<orc::DuplicateDefinition>(*KV.first));
-      // Duplicate definitions are discarded, so remove the duplicates from
-      // materializer.
-      UMII->discard(*this, KV.first);
-      continue;
+      // Add the query to the PendingQueries list.
+      assert(SymI->second.getFlags().isMaterializing() &&
+             "By this line the symbol should be materializing");
+      auto &MI = MaterializingInfos[Name];
+      MI.PendingQueries.push_back(Q);
+      Q->addQueryDependence(*this, Name);
     }
+  });
 
-    // Existing definition was weaker. Replace it.
-    if (I != Symbols.end())
-      I->second.replaceWith(*this, KV.first, KV.second, UMII);
-    else
-      Symbols.insert(
-          std::make_pair(KV.first, SymbolTableEntry(KV.second, UMII)));
-  }
+  if (Q->isFullyResolved())
+    Q->handleFullyResolved();
+
+  if (Q->isFullyReady())
+    Q->handleFullyReady();
+
+  // Dispatch any required MaterializationUnits for materialization.
+  for (auto &MU : MUs)
+    ES.dispatchMaterialization(*this, std::move(MU));
+
+  return Unresolved;
+}
 
-  if (UMII->Symbols.empty())
-    UnmaterializedInfos.erase(UMII);
+void VSO::dump(raw_ostream &OS) {
+  ES.runSessionLocked([&, this]() {
+    OS << "VSO \"" << VSOName
+       << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES))
+       << "):\n"
+       << "Symbol table:\n";
 
-  return Err;
+    for (auto &KV : Symbols) {
+      OS << "    \"" << *KV.first << "\": " << KV.second.getAddress();
+      if (KV.second.getFlags().isLazy() ||
+          KV.second.getFlags().isMaterializing()) {
+        OS << " (";
+        if (KV.second.getFlags().isLazy()) {
+          auto I = UnmaterializedInfos.find(KV.first);
+          assert(I != UnmaterializedInfos.end() &&
+                 "Lazy symbol should have UnmaterializedInfo");
+          OS << " Lazy (MU=" << I->second->MU.get() << ")";
+        }
+        if (KV.second.getFlags().isMaterializing())
+          OS << " Materializing";
+        OS << " )\n";
+      } else
+        OS << "\n";
+    }
+
+    if (!MaterializingInfos.empty())
+      OS << "  MaterializingInfos entries:\n";
+    for (auto &KV : MaterializingInfos) {
+      OS << "    \"" << *KV.first << "\":\n"
+         << "      IsFinalized = " << (KV.second.IsFinalized ? "true" : "false")
+         << "\n"
+         << "      " << KV.second.PendingQueries.size() << " pending queries.\n"
+         << "      Dependants:\n";
+      for (auto &KV2 : KV.second.Dependants)
+        OS << "        " << KV2.first->getName() << ": " << KV2.second << "\n";
+      OS << "      Unfinalized Dependencies:\n";
+      for (auto &KV2 : KV.second.UnfinalizedDependencies)
+        OS << "        " << KV2.first->getName() << ": " << KV2.second << "\n";
+    }
+  });
 }
 
-SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Names) {
+Error VSO::defineImpl(MaterializationUnit &MU) {
+  SymbolNameSet Duplicates;
+  SymbolNameSet MUDefsOverridden;
+  std::vector<SymbolMap::iterator> ExistingDefsOverridden;
+  for (auto &KV : MU.getSymbols()) {
+    assert(!KV.second.isLazy() && "Lazy flag should be managed internally.");
+    assert(!KV.second.isMaterializing() &&
+           "Materializing flags should be managed internally.");
 
-  for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) {
-    auto Tmp = I++;
-    auto SymI = Symbols.find(*Tmp);
+    SymbolMap::iterator EntryItr;
+    bool Added;
 
-    // If the symbol isn't in this dylib then just continue.
-    if (SymI == Symbols.end())
-      continue;
+    auto NewFlags = KV.second;
+    NewFlags |= JITSymbolFlags::Lazy;
 
-    Names.erase(Tmp);
+    std::tie(EntryItr, Added) = Symbols.insert(
+        std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
 
-    Flags[SymI->first] =
-        JITSymbolFlags::stripTransientFlags(SymI->second.Flags);
+    if (!Added) {
+      if (KV.second.isStrong()) {
+        if (EntryItr->second.getFlags().isStrong())
+          Duplicates.insert(KV.first);
+        else
+          ExistingDefsOverridden.push_back(EntryItr);
+      } else
+        MUDefsOverridden.insert(KV.first);
+    }
   }
 
-  return Names;
-}
+  if (!Duplicates.empty()) {
+    // We need to remove the symbols we added.
+    for (auto &KV : MU.getSymbols()) {
+      if (Duplicates.count(KV.first) || Duplicates.count(KV.first))
+        continue;
 
-VSO::LookupResult VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
-                              SymbolNameSet Names) {
-  MaterializerList Materializers;
+      bool Found = false;
+      for (const auto &I : ExistingDefsOverridden)
+        if (I->first == KV.first)
+          Found = true;
 
-  for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) {
-    auto Tmp = I++;
-    auto SymI = Symbols.find(*Tmp);
+      if (!Found)
+        Symbols.erase(KV.first);
+    }
 
-    // If the symbol isn't in this dylib then just continue.
-    if (SymI == Symbols.end())
-      continue;
+    // FIXME: Return all duplicates.
+    return make_error<DuplicateDefinition>(**Duplicates.begin());
+  }
 
-    // The symbol is in the VSO. Erase it from Names and proceed.
-    Names.erase(Tmp);
+  // Update flags on existing defs and call discard on their materializers.
+  for (auto &ExistingDefItr : ExistingDefsOverridden) {
+    assert(ExistingDefItr->second.getFlags().isLazy() &&
+           !ExistingDefItr->second.getFlags().isMaterializing() &&
+           "Overridden existing def should be in the Lazy state");
 
-    // If this symbol has not been materialized yet grab its materializer,
-    // move all of its sibling symbols to the materializing state, and
-    // delete its unmaterialized info.
-    if (SymI->second.Flags.isLazy()) {
-      assert(SymI->second.UMII->MU &&
-             "Lazy symbol has no materializer attached");
-      auto MU = std::move(SymI->second.UMII->MU);
-      auto SymbolFlags = std::move(SymI->second.UMII->Symbols);
-      UnmaterializedInfos.erase(SymI->second.UMII);
+    ExistingDefItr->second.getFlags() &= ~JITSymbolFlags::Weak;
 
-      for (auto &KV : SymbolFlags) {
-        auto SiblingI = Symbols.find(KV.first);
-        MaterializingInfos.insert(
-            std::make_pair(SiblingI->first, MaterializingInfo()));
-        SiblingI->second.notifyMaterializing();
-      }
+    auto UMII = UnmaterializedInfos.find(ExistingDefItr->first);
+    assert(UMII != UnmaterializedInfos.end() &&
+           "Overridden existing def should have an UnmaterializedInfo");
 
-      Materializers.push_back(Materializer(
-          std::move(MU),
-          MaterializationResponsibility(*this, std::move(SymbolFlags))));
-    }
-
-    // If this symbol already has a fully materialized value, just use it.
-    if (!SymI->second.Flags.isMaterializing()) {
-      Query->resolve(SymI->first, JITEvaluatedSymbol(SymI->second.Address,
-                                                     SymI->second.Flags));
-      Query->finalizeSymbol();
-      continue;
-    }
-
-    // If this symbol is materializing, then get (or create) its
-    // MaterializingInfo struct and appaend the query.
-    auto J = MaterializingInfos.find(SymI->first);
-    assert(J != MaterializingInfos.end() && "Missing MaterializingInfo");
-
-    if (SymI->second.Address) {
-      auto Sym = JITEvaluatedSymbol(SymI->second.Address, SymI->second.Flags);
-      Query->resolve(SymI->first, Sym);
-      assert(J->second.PendingResolution.empty() &&
-             "Queries still pending resolution on resolved symbol?");
-      J->second.PendingFinalization.push_back(Query);
-    } else {
-      assert(J->second.PendingFinalization.empty() &&
-             "Queries pendiing finalization on unresolved symbol?");
-      J->second.PendingResolution.push_back(Query);
-    }
-  }
-
-  return {std::move(Materializers), std::move(Names)};
-}
-
-void VSO::resolve(const SymbolMap &SymbolValues) {
-  for (auto &KV : SymbolValues) {
-    auto I = Symbols.find(KV.first);
-    assert(I != Symbols.end() && "Resolving symbol not present in this dylib");
-    I->second.resolve(*this, KV.second);
-
-    auto J = MaterializingInfos.find(KV.first);
-    if (J == MaterializingInfos.end())
-      continue;
-
-    assert(J->second.PendingFinalization.empty() &&
-           "Queries already pending finalization?");
-    for (auto &Q : J->second.PendingResolution)
-      Q->resolve(KV.first, KV.second);
-    J->second.PendingFinalization = std::move(J->second.PendingResolution);
-    J->second.PendingResolution = MaterializingInfo::QueryList();
-  }
-}
-
-void VSO::notifyMaterializationFailed(const SymbolNameSet &Names) {
-  assert(!Names.empty() && "Failed to materialize empty set?");
-
-  std::map<std::shared_ptr<AsynchronousSymbolQuery>, SymbolNameSet>
-      ResolutionFailures;
-  std::map<std::shared_ptr<AsynchronousSymbolQuery>, SymbolNameSet>
-      FinalizationFailures;
-
-  for (auto &S : Names) {
-    auto I = Symbols.find(S);
-    assert(I != Symbols.end() && "Symbol not present in this VSO");
-
-    auto J = MaterializingInfos.find(S);
-    if (J != MaterializingInfos.end()) {
-      if (J->second.PendingFinalization.empty()) {
-        for (auto &Q : J->second.PendingResolution)
-          ResolutionFailures[Q].insert(S);
-      } else {
-        for (auto &Q : J->second.PendingFinalization)
-          FinalizationFailures[Q].insert(S);
-      }
-      MaterializingInfos.erase(J);
-    }
-    Symbols.erase(I);
+    UMII->second->MU->doDiscard(*this, ExistingDefItr->first);
   }
 
-  for (auto &KV : ResolutionFailures)
-    KV.first->notifyMaterializationFailed(
-        make_error<FailedToResolve>(std::move(KV.second)));
+  // Discard overridden symbols povided by MU.
+  for (auto &Sym : MUDefsOverridden)
+    MU.doDiscard(*this, Sym);
 
-  for (auto &KV : FinalizationFailures)
-    KV.first->notifyMaterializationFailed(
-        make_error<FailedToFinalize>(std::move(KV.second)));
+  return Error::success();
 }
 
-void VSO::finalize(const SymbolNameSet &SymbolsToFinalize) {
-  for (auto &S : SymbolsToFinalize) {
-    auto I = Symbols.find(S);
-    assert(I != Symbols.end() && "Finalizing symbol not present in this dylib");
+void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q,
+                            const SymbolNameSet &QuerySymbols) {
+  for (auto &QuerySymbol : QuerySymbols) {
+    assert(MaterializingInfos.count(QuerySymbol) &&
+           "QuerySymbol does not have MaterializingInfo");
+    auto &MI = MaterializingInfos[QuerySymbol];
 
-    auto J = MaterializingInfos.find(S);
-    if (J != MaterializingInfos.end()) {
-      assert(J->second.PendingResolution.empty() &&
-             "Queries still pending resolution?");
-      for (auto &Q : J->second.PendingFinalization)
-        Q->finalizeSymbol();
-      MaterializingInfos.erase(J);
+    auto IdenticalQuery =
+        [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) {
+          return R.get() == &Q;
+        };
+
+    auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(),
+                          IdenticalQuery);
+    assert(I != MI.PendingQueries.end() &&
+           "Query Q should be in the PendingQueries list for QuerySymbol");
+    MI.PendingQueries.erase(I);
+  }
+}
+
+void VSO::transferFinalizedNodeDependencies(
+    MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
+    MaterializingInfo &FinalizedMI) {
+  for (auto &KV : FinalizedMI.UnfinalizedDependencies) {
+    auto &DependencyVSO = *KV.first;
+    SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr;
+
+    for (auto &DependencyName : KV.second) {
+      auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName];
+
+      // Do not add self dependencies.
+      if (&DependencyMI == &DependantMI)
+        continue;
+
+      // If we haven't looked up the dependencies for DependencyVSO yet, do it
+      // now and cache the result.
+      if (!UnfinalizedDependenciesOnDependencyVSO)
+        UnfinalizedDependenciesOnDependencyVSO =
+            &DependantMI.UnfinalizedDependencies[&DependencyVSO];
+
+      DependencyMI.Dependants[this].insert(DependantName);
+      UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName);
     }
-    I->second.finalize();
   }
 }
 
+VSO &ExecutionSession::createVSO(std::string Name) {
+  return runSessionLocked([&, this]() -> VSO & {
+      VSOs.push_back(std::unique_ptr<VSO>(new VSO(*this, std::move(Name))));
+    return *VSOs.back();
+  });
+}
+
 Expected<SymbolMap> lookup(const std::vector<VSO *> &VSOs, SymbolNameSet Names,
-                           MaterializationDispatcher DispatchMaterialization) {
+                           MaterializationResponsibility *R) {
 #if LLVM_ENABLE_THREADS
   // In the threaded case we use promises to return the results.
   std::promise<SymbolMap> PromisedResult;
@@ -614,18 +863,21 @@ Expected<SymbolMap> lookup(const std::ve
   Error ResolutionError = Error::success();
   std::promise<void> PromisedReady;
   Error ReadyError = Error::success();
-  auto OnResolve = [&](Expected<SymbolMap> Result) {
-    if (Result)
-      PromisedResult.set_value(std::move(*Result));
-    else {
-      {
-        ErrorAsOutParameter _(&ResolutionError);
-        std::lock_guard<std::mutex> Lock(ErrMutex);
-        ResolutionError = Result.takeError();
-      }
-      PromisedResult.set_value(SymbolMap());
-    }
-  };
+  auto OnResolve =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        if (Result) {
+          if (R)
+            R->addDependencies(Result->Dependencies);
+          PromisedResult.set_value(std::move(Result->Symbols));
+        } else {
+          {
+            ErrorAsOutParameter _(&ResolutionError);
+            std::lock_guard<std::mutex> Lock(ErrMutex);
+            ResolutionError = Result.takeError();
+          }
+          PromisedResult.set_value(SymbolMap());
+        }
+      };
   auto OnReady = [&](Error Err) {
     if (Err) {
       ErrorAsOutParameter _(&ReadyError);
@@ -639,12 +891,14 @@ Expected<SymbolMap> lookup(const std::ve
   Error ResolutionError = Error::success();
   Error ReadyError = Error::success();
 
-  auto OnResolve = [&](Expected<SymbolMap> R) {
+  auto OnResolve = [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
     ErrorAsOutParameter _(&ResolutionError);
-    if (R)
-      Result = std::move(*R);
-    else
-      ResolutionError = R.takeError();
+    if (RR) {
+      if (R)
+        R->addDependencies(RR->Dependencies);
+      Result = std::move(RR->Symbols);
+    } else
+      ResolutionError = RR.takeError();
   };
   auto OnReady = [&](Error Err) {
     ErrorAsOutParameter _(&ReadyError);
@@ -658,18 +912,14 @@ Expected<SymbolMap> lookup(const std::ve
   SymbolNameSet UnresolvedSymbols(std::move(Names));
 
   for (auto *V : VSOs) {
-
+    assert(V && "VSO pointers in VSOs list should be non-null");
     if (UnresolvedSymbols.empty())
       break;
-
-    assert(V && "VSO pointers in VSOs list should be non-null");
-    auto LR = V->lookup(Query, UnresolvedSymbols);
-    UnresolvedSymbols = std::move(LR.UnresolvedSymbols);
-
-    for (auto &M : LR.Materializers)
-      DispatchMaterialization(std::move(M));
+    UnresolvedSymbols = V->lookup(Query, UnresolvedSymbols);
   }
 
+  // FIXME: Error out if there are remaining unresolved symbols.
+
 #if LLVM_ENABLE_THREADS
   auto ResultFuture = PromisedResult.get_future();
   auto Result = ResultFuture.get();
@@ -709,22 +959,17 @@ Expected<SymbolMap> lookup(const std::ve
 }
 
 /// Look up a symbol by searching a list of VSOs.
-Expected<JITEvaluatedSymbol>
-lookup(const std::vector<VSO *> VSOs, SymbolStringPtr Name,
-       MaterializationDispatcher DispatchMaterialization) {
+Expected<JITEvaluatedSymbol> lookup(const std::vector<VSO *> VSOs,
+                                    SymbolStringPtr Name,
+                                    MaterializationResponsibility *R) {
   SymbolNameSet Names({Name});
-  if (auto ResultMap =
-          lookup(VSOs, std::move(Names), std::move(DispatchMaterialization))) {
+  if (auto ResultMap = lookup(VSOs, std::move(Names), R)) {
     assert(ResultMap->size() == 1 && "Unexpected number of results");
     assert(ResultMap->count(Name) && "Missing result for symbol");
-    return ResultMap->begin()->second;
+    return std::move(ResultMap->begin()->second);
   } else
     return ResultMap.takeError();
 }
 
-void ExecutionSession::logErrorsToStdErr(Error Err) {
-  logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
-}
-
 } // End namespace orc.
 } // End namespace llvm.

Modified: llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp Wed May 16 15:24:30 2018
@@ -12,9 +12,9 @@
 namespace llvm {
 namespace orc {
 
-JITSymbolResolverAdapter::JITSymbolResolverAdapter(ExecutionSession &ES,
-                                                   SymbolResolver &R)
-    : ES(ES), R(R) {}
+JITSymbolResolverAdapter::JITSymbolResolverAdapter(
+    ExecutionSession &ES, SymbolResolver &R, MaterializationResponsibility *MR)
+    : ES(ES), R(R), MR(MR) {}
 
 Expected<JITSymbolResolverAdapter::LookupResult>
 JITSymbolResolverAdapter::lookup(const LookupSet &Symbols) {
@@ -25,26 +25,28 @@ JITSymbolResolverAdapter::lookup(const L
   for (auto &S : Symbols)
     InternedSymbols.insert(ES.getSymbolStringPool().intern(S));
 
-  auto OnResolve = [&](Expected<SymbolMap> R) {
-    if (R) {
-      for (auto &KV : *R) {
-        ResolvedStrings.insert(KV.first);
-        Result[*KV.first] = KV.second;
-      }
-    } else
-      Err = joinErrors(std::move(Err), R.takeError());
-  };
-
-  auto OnReady = [](Error Err) {
-    // FIXME: Report error to ExecutionSession.
-    logAllUnhandledErrors(std::move(Err), errs(),
-                          "legacy resolver received on-ready error:\n");
-  };
+  auto OnResolve =
+      [&, this](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
+        if (RR) {
+          // If this lookup was attached to a MaterializationResponsibility then
+          // record the dependencies.
+          if (MR)
+            MR->addDependencies(RR->Dependencies);
+
+          for (auto &KV : RR->Symbols) {
+            ResolvedStrings.insert(KV.first);
+            Result[*KV.first] = KV.second;
+          }
+        } else
+          Err = joinErrors(std::move(Err), RR.takeError());
+      };
+
+  auto OnReady = [this](Error Err) { ES.reportError(std::move(Err)); };
 
   auto Query = std::make_shared<AsynchronousSymbolQuery>(InternedSymbols,
                                                          OnResolve, OnReady);
 
-  auto UnresolvedSymbols = R.lookup(std::move(Query), InternedSymbols);
+  auto UnresolvedSymbols = R.lookup(Query, InternedSymbols);
 
   if (!UnresolvedSymbols.empty()) {
     std::string ErrorMsg = "Unresolved symbols: ";

Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h Wed May 16 15:24:30 2018
@@ -155,16 +155,19 @@ private:
           if (auto Addr = Sym.getAddress())
             Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
           else {
-            Query->notifyMaterializationFailed(Addr.takeError());
+            Stack.ES.failQuery(*Query, Addr.takeError());
             return orc::SymbolNameSet();
           }
         } else if (auto Err = Sym.takeError()) {
-          Query->notifyMaterializationFailed(std::move(Err));
+          Stack.ES.failQuery(*Query, std::move(Err));
           return orc::SymbolNameSet();
         } else
           UnresolvedSymbols.insert(S);
       }
 
+      if (Query->isFullyResolved())
+        Query->handleFullyResolved();
+
       return UnresolvedSymbols;
     }
 

Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h Wed May 16 15:24:30 2018
@@ -171,34 +171,40 @@ class OrcMCJITReplacement : public Execu
     SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
                          SymbolNameSet Symbols) override {
       SymbolNameSet UnresolvedSymbols;
+      bool NewSymbolsResolved = false;
 
       for (auto &S : Symbols) {
         if (auto Sym = M.findMangledSymbol(*S)) {
-          if (auto Addr = Sym.getAddress())
+          if (auto Addr = Sym.getAddress()) {
             Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
-          else {
-            Query->notifyMaterializationFailed(Addr.takeError());
+            NewSymbolsResolved = true;
+          } else {
+            M.ES.failQuery(*Query, Addr.takeError());
             return SymbolNameSet();
           }
         } else if (auto Err = Sym.takeError()) {
-          Query->notifyMaterializationFailed(std::move(Err));
+          M.ES.failQuery(*Query, std::move(Err));
           return SymbolNameSet();
         } else {
           if (auto Sym2 = M.ClientResolver->findSymbol(*S)) {
-            if (auto Addr = Sym2.getAddress())
+            if (auto Addr = Sym2.getAddress()) {
               Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym2.getFlags()));
-            else {
-              Query->notifyMaterializationFailed(Addr.takeError());
+              NewSymbolsResolved = true;
+            } else {
+              M.ES.failQuery(*Query, Addr.takeError());
               return SymbolNameSet();
             }
           } else if (auto Err = Sym2.takeError()) {
-            Query->notifyMaterializationFailed(std::move(Err));
+            M.ES.failQuery(*Query, std::move(Err));
             return SymbolNameSet();
           } else
             UnresolvedSymbols.insert(S);
         }
       }
 
+      if (NewSymbolsResolved && Query->isFullyResolved())
+        Query->handleFullyResolved();
+
       return UnresolvedSymbols;
     }
 

Modified: llvm/trunk/tools/lli/OrcLazyJIT.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/OrcLazyJIT.h?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/tools/lli/OrcLazyJIT.h (original)
+++ llvm/trunk/tools/lli/OrcLazyJIT.h Wed May 16 15:24:30 2018
@@ -174,9 +174,10 @@ public:
             }
             return std::move(*NotFoundViaLegacyLookup);
           },
-          [LegacyLookup](std::shared_ptr<orc::AsynchronousSymbolQuery> Query,
+          [this,
+           LegacyLookup](std::shared_ptr<orc::AsynchronousSymbolQuery> Query,
                          orc::SymbolNameSet Symbols) {
-            return lookupWithLegacyFn(*Query, Symbols, LegacyLookup);
+            return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
           });
 
       // Add the module to the JIT.

Modified: llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp (original)
+++ llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp Wed May 16 15:24:30 2018
@@ -22,36 +22,36 @@ namespace {
 
 class SimpleMaterializationUnit : public MaterializationUnit {
 public:
-  using GetSymbolsFunction = std::function<SymbolFlagsMap()>;
   using MaterializeFunction =
       std::function<void(MaterializationResponsibility)>;
   using DiscardFunction = std::function<void(const VSO &, SymbolStringPtr)>;
   using DestructorFunction = std::function<void()>;
 
   SimpleMaterializationUnit(
-      GetSymbolsFunction GetSymbols, MaterializeFunction Materialize,
-      DiscardFunction Discard,
+      SymbolFlagsMap SymbolFlags, MaterializeFunction Materialize,
+      DiscardFunction Discard = DiscardFunction(),
       DestructorFunction Destructor = DestructorFunction())
-      : GetSymbols(std::move(GetSymbols)), Materialize(std::move(Materialize)),
-        Discard(std::move(Discard)), Destructor(std::move(Destructor)) {}
+      : MaterializationUnit(std::move(SymbolFlags)),
+        Materialize(std::move(Materialize)), Discard(std::move(Discard)),
+        Destructor(std::move(Destructor)) {}
 
   ~SimpleMaterializationUnit() override {
     if (Destructor)
       Destructor();
   }
 
-  SymbolFlagsMap getSymbols() override { return GetSymbols(); }
-
   void materialize(MaterializationResponsibility R) override {
     Materialize(std::move(R));
   }
 
   void discard(const VSO &V, SymbolStringPtr Name) override {
-    Discard(V, std::move(Name));
+    if (Discard)
+      Discard(V, std::move(Name));
+    else
+      llvm_unreachable("Discard not supported");
   }
 
 private:
-  GetSymbolsFunction GetSymbols;
   MaterializeFunction Materialize;
   DiscardFunction Discard;
   DestructorFunction Destructor;
@@ -65,14 +65,16 @@ TEST(CoreAPIsTest, AsynchronousSymbolQue
 
   bool OnResolutionRun = false;
   bool OnReadyRun = false;
-  auto OnResolution = [&](Expected<SymbolMap> Result) {
-    EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
-    auto I = Result->find(Foo);
-    EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
-    EXPECT_EQ(I->second.getAddress(), FakeAddr)
-        << "Resolution returned incorrect result";
-    OnResolutionRun = true;
-  };
+  auto OnResolution =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
+        auto &Resolved = Result->Symbols;
+        auto I = Resolved.find(Foo);
+        EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
+        EXPECT_EQ(I->second.getAddress(), FakeAddr)
+            << "Resolution returned incorrect result";
+        OnResolutionRun = true;
+      };
   auto OnReady = [&](Error Err) {
     cantFail(std::move(Err));
     OnReadyRun = true;
@@ -82,24 +84,32 @@ TEST(CoreAPIsTest, AsynchronousSymbolQue
 
   Q.resolve(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported));
 
+  EXPECT_TRUE(Q.isFullyResolved()) << "Expected query to be fully resolved";
+
+  if (!Q.isFullyResolved())
+    return;
+
+  Q.handleFullyResolved();
+
   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
 }
 
-TEST(CoreAPIsTest, AsynchronousSymbolQueryResolutionErrorOnly) {
-  SymbolStringPool SP;
-  auto Foo = SP.intern("foo");
+TEST(CoreAPIsTest, ExecutionSessionFailQuery) {
+  ExecutionSession ES;
+  auto Foo = ES.getSymbolStringPool().intern("foo");
   SymbolNameSet Names({Foo});
 
   bool OnResolutionRun = false;
   bool OnReadyRun = false;
 
-  auto OnResolution = [&](Expected<SymbolMap> Result) {
-    EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
-    auto Msg = toString(Result.takeError());
-    EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result";
-    OnResolutionRun = true;
-  };
+  auto OnResolution =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
+        auto Msg = toString(Result.takeError());
+        EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result";
+        OnResolutionRun = true;
+      };
   auto OnReady = [&](Error Err) {
     cantFail(std::move(Err));
     OnReadyRun = true;
@@ -107,30 +117,31 @@ TEST(CoreAPIsTest, AsynchronousSymbolQue
 
   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
 
-  Q.notifyMaterializationFailed(
-      make_error<StringError>("xyz", inconvertibleErrorCode()));
+  ES.failQuery(Q, make_error<StringError>("xyz", inconvertibleErrorCode()));
 
   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
 }
 
 TEST(CoreAPIsTest, SimpleAsynchronousSymbolQueryAgainstVSO) {
-  SymbolStringPool SP;
-  auto Foo = SP.intern("foo");
+  ExecutionSession ES;
+  auto Foo = ES.getSymbolStringPool().intern("foo");
   constexpr JITTargetAddress FakeAddr = 0xdeadbeef;
   SymbolNameSet Names({Foo});
 
   bool OnResolutionRun = false;
   bool OnReadyRun = false;
 
-  auto OnResolution = [&](Expected<SymbolMap> Result) {
-    EXPECT_TRUE(!!Result) << "Query unexpectedly returned error";
-    auto I = Result->find(Foo);
-    EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
-    EXPECT_EQ(I->second.getAddress(), FakeAddr)
-        << "Resolution returned incorrect result";
-    OnResolutionRun = true;
-  };
+  auto OnResolution =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        EXPECT_TRUE(!!Result) << "Query unexpectedly returned error";
+        auto &Resolved = Result->Symbols;
+        auto I = Resolved.find(Foo);
+        EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
+        EXPECT_EQ(I->second.getAddress(), FakeAddr)
+            << "Resolution returned incorrect result";
+        OnResolutionRun = true;
+      };
 
   auto OnReady = [&](Error Err) {
     cantFail(std::move(Err));
@@ -139,11 +150,12 @@ TEST(CoreAPIsTest, SimpleAsynchronousSym
 
   auto Q =
       std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
-  VSO V;
+  auto &V = ES.createVSO("V");
 
-  SymbolMap Defs;
-  Defs[Foo] = JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported);
-  cantFail(V.define(std::move(Defs)));
+  auto Defs = absoluteSymbols(
+      {{Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported)}});
+  cantFail(V.define(Defs));
+  assert(Defs == nullptr && "Defs should have been accepted");
   V.lookup(Q, Names);
 
   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
@@ -155,33 +167,26 @@ TEST(CoreAPIsTest, LookupFlagsTest) {
   // Test that lookupFlags works on a predefined symbol, and does not trigger
   // materialization of a lazy symbol.
 
-  SymbolStringPool SP;
-  auto Foo = SP.intern("foo");
-  auto Bar = SP.intern("bar");
-  auto Baz = SP.intern("baz");
+  ExecutionSession ES;
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto Bar = ES.getSymbolStringPool().intern("bar");
+  auto Baz = ES.getSymbolStringPool().intern("baz");
 
   JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
   JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>(
       JITSymbolFlags::Exported | JITSymbolFlags::Weak);
 
-  VSO V;
+  VSO &V = ES.createVSO("V");
 
   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
-      [=]() {
-        return SymbolFlagsMap({{Bar, BarFlags}});
-      },
+      SymbolFlagsMap({{Bar, BarFlags}}),
       [](MaterializationResponsibility R) {
         llvm_unreachable("Symbol materialized on flags lookup");
-      },
-      [](const VSO &V, SymbolStringPtr Name) {
-        llvm_unreachable("Symbol finalized on flags lookup");
       });
 
-  SymbolMap InitialDefs;
-  InitialDefs[Foo] = JITEvaluatedSymbol(0xdeadbeef, FooFlags);
-  cantFail(V.define(std::move(InitialDefs)));
-
-  cantFail(V.defineLazy(std::move(MU)));
+  cantFail(V.define(
+      absoluteSymbols({{Foo, JITEvaluatedSymbol(0xdeadbeef, FooFlags)}})));
+  cantFail(V.define(std::move(MU)));
 
   SymbolNameSet Names({Foo, Bar, Baz});
 
@@ -199,18 +204,150 @@ TEST(CoreAPIsTest, LookupFlagsTest) {
   EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
 }
 
+TEST(CoreAPIsTest, TestCircularDependenceInOneVSO) {
+
+  ExecutionSession ES;
+
+  auto &V = ES.createVSO("V");
+
+  // Create three symbols: Foo, Bar and Baz.
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto FooFlags = JITSymbolFlags::Exported;
+  auto FooSym = JITEvaluatedSymbol(1U, FooFlags);
+
+  auto Bar = ES.getSymbolStringPool().intern("bar");
+  auto BarFlags = JITSymbolFlags::Exported;
+  auto BarSym = JITEvaluatedSymbol(2U, BarFlags);
+
+  auto Baz = ES.getSymbolStringPool().intern("baz");
+  auto BazFlags = JITSymbolFlags::Exported;
+  auto BazSym = JITEvaluatedSymbol(3U, BazFlags);
+
+  // Create three MaterializationResponsibility objects: one for each symbol
+  // (these are optional because MaterializationResponsibility does not have
+  // a default constructor).
+  Optional<MaterializationResponsibility> FooR;
+  Optional<MaterializationResponsibility> BarR;
+  Optional<MaterializationResponsibility> BazR;
+
+  // Create a MaterializationUnit for each symbol that moves the
+  // MaterializationResponsibility into one of the locals above.
+  auto FooMU = llvm::make_unique<SimpleMaterializationUnit>(
+      SymbolFlagsMap({{Foo, FooFlags}}),
+      [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); });
+
+  auto BarMU = llvm::make_unique<SimpleMaterializationUnit>(
+      SymbolFlagsMap({{Bar, BarFlags}}),
+      [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); });
+
+  auto BazMU = llvm::make_unique<SimpleMaterializationUnit>(
+      SymbolFlagsMap({{Baz, BazFlags}}),
+      [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); });
+
+  // Define the symbols.
+  cantFail(V.define(FooMU));
+  cantFail(V.define(BarMU));
+  cantFail(V.define(BazMU));
+
+  // Query each of the symbols to trigger materialization.
+  bool FooResolved = false;
+  bool FooReady = false;
+  auto FooQ = std::make_shared<AsynchronousSymbolQuery>(
+      SymbolNameSet({Foo}),
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
+        cantFail(std::move(RR));
+        FooResolved = true;
+      },
+      [&](Error Err) {
+        cantFail(std::move(Err));
+        FooReady = true;
+      });
+  {
+    auto Unresolved = V.lookup(FooQ, {Foo});
+    EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Foo\"";
+  }
+
+  bool BarResolved = false;
+  bool BarReady = false;
+  auto BarQ = std::make_shared<AsynchronousSymbolQuery>(
+      SymbolNameSet({Bar}),
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
+        cantFail(std::move(RR));
+        BarResolved = true;
+      },
+      [&](Error Err) {
+        cantFail(std::move(Err));
+        BarReady = true;
+      });
+  {
+    auto Unresolved = V.lookup(BarQ, {Bar});
+    EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Bar\"";
+  }
+
+  bool BazResolved = false;
+  bool BazReady = false;
+  auto BazQ = std::make_shared<AsynchronousSymbolQuery>(
+      SymbolNameSet({Baz}),
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
+        cantFail(std::move(RR));
+        BazResolved = true;
+      },
+      [&](Error Err) {
+        cantFail(std::move(Err));
+        BazReady = true;
+      });
+  {
+    auto Unresolved = V.lookup(BazQ, {Baz});
+    EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Baz\"";
+  }
+
+  FooR->addDependencies({{&V, SymbolNameSet({Bar})}});
+  BarR->addDependencies({{&V, SymbolNameSet({Baz})}});
+  BazR->addDependencies({{&V, SymbolNameSet({Foo})}});
+
+  EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet";
+  EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet";
+  EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet";
+
+  FooR->resolve({{Foo, FooSym}});
+  BarR->resolve({{Bar, BarSym}});
+  BazR->resolve({{Baz, BazSym}});
+
+  EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now";
+  EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now";
+  EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now";
+
+  EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet";
+  EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet";
+  EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet";
+
+  FooR->finalize();
+  BarR->finalize();
+
+  // Verify that nothing is ready until the circular dependence is resolved.
+
+  EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready";
+  EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready";
+  EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready";
+
+  BazR->finalize();
+
+  // Verify that everything becomes ready once the circular dependence resolved.
+  EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now";
+  EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now";
+  EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now";
+}
+
 TEST(CoreAPIsTest, DropMaterializerWhenEmpty) {
-  SymbolStringPool SP;
-  auto Foo = SP.intern("foo");
-  auto Bar = SP.intern("bar");
+  ExecutionSession ES;
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto Bar = ES.getSymbolStringPool().intern("bar");
 
   bool DestructorRun = false;
 
   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
-      [=]() {
-        return SymbolFlagsMap(
-            {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
-      },
+      SymbolFlagsMap(
+          {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}),
       [](MaterializationResponsibility R) {
         llvm_unreachable("Unexpected call to materialize");
       },
@@ -220,18 +357,18 @@ TEST(CoreAPIsTest, DropMaterializerWhenE
       },
       [&]() { DestructorRun = true; });
 
-  VSO V;
+  auto &V = ES.createVSO("V");
 
-  cantFail(V.defineLazy(std::move(MU)));
+  cantFail(V.define(MU));
 
   auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
   auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
-  cantFail(V.define(SymbolMap({{Foo, FooSym}})));
+  cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
 
   EXPECT_FALSE(DestructorRun)
       << "MaterializationUnit should not have been destroyed yet";
 
-  cantFail(V.define(SymbolMap({{Bar, BarSym}})));
+  cantFail(V.define(absoluteSymbols({{Bar, BarSym}})));
 
   EXPECT_TRUE(DestructorRun)
       << "MaterializationUnit should have been destroyed";
@@ -242,22 +379,20 @@ TEST(CoreAPIsTest, AddAndMaterializeLazy
   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
   constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
 
-  SymbolStringPool SP;
-  auto Foo = SP.intern("foo");
-  auto Bar = SP.intern("bar");
+  ExecutionSession ES;
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto Bar = ES.getSymbolStringPool().intern("bar");
 
   bool FooMaterialized = false;
   bool BarDiscarded = false;
 
-  VSO V;
+  auto &V = ES.createVSO("V");
 
   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
-      [=]() {
-        return SymbolFlagsMap(
-            {{Foo, JITSymbolFlags::Exported},
-             {Bar, static_cast<JITSymbolFlags::FlagNames>(
-                       JITSymbolFlags::Exported | JITSymbolFlags::Weak)}});
-      },
+      SymbolFlagsMap(
+          {{Foo, JITSymbolFlags::Exported},
+           {Bar, static_cast<JITSymbolFlags::FlagNames>(
+                     JITSymbolFlags::Exported | JITSymbolFlags::Weak)}}),
       [&](MaterializationResponsibility R) {
         assert(BarDiscarded && "Bar should have been discarded by this point");
         SymbolMap SymbolsToResolve;
@@ -272,25 +407,27 @@ TEST(CoreAPIsTest, AddAndMaterializeLazy
         BarDiscarded = true;
       });
 
-  cantFail(V.defineLazy(std::move(MU)));
+  cantFail(V.define(MU));
 
-  SymbolMap BarOverride;
-  BarOverride[Bar] = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
-  cantFail(V.define(std::move(BarOverride)));
+  ;
+  cantFail(V.define(absoluteSymbols(
+      {{Bar, JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported)}})));
 
   SymbolNameSet Names({Foo});
 
   bool OnResolutionRun = false;
   bool OnReadyRun = false;
 
-  auto OnResolution = [&](Expected<SymbolMap> Result) {
-    EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
-    auto I = Result->find(Foo);
-    EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
-    EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
-        << "Resolution returned incorrect result";
-    OnResolutionRun = true;
-  };
+  auto OnResolution =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
+        auto I = Result->Symbols.find(Foo);
+        EXPECT_NE(I, Result->Symbols.end())
+            << "Could not find symbol definition";
+        EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
+            << "Resolution returned incorrect result";
+        OnResolutionRun = true;
+      };
 
   auto OnReady = [&](Error Err) {
     cantFail(std::move(Err));
@@ -300,40 +437,98 @@ TEST(CoreAPIsTest, AddAndMaterializeLazy
   auto Q =
       std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
 
-  auto LR = V.lookup(std::move(Q), Names);
+  auto Unresolved = V.lookup(std::move(Q), Names);
 
-  for (auto &M : LR.Materializers)
-    M();
-
-  EXPECT_TRUE(LR.UnresolvedSymbols.empty()) << "Could not find Foo in dylib";
+  EXPECT_TRUE(Unresolved.empty()) << "Could not find Foo in dylib";
   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
   EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
 }
 
+TEST(CoreAPIsTest, DefineMaterializingSymbol) {
+  ExecutionSession ES;
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto Bar = ES.getSymbolStringPool().intern("bar");
+
+  auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
+  auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
+
+  bool ExpectNoMoreMaterialization = false;
+  ES.setDispatchMaterialization(
+      [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) {
+        if (ExpectNoMoreMaterialization)
+          ADD_FAILURE() << "Unexpected materialization";
+        MU->doMaterialize(V);
+      });
+
+  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
+      SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
+      [&](MaterializationResponsibility R) {
+        cantFail(
+            R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}})));
+        R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
+        R.finalize();
+      });
+
+  auto &V = ES.createVSO("V");
+  cantFail(V.define(MU));
+
+  auto OnResolution1 =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        cantFail(std::move(Result));
+      };
+
+  auto OnReady1 = [](Error Err) { cantFail(std::move(Err)); };
+
+  auto Q1 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo}),
+                                                      OnResolution1, OnReady1);
+
+  V.lookup(std::move(Q1), {Foo});
+
+  bool BarResolved = false;
+  auto OnResolution2 =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        auto R = cantFail(std::move(Result));
+        EXPECT_EQ(R.Symbols.size(), 1U) << "Expected to resolve one symbol";
+        EXPECT_EQ(R.Symbols.count(Bar), 1U) << "Expected to resolve 'Bar'";
+        EXPECT_EQ(R.Symbols[Bar].getAddress(), BarSym.getAddress())
+            << "Expected Bar == BarSym";
+        BarResolved = true;
+      };
+
+  auto OnReady2 = [](Error Err) { cantFail(std::move(Err)); };
+
+  auto Q2 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Bar}),
+                                                      OnResolution2, OnReady2);
+
+  ExpectNoMoreMaterialization = true;
+  V.lookup(std::move(Q2), {Bar});
+
+  EXPECT_TRUE(BarResolved) << "Bar should have been resolved";
+}
+
 TEST(CoreAPIsTest, FailResolution) {
-  SymbolStringPool SP;
-  auto Foo = SP.intern("foo");
-  auto Bar = SP.intern("bar");
+  ExecutionSession ES;
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto Bar = ES.getSymbolStringPool().intern("bar");
 
   SymbolNameSet Names({Foo, Bar});
 
   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
-      [=]() {
-        return SymbolFlagsMap(
-            {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
-      },
-      [&](MaterializationResponsibility R) { R.notifyMaterializationFailed(); },
-      [&](const VSO &V, SymbolStringPtr Name) {
-        llvm_unreachable("Unexpected call to discard");
+      SymbolFlagsMap(
+          {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}),
+      [&](MaterializationResponsibility R) {
+        R.failMaterialization(
+            [&]() { return make_error<FailedToResolve>(Names); });
       });
 
-  VSO V;
+  auto &V = ES.createVSO("V");
 
-  cantFail(V.defineLazy(std::move(MU)));
+  cantFail(V.define(MU));
 
-  auto OnResolution = [&](Expected<SymbolMap> Result) {
+  auto OnResolution = [&](Expected<AsynchronousSymbolQuery::ResolutionResult>
+                              Result) {
     handleAllErrors(Result.takeError(),
                     [&](FailedToResolve &F) {
                       EXPECT_EQ(F.getSymbols(), Names)
@@ -359,23 +554,19 @@ TEST(CoreAPIsTest, FailResolution) {
   auto Q =
       std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
 
-  auto LR = V.lookup(std::move(Q), Names);
-  for (auto &M : LR.Materializers)
-    M();
+  V.lookup(std::move(Q), Names);
 }
 
 TEST(CoreAPIsTest, FailFinalization) {
-  SymbolStringPool SP;
-  auto Foo = SP.intern("foo");
-  auto Bar = SP.intern("bar");
+  ExecutionSession ES;
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto Bar = ES.getSymbolStringPool().intern("bar");
 
   SymbolNameSet Names({Foo, Bar});
 
   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
-      [=]() {
-        return SymbolFlagsMap(
-            {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}});
-      },
+      SymbolFlagsMap(
+          {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}}),
       [&](MaterializationResponsibility R) {
         constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
         constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
@@ -383,19 +574,18 @@ TEST(CoreAPIsTest, FailFinalization) {
         auto FooSym = JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
         auto BarSym = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
         R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
-        R.notifyMaterializationFailed();
-      },
-      [&](const VSO &V, SymbolStringPtr Name) {
-        llvm_unreachable("Unexpected call to discard");
+        R.failMaterialization(
+            [&]() { return make_error<FailedToFinalize>(Names); });
       });
 
-  VSO V;
+  auto &V = ES.createVSO("V");
 
-  cantFail(V.defineLazy(std::move(MU)));
+  cantFail(V.define(MU));
 
-  auto OnResolution = [](Expected<SymbolMap> Result) {
-    cantFail(std::move(Result));
-  };
+  auto OnResolution =
+      [](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        cantFail(std::move(Result));
+      };
 
   auto OnReady = [&](Error Err) {
     handleAllErrors(std::move(Err),
@@ -418,32 +608,28 @@ TEST(CoreAPIsTest, FailFinalization) {
   auto Q =
       std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
 
-  auto LR = V.lookup(std::move(Q), Names);
-  for (auto &M : LR.Materializers)
-    M();
+  V.lookup(std::move(Q), Names);
 }
 
 TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
   JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
   JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
 
-  SymbolStringPool SP;
-  auto Foo = SP.intern("foo");
-  auto Bar = SP.intern("bar");
-  auto Baz = SP.intern("baz");
+  ExecutionSession ES;
+
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto Bar = ES.getSymbolStringPool().intern("bar");
+  auto Baz = ES.getSymbolStringPool().intern("baz");
 
-  VSO V;
-  cantFail(V.define({{Foo, FooSym}, {Bar, BarSym}}));
+  auto &V = ES.createVSO("V");
+  cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
 
   auto Resolver = createSymbolResolver(
       [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) {
         return V.lookupFlags(SymbolFlags, Symbols);
       },
       [&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) {
-        auto LR = V.lookup(std::move(Q), Symbols);
-        assert(LR.Materializers.empty() &&
-               "Test generated unexpected materialization work?");
-        return std::move(LR.UnresolvedSymbols);
+        return V.lookup(std::move(Q), Symbols);
       });
 
   SymbolNameSet Symbols({Foo, Bar, Baz});
@@ -466,17 +652,21 @@ TEST(CoreAPIsTest, TestLambdaSymbolResol
 
   bool OnResolvedRun = false;
 
-  auto OnResolved = [&](Expected<SymbolMap> Result) {
-    OnResolvedRun = true;
-    EXPECT_TRUE(!!Result) << "Unexpected error";
-    EXPECT_EQ(Result->size(), 2U) << "Unexpected number of resolved symbols";
-    EXPECT_EQ(Result->count(Foo), 1U) << "Missing lookup result for foo";
-    EXPECT_EQ(Result->count(Bar), 1U) << "Missing lookup result for bar";
-    EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
-        << "Incorrect address for foo";
-    EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress())
-        << "Incorrect address for bar";
-  };
+  auto OnResolved =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        OnResolvedRun = true;
+        EXPECT_TRUE(!!Result) << "Unexpected error";
+        EXPECT_EQ(Result->Symbols.size(), 2U)
+            << "Unexpected number of resolved symbols";
+        EXPECT_EQ(Result->Symbols.count(Foo), 1U)
+            << "Missing lookup result for foo";
+        EXPECT_EQ(Result->Symbols.count(Bar), 1U)
+            << "Missing lookup result for bar";
+        EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress())
+            << "Incorrect address for foo";
+        EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress())
+            << "Incorrect address for bar";
+      };
   auto OnReady = [&](Error Err) {
     EXPECT_FALSE(!!Err) << "Finalization should never fail in this test";
   };
@@ -498,23 +688,17 @@ TEST(CoreAPIsTest, TestLookupWithUnthrea
   auto Foo = ES.getSymbolStringPool().intern("foo");
 
   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
-      [=]() {
-        return SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}});
-      },
+      SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
       [&](MaterializationResponsibility R) {
         R.resolve({{Foo, FooSym}});
         R.finalize();
-      },
-      [](const VSO &V, SymbolStringPtr Name) {
-        llvm_unreachable("Not expecting finalization");
       });
 
-  VSO V;
+  auto &V = ES.createVSO("V");
 
-  cantFail(V.defineLazy(std::move(MU)));
+  cantFail(V.define(MU));
 
-  auto FooLookupResult =
-      cantFail(lookup({&V}, Foo, MaterializeOnCurrentThread()));
+  auto FooLookupResult = cantFail(lookup({&V}, Foo, nullptr));
 
   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
       << "lookup returned an incorrect address";
@@ -528,33 +712,20 @@ TEST(CoreAPIsTest, TestLookupWithThreade
   JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported);
 
   ExecutionSession ES(std::make_shared<SymbolStringPool>());
-  auto Foo = ES.getSymbolStringPool().intern("foo");
 
-  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
-      [=]() {
-        return SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}});
-      },
-      [&](MaterializationResponsibility R) {
-        R.resolve({{Foo, FooSym}});
-        R.finalize();
-      },
-      [](const VSO &V, SymbolStringPtr Name) {
-        llvm_unreachable("Not expecting finalization");
+  std::thread MaterializationThread;
+  ES.setDispatchMaterialization(
+      [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) {
+        auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU));
+        MaterializationThread =
+            std::thread([SharedMU, &V]() { SharedMU->doMaterialize(V); });
       });
+  auto Foo = ES.getSymbolStringPool().intern("foo");
 
-  VSO V;
-
-  cantFail(V.defineLazy(std::move(MU)));
-
-  std::thread MaterializationThread;
-  auto MaterializeOnNewThread = [&](VSO::Materializer M) {
-    // FIXME: Use move capture once we move to C++14.
-    auto SharedM = std::make_shared<VSO::Materializer>(std::move(M));
-    MaterializationThread = std::thread([SharedM]() { (*SharedM)(); });
-  };
+  auto &V = ES.createVSO("V");
+  cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
 
-  auto FooLookupResult =
-    cantFail(lookup({&V}, Foo, MaterializeOnNewThread));
+  auto FooLookupResult = cantFail(lookup({&V}, Foo, nullptr));
 
   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
       << "lookup returned an incorrect address";

Modified: llvm/trunk/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp (original)
+++ llvm/trunk/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp Wed May 16 15:24:30 2018
@@ -21,11 +21,9 @@ TEST(LegacyAPIInteropTest, QueryAgainstV
   ExecutionSession ES(std::make_shared<SymbolStringPool>());
   auto Foo = ES.getSymbolStringPool().intern("foo");
 
-  VSO V;
-  SymbolMap Defs;
+  auto &V = ES.createVSO("V");
   JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
-  Defs[Foo] = FooSym;
-  cantFail(V.define(std::move(Defs)));
+  cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
 
   auto LookupFlags = [&](SymbolFlagsMap &SymbolFlags,
                          const SymbolNameSet &Names) {
@@ -34,15 +32,12 @@ TEST(LegacyAPIInteropTest, QueryAgainstV
 
   auto Lookup = [&](std::shared_ptr<AsynchronousSymbolQuery> Query,
                     SymbolNameSet Symbols) {
-    auto R = V.lookup(std::move(Query), Symbols);
-    EXPECT_TRUE(R.Materializers.empty())
-        << "Query resulted in unexpected materialization work";
-    return std::move(R.UnresolvedSymbols);
+    return V.lookup(std::move(Query), Symbols);
   };
 
   auto UnderlyingResolver =
       createSymbolResolver(std::move(LookupFlags), std::move(Lookup));
-  JITSymbolResolverAdapter Resolver(ES, *UnderlyingResolver);
+  JITSymbolResolverAdapter Resolver(ES, *UnderlyingResolver, nullptr);
 
   JITSymbolResolver::LookupSet Names{StringRef("foo")};
 
@@ -90,10 +85,10 @@ TEST(LegacyAPIInteropTset, LegacyLookupH
     return nullptr;
   };
 
-  SymbolStringPool SP;
-  auto Foo = SP.intern("foo");
-  auto Bar = SP.intern("bar");
-  auto Baz = SP.intern("baz");
+  ExecutionSession ES;
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto Bar = ES.getSymbolStringPool().intern("bar");
+  auto Baz = ES.getSymbolStringPool().intern("baz");
 
   SymbolNameSet Symbols({Foo, Bar, Baz});
 
@@ -115,24 +110,29 @@ TEST(LegacyAPIInteropTset, LegacyLookupH
 
   bool OnResolvedRun = false;
   bool OnReadyRun = false;
-  auto OnResolved = [&](Expected<SymbolMap> Result) {
-    OnResolvedRun = true;
-    EXPECT_TRUE(!!Result) << "lookuWithLegacy failed to resolve";
-    EXPECT_EQ(Result->size(), 2U) << "Wrong number of symbols resolved";
-    EXPECT_EQ(Result->count(Foo), 1U) << "Result for foo missing";
-    EXPECT_EQ(Result->count(Bar), 1U) << "Result for bar missing";
-    EXPECT_EQ((*Result)[Foo].getAddress(), FooAddr) << "Wrong address for foo";
-    EXPECT_EQ((*Result)[Foo].getFlags(), FooFlags) << "Wrong flags for foo";
-    EXPECT_EQ((*Result)[Bar].getAddress(), BarAddr) << "Wrong address for bar";
-    EXPECT_EQ((*Result)[Bar].getFlags(), BarFlags) << "Wrong flags for bar";
-  };
+  auto OnResolved =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        OnResolvedRun = true;
+        EXPECT_TRUE(!!Result) << "lookuWithLegacy failed to resolve";
+
+        auto &Resolved = Result->Symbols;
+        EXPECT_EQ(Resolved.size(), 2U) << "Wrong number of symbols resolved";
+        EXPECT_EQ(Resolved.count(Foo), 1U) << "Result for foo missing";
+        EXPECT_EQ(Resolved.count(Bar), 1U) << "Result for bar missing";
+        EXPECT_EQ(Resolved[Foo].getAddress(), FooAddr)
+            << "Wrong address for foo";
+        EXPECT_EQ(Resolved[Foo].getFlags(), FooFlags) << "Wrong flags for foo";
+        EXPECT_EQ(Resolved[Bar].getAddress(), BarAddr)
+            << "Wrong address for bar";
+        EXPECT_EQ(Resolved[Bar].getFlags(), BarFlags) << "Wrong flags for bar";
+      };
   auto OnReady = [&](Error Err) {
     EXPECT_FALSE(!!Err) << "Finalization unexpectedly failed";
     OnReadyRun = true;
   };
 
   AsynchronousSymbolQuery Q({Foo, Bar}, OnResolved, OnReady);
-  auto Unresolved = lookupWithLegacyFn(Q, Symbols, LegacyLookup);
+  auto Unresolved = lookupWithLegacyFn(ES, Q, Symbols, LegacyLookup);
 
   EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run";
   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";

Modified: llvm/trunk/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp?rev=332541&r1=332540&r2=332541&view=diff
==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp (original)
+++ llvm/trunk/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp Wed May 16 15:24:30 2018
@@ -190,7 +190,7 @@ TEST_F(RTDyldObjectLinkingLayerExecution
       },
       [&](std::shared_ptr<AsynchronousSymbolQuery> Query,
           const SymbolNameSet &Symbols) {
-        return lookupWithLegacyFn(*Query, Symbols, LegacyLookup);
+        return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
       });
 
   cantFail(ObjLayer.addObject(K2, std::move(Obj2)));




More information about the llvm-commits mailing list