Revert r337595 "[ORC] Add new symbol lookup methods to ExecutionSessionBase in preparation for"

Breaks the build with LLVM_ENABLE_THREADS=OFF.

llvm-svn: 337608
diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp
index dc6a156..65f1178 100644
--- a/llvm/lib/ExecutionEngine/Orc/Core.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp
@@ -23,9 +23,6 @@
 char FailedToMaterialize::ID = 0;
 char SymbolsNotFound::ID = 0;
 
-RegisterDependenciesFunction NoDependenciesToRegister =
-    RegisterDependenciesFunction();
-
 void MaterializationUnit::anchor() {}
 
 raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
@@ -141,361 +138,20 @@
   OS << "Symbols not found: " << Symbols;
 }
 
-void ExecutionSessionBase::legacyFailQuery(AsynchronousSymbolQuery &Q,
-                                           Error Err) {
-  assert(!!Err && "Error should be in failure state");
-
-  bool SendErrorToQuery;
-  runSessionLocked([&]() {
+void ExecutionSessionBase::failQuery(AsynchronousSymbolQuery &Q, Error Err) {
+  bool DeliveredError = true;
+  runSessionLocked([&]() -> void {
     Q.detach();
-    SendErrorToQuery = Q.canStillFail();
+    if (Q.canStillFail())
+      Q.handleFailed(std::move(Err));
+    else
+      DeliveredError = false;
   });
 
-  if (SendErrorToQuery)
-    Q.handleFailed(std::move(Err));
-  else
+  if (!DeliveredError)
     reportError(std::move(Err));
 }
 
-Expected<SymbolMap> ExecutionSessionBase::legacyLookup(
-    ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup,
-    SymbolNameSet Names, bool WaitUntilReady,
-    RegisterDependenciesFunction RegisterDependencies) {
-#if LLVM_ENABLE_THREADS
-  // In the threaded case we use promises to return the results.
-  std::promise<SymbolMap> PromisedResult;
-  std::mutex ErrMutex;
-  Error ResolutionError = Error::success();
-  std::promise<void> PromisedReady;
-  Error ReadyError = Error::success();
-  auto OnResolve = [&](Expected<SymbolMap> R) {
-    if (R)
-      PromisedResult.set_value(std::move(*R));
-    else {
-      {
-        ErrorAsOutParameter _(&ResolutionError);
-        std::lock_guard<std::mutex> Lock(ErrMutex);
-        ResolutionError = R.takeError();
-      }
-      PromisedResult.set_value(SymbolMap());
-    }
-  };
-
-  std::function<void(Error)> OnReady;
-  if (WaitUntilReady) {
-    OnReady = [&](Error Err) {
-      if (Err) {
-        ErrorAsOutParameter _(&ReadyError);
-        std::lock_guard<std::mutex> Lock(ErrMutex);
-        ReadyError = std::move(Err);
-      }
-      PromisedReady.set_value();
-    };
-  } else {
-    OnReady = [&](Error Err) {
-      if (Err)
-        ES.reportError(std::move(Err));
-    };
-  }
-
-#else
-  SymbolMap Result;
-  Error ResolutionError = Error::success();
-  Error ReadyError = Error::success();
-
-  auto OnResolve = [&](Expected<SymbolMap> R) {
-    ErrorAsOutParameter _(&ResolutionError);
-    if (R)
-      Result = std::move(*R);
-    else
-      ResolutionError = R.takeError();
-  };
-
-  std::function<void(Error)> OnReady;
-  if (WaitUntilReady) {
-    OnReady = [&](Error Err) {
-      ErrorAsOutParameter _(&ReadyError);
-      if (Err)
-        ReadyError = std::move(Err);
-    };
-  } else {
-    OnReady = [&](Error Err) {
-      if (Err)
-        ES.reportError(std::move(Err));
-    };
-  }
-#endif
-
-  auto Query = std::make_shared<AsynchronousSymbolQuery>(
-      Names, std::move(OnResolve), std::move(OnReady));
-  // FIXME: This should be run session locked along with the registration code
-  // and error reporting below.
-  SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
-
-  // If the query was lodged successfully then register the dependencies,
-  // otherwise fail it with an error.
-  if (UnresolvedSymbols.empty())
-    RegisterDependencies(Query->QueryRegistrations);
-  else {
-    bool DeliverError = runSessionLocked([&]() {
-      Query->detach();
-      return Query->canStillFail();
-    });
-    auto Err = make_error<SymbolsNotFound>(std::move(UnresolvedSymbols));
-    if (DeliverError)
-      Query->handleFailed(std::move(Err));
-    else
-      ES.reportError(std::move(Err));
-  }
-
-#if LLVM_ENABLE_THREADS
-  auto ResultFuture = PromisedResult.get_future();
-  auto Result = ResultFuture.get();
-
-  {
-    std::lock_guard<std::mutex> Lock(ErrMutex);
-    if (ResolutionError) {
-      // ReadyError will never be assigned. Consume the success value.
-      cantFail(std::move(ReadyError));
-      return std::move(ResolutionError);
-    }
-  }
-
-  if (WaitUntilReady) {
-    auto ReadyFuture = PromisedReady.get_future();
-    ReadyFuture.get();
-
-    {
-      std::lock_guard<std::mutex> Lock(ErrMutex);
-      if (ReadyError)
-        return std::move(ReadyError);
-    }
-  } else
-    cantFail(std::move(ReadyError));
-
-  return std::move(Result);
-
-#else
-  if (ResolutionError) {
-    // ReadyError will never be assigned. Consume the success value.
-    cantFail(std::move(ReadyError));
-    return std::move(ResolutionError);
-  }
-
-  if (ReadyError)
-    return std::move(ReadyError);
-
-  return Result;
-#endif
-}
-
-void ExecutionSessionBase::lookup(
-    const VSOList &VSOs, const SymbolNameSet &Symbols,
-    SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
-    RegisterDependenciesFunction RegisterDependencies) {
-
-  // lookup can be re-entered recursively if running on a single thread. Run any
-  // outstanding MUs in case this query depends on them, otherwise the main
-  // thread will starve waiting for a result from an MU that it failed to run.
-  runOutstandingMUs();
-
-  auto Unresolved = std::move(Symbols);
-  std::map<VSO *, MaterializationUnitList> MUsMap;
-  auto Q = std::make_shared<AsynchronousSymbolQuery>(
-      Symbols, std::move(OnResolve), std::move(OnReady));
-  bool QueryIsFullyResolved = false;
-  bool QueryIsFullyReady = false;
-  bool QueryFailed = false;
-
-  runSessionLocked([&]() {
-    for (auto *V : VSOs) {
-      assert(V && "VSOList entries must not be null");
-      assert(!MUsMap.count(V) &&
-             "VSOList should not contain duplicate entries");
-      V->lodgeQuery(Q, Unresolved, MUsMap[V]);
-    }
-
-    if (Unresolved.empty()) {
-      // Query lodged successfully.
-
-      // Record whether this query is fully ready / resolved. We will use
-      // this to call handleFullyResolved/handleFullyReady outside the session
-      // lock.
-      QueryIsFullyResolved = Q->isFullyResolved();
-      QueryIsFullyReady = Q->isFullyReady();
-
-      // Call the register dependencies function.
-      if (RegisterDependencies && !Q->QueryRegistrations.empty())
-        RegisterDependencies(Q->QueryRegistrations);
-    } else {
-      // Query failed due to unresolved symbols.
-      QueryFailed = true;
-
-      // Disconnect the query from its dependencies.
-      Q->detach();
-
-      // Replace the MUs.
-      for (auto &KV : MUsMap)
-        for (auto &MU : KV.second)
-          KV.first->replace(std::move(MU));
-    }
-  });
-
-  if (QueryFailed) {
-    Q->handleFailed(make_error<SymbolsNotFound>(std::move(Unresolved)));
-    return;
-  } else {
-    if (QueryIsFullyResolved)
-      Q->handleFullyResolved();
-    if (QueryIsFullyReady)
-      Q->handleFullyReady();
-  }
-
-  // Move the MUs to the OutstandingMUs list, then materialize.
-  {
-    std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
-
-    for (auto &KV : MUsMap)
-      for (auto &MU : KV.second)
-        OutstandingMUs.push_back(std::make_pair(KV.first, std::move(MU)));
-  }
-
-  runOutstandingMUs();
-}
-
-Expected<SymbolMap>
-ExecutionSessionBase::lookup(const VSOList &VSOs, const SymbolNameSet &Symbols,
-                             RegisterDependenciesFunction RegisterDependencies,
-                             bool WaitUntilReady) {
-#if LLVM_ENABLE_THREADS
-  // In the threaded case we use promises to return the results.
-  std::promise<SymbolMap> PromisedResult;
-  std::mutex ErrMutex;
-  Error ResolutionError = Error::success();
-  std::promise<void> PromisedReady;
-  Error ReadyError = Error::success();
-  auto OnResolve = [&](Expected<SymbolMap> R) {
-    if (R)
-      PromisedResult.set_value(std::move(*R));
-    else {
-      {
-        ErrorAsOutParameter _(&ResolutionError);
-        std::lock_guard<std::mutex> Lock(ErrMutex);
-        ResolutionError = R.takeError();
-      }
-      PromisedResult.set_value(SymbolMap());
-    }
-  };
-
-  std::function<void(Error)> OnReady;
-  if (WaitUntilReady) {
-    OnReady = [&](Error Err) {
-      if (Err) {
-        ErrorAsOutParameter _(&ReadyError);
-        std::lock_guard<std::mutex> Lock(ErrMutex);
-        ReadyError = std::move(Err);
-      }
-      PromisedReady.set_value();
-    };
-  } else {
-    OnReady = [&](Error Err) {
-      if (Err)
-        reportError(std::move(Err));
-    };
-  }
-
-#else
-  SymbolMap Result;
-  Error ResolutionError = Error::success();
-  Error ReadyError = Error::success();
-
-  auto OnResolve = [&](Expected<SymbolMap> R) {
-    ErrorAsOutParameter _(&ResolutionError);
-    if (R)
-      Result = std::move(R->Symbols);
-    else
-      ResolutionError = R.takeError();
-  };
-
-  std::function<void(Error)> OnReady;
-  if (WaitUntilReady) {
-    OnReady = [&](Error Err) {
-      ErrorAsOutParameter _(&ReadyError);
-      if (Err)
-        ReadyError = std::move(Err);
-    };
-  } else {
-    OnReady = [&](Error Err) {
-      if (Err)
-        reportError(std::move(Err));
-    };
-  }
-#endif
-
-  // Perform the asynchronous lookup.
-  lookup(VSOs, Symbols, OnResolve, OnReady, RegisterDependencies);
-
-#if LLVM_ENABLE_THREADS
-  auto ResultFuture = PromisedResult.get_future();
-  auto Result = ResultFuture.get();
-
-  {
-    std::lock_guard<std::mutex> Lock(ErrMutex);
-    if (ResolutionError) {
-      // ReadyError will never be assigned. Consume the success value.
-      cantFail(std::move(ReadyError));
-      return std::move(ResolutionError);
-    }
-  }
-
-  if (WaitUntilReady) {
-    auto ReadyFuture = PromisedReady.get_future();
-    ReadyFuture.get();
-
-    {
-      std::lock_guard<std::mutex> Lock(ErrMutex);
-      if (ReadyError)
-        return std::move(ReadyError);
-    }
-  } else
-    cantFail(std::move(ReadyError));
-
-  return std::move(Result);
-
-#else
-  if (ResolutionError) {
-    // ReadyError will never be assigned. Consume the success value.
-    cantFail(std::move(ReadyError));
-    return std::move(ResolutionError);
-  }
-
-  if (ReadyError)
-    return std::move(ReadyError);
-
-  return Result;
-#endif
-}
-
-void ExecutionSessionBase::runOutstandingMUs() {
-  while (1) {
-    std::pair<VSO *, std::unique_ptr<MaterializationUnit>> VSOAndMU;
-
-    {
-      std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
-      if (!OutstandingMUs.empty()) {
-        VSOAndMU = std::move(OutstandingMUs.back());
-        OutstandingMUs.pop_back();
-      }
-    }
-
-    if (VSOAndMU.first) {
-      assert(VSOAndMU.second && "VSO, but no MU?");
-      dispatchMaterialization(*VSOAndMU.first, std::move(VSOAndMU.second));
-    } else
-      break;
-  }
-}
-
 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
     const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
     SymbolsReadyCallback NotifySymbolsReady)
@@ -505,6 +161,12 @@
 
   for (auto &S : Symbols)
     ResolvedSymbols[S] = nullptr;
+
+  // If the query is empty it is trivially resolved/ready.
+  if (Symbols.empty()) {
+    handleFullyResolved();
+    handleFullyReady();
+  }
 }
 
 void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name,
@@ -521,7 +183,8 @@
   assert(NotYetResolvedCount == 0 && "Not fully resolved?");
   assert(NotifySymbolsResolved &&
          "NotifySymbolsResolved already called or error occurred");
-  NotifySymbolsResolved(std::move(ResolvedSymbols));
+  NotifySymbolsResolved(
+      ResolutionResult(std::move(ResolvedSymbols), QueryRegistrations));
   NotifySymbolsResolved = SymbolsResolvedCallback();
 }
 
@@ -686,8 +349,7 @@
 
 void MaterializationResponsibility::addDependencies(
     const SymbolDependenceMap &Dependencies) {
-  for (auto &KV : SymbolFlags)
-    V.addDependencies(KV.first, Dependencies);
+  V.addDependencies(SymbolFlags, Dependencies);
 }
 
 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
@@ -722,9 +384,8 @@
 void ReExportsMaterializationUnit::materialize(
     MaterializationResponsibility R) {
 
-  auto &ES = R.getTargetVSO().getExecutionSession();
-  VSO &TgtV = R.getTargetVSO();
-  VSO &SrcV = SourceVSO ? *SourceVSO : TgtV;
+  VSO &SrcV = SourceVSO ? *SourceVSO : R.getTargetVSO();
+  auto &ES = SrcV.getExecutionSession();
 
   // Find the set of requested aliases and aliasees. Return any unrequested
   // aliases back to the VSO so as to not prematurely materialize any aliasees.
@@ -773,8 +434,9 @@
       auto Tmp = I++;
 
       // Chain detected. Skip this symbol for this round.
-      if (&SrcV == &TgtV && (QueryAliases.count(Tmp->second.Aliasee) ||
-                             RequestedAliases.count(Tmp->second.Aliasee)))
+      if (&SrcV == &R.getTargetVSO() &&
+          (QueryAliases.count(Tmp->second.Aliasee) ||
+           RequestedAliases.count(Tmp->second.Aliasee)))
         continue;
 
       ResponsibilitySymbols.insert(Tmp->first);
@@ -797,32 +459,49 @@
 
     QueryInfos.pop_back();
 
-    auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
-      R.addDependencies(Deps);
-    };
+    auto OnResolve =
+        [QueryInfo,
+         &SrcV](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
+          if (RR) {
+            SymbolMap ResolutionMap;
+            SymbolNameSet Resolved;
+            for (auto &KV : QueryInfo->Aliases) {
+              assert(RR->Symbols.count(KV.second.Aliasee) &&
+                     "Result map missing entry?");
+              ResolutionMap[KV.first] = JITEvaluatedSymbol(
+                  RR->Symbols[KV.second.Aliasee].getAddress(),
+                  KV.second.AliasFlags);
 
-    auto OnResolve = [QueryInfo](Expected<SymbolMap> Result) {
-      if (Result) {
-        SymbolMap ResolutionMap;
-        for (auto &KV : QueryInfo->Aliases) {
-          assert(Result->count(KV.second.Aliasee) &&
-                 "Result map missing entry?");
-          ResolutionMap[KV.first] = JITEvaluatedSymbol(
-              (*Result)[KV.second.Aliasee].getAddress(), KV.second.AliasFlags);
-        }
-        QueryInfo->R.resolve(ResolutionMap);
-        QueryInfo->R.finalize();
-      } else {
-        auto &ES = QueryInfo->R.getTargetVSO().getExecutionSession();
-        ES.reportError(Result.takeError());
-        QueryInfo->R.failMaterialization();
-      }
-    };
+              // FIXME: We're creating a SymbolFlagsMap and a std::map of
+              // std::sets just to add one dependency here. This needs a
+              // re-think.
+              Resolved.insert(KV.first);
+            }
+            QueryInfo->R.resolve(ResolutionMap);
+
+            SymbolDependenceMap Deps;
+            Deps[&SrcV] = std::move(Resolved);
+            QueryInfo->R.addDependencies(Deps);
+
+            QueryInfo->R.finalize();
+          } else {
+            auto &ES = QueryInfo->R.getTargetVSO().getExecutionSession();
+            ES.reportError(RR.takeError());
+            QueryInfo->R.failMaterialization();
+          }
+        };
 
     auto OnReady = [&ES](Error Err) { ES.reportError(std::move(Err)); };
 
-    ES.lookup({&SrcV}, QuerySymbols, std::move(OnResolve), std::move(OnReady),
-              std::move(RegisterDependencies));
+    auto Q = std::make_shared<AsynchronousSymbolQuery>(
+        QuerySymbols, std::move(OnResolve), std::move(OnReady));
+
+    auto Unresolved = SrcV.lookup(Q, std::move(QuerySymbols));
+
+    if (!Unresolved.empty()) {
+      ES.failQuery(*Q, make_error<SymbolsNotFound>(std::move(Unresolved)));
+      return;
+    }
   }
 }
 
@@ -963,35 +642,40 @@
   });
 }
 
-void VSO::addDependencies(const SymbolStringPtr &Name,
+void VSO::addDependencies(const SymbolFlagsMap &Dependants,
                           const SymbolDependenceMap &Dependencies) {
-  assert(Symbols.count(Name) && "Name not in symbol table");
-  assert((Symbols[Name].getFlags().isLazy() ||
-          Symbols[Name].getFlags().isMaterializing()) &&
-         "Symbol is not lazy or materializing");
+  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");
+      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 &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];
+        for (auto &OtherSymbol : KV.second) {
+          auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol];
 
-      if (OtherMI.IsFinalized)
-        transferFinalizedNodeDependencies(MI, Name, OtherMI);
-      else if (&OtherVSO != this || OtherSymbol != Name) {
-        OtherMI.Dependants[this].insert(Name);
-        DepsOnOtherVSO.insert(OtherSymbol);
+          if (OtherMI.IsFinalized)
+            transferFinalizedNodeDependencies(MI, Name, OtherMI);
+          else if (&OtherVSO != this || OtherSymbol != Name) {
+            OtherMI.Dependants[this].insert(Name);
+            DepsOnOtherVSO.insert(OtherSymbol);
+          }
+        }
+
+        if (DepsOnOtherVSO.empty())
+          MI.UnfinalizedDependencies.erase(&OtherVSO);
       }
     }
-
-    if (DepsOnOtherVSO.empty())
-      MI.UnfinalizedDependencies.erase(&OtherVSO);
-  }
+  });
 }
 
 void VSO::resolve(const SymbolMap &Resolved) {
@@ -1172,6 +856,25 @@
     Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols));
 }
 
+void VSO::runOutstandingMUs() {
+  while (1) {
+    std::unique_ptr<MaterializationUnit> MU;
+
+    {
+      std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
+      if (!OutstandingMUs.empty()) {
+        MU = std::move(OutstandingMUs.back());
+        OutstandingMUs.pop_back();
+      }
+    }
+
+    if (MU)
+      ES.dispatchMaterialization(*this, std::move(MU));
+    else
+      break;
+  }
+}
+
 void VSO::setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst) {
   if (SearchThisVSOFirst && NewSearchOrder.front() != this)
     NewSearchOrder.insert(NewSearchOrder.begin(), this);
@@ -1236,89 +939,11 @@
   return Unresolved;
 }
 
-void VSO::lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
-                     SymbolNameSet &Unresolved, MaterializationUnitList &MUs) {
+SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
+                          SymbolNameSet Names) {
   assert(Q && "Query can not be null");
 
-  lodgeQueryImpl(Q, Unresolved, MUs);
-  if (FallbackDefinitionGenerator && !Unresolved.empty()) {
-    auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved);
-    if (!FallbackDefs.empty()) {
-      for (auto &D : FallbackDefs)
-        Unresolved.erase(D);
-      lodgeQueryImpl(Q, FallbackDefs, MUs);
-      assert(FallbackDefs.empty() &&
-             "All fallback defs should have been found by lookupImpl");
-    }
-  }
-}
-
-void VSO::lodgeQueryImpl(
-    std::shared_ptr<AsynchronousSymbolQuery> &Q, SymbolNameSet &Unresolved,
-    std::vector<std::unique_ptr<MaterializationUnit>> &MUs) {
-  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 added 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");
-
-      // Move 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;
-    }
-
-    // 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);
-  }
-}
-
-SymbolNameSet VSO::legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
-                                SymbolNameSet Names) {
-  assert(Q && "Query can not be null");
-
-  ES.runOutstandingMUs();
+  runOutstandingMUs();
 
   LookupImplActionFlags ActionFlags = None;
   std::vector<std::unique_ptr<MaterializationUnit>> MUs;
@@ -1353,11 +978,11 @@
   //        callbacks from asynchronous queries.
   // Add MUs to the OutstandingMUs list.
   {
-    std::lock_guard<std::recursive_mutex> Lock(ES.OutstandingMUsMutex);
+    std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
     for (auto &MU : MUs)
-      ES.OutstandingMUs.push_back(make_pair(this, std::move(MU)));
+      OutstandingMUs.push_back(std::move(MU));
   }
-  ES.runOutstandingMUs();
+  runOutstandingMUs();
 
   // Dispatch any required MaterializationUnits for materialization.
   // for (auto &MU : MUs)
@@ -1618,6 +1243,133 @@
   });
 }
 
+Expected<SymbolMap> blockingLookup(ExecutionSessionBase &ES,
+                                   AsynchronousLookupFunction AsyncLookup,
+                                   SymbolNameSet Names, bool WaitUntilReady,
+                                   MaterializationResponsibility *MR) {
+
+#if LLVM_ENABLE_THREADS
+  // In the threaded case we use promises to return the results.
+  std::promise<SymbolMap> PromisedResult;
+  std::mutex ErrMutex;
+  Error ResolutionError = Error::success();
+  std::promise<void> PromisedReady;
+  Error ReadyError = Error::success();
+  auto OnResolve =
+      [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
+        if (Result) {
+          if (MR)
+            MR->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());
+        }
+      };
+
+  std::function<void(Error)> OnReady;
+  if (WaitUntilReady) {
+    OnReady = [&](Error Err) {
+      if (Err) {
+        ErrorAsOutParameter _(&ReadyError);
+        std::lock_guard<std::mutex> Lock(ErrMutex);
+        ReadyError = std::move(Err);
+      }
+      PromisedReady.set_value();
+    };
+  } else {
+    OnReady = [&](Error Err) {
+      if (Err)
+        ES.reportError(std::move(Err));
+    };
+  }
+
+#else
+  SymbolMap Result;
+  Error ResolutionError = Error::success();
+  Error ReadyError = Error::success();
+
+  auto OnResolve = [&](Expected<AsynchronousSymbolQuery::ResolutionResult> R) {
+    ErrorAsOutParameter _(&ResolutionError);
+    if (R) {
+      if (MR)
+        MR->addDependencies(R->Dependencies);
+      Result = std::move(R->Symbols);
+    } else
+      ResolutionError = R.takeError();
+  };
+
+  std::function<void(Error)> OnReady;
+  if (WaitUntilReady) {
+    OnReady = [&](Error Err) {
+      ErrorAsOutParameter _(&ReadyError);
+      if (Err)
+        ReadyError = std::move(Err);
+    };
+  } else {
+    OnReady = [&](Error Err) {
+      if (Err)
+        ES.reportError(std::move(Err));
+    };
+  }
+#endif
+
+  auto Query = std::make_shared<AsynchronousSymbolQuery>(
+      Names, std::move(OnResolve), std::move(OnReady));
+
+  SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
+
+  // If there are unresolved symbols then the query will never return.
+  // Fail it with ES.failQuery.
+  if (!UnresolvedSymbols.empty())
+    ES.failQuery(*Query,
+                 make_error<SymbolsNotFound>(std::move(UnresolvedSymbols)));
+
+#if LLVM_ENABLE_THREADS
+  auto ResultFuture = PromisedResult.get_future();
+  auto Result = ResultFuture.get();
+
+  {
+    std::lock_guard<std::mutex> Lock(ErrMutex);
+    if (ResolutionError) {
+      // ReadyError will never be assigned. Consume the success value.
+      cantFail(std::move(ReadyError));
+      return std::move(ResolutionError);
+    }
+  }
+
+  if (WaitUntilReady) {
+    auto ReadyFuture = PromisedReady.get_future();
+    ReadyFuture.get();
+
+    {
+      std::lock_guard<std::mutex> Lock(ErrMutex);
+      if (ReadyError)
+        return std::move(ReadyError);
+    }
+  } else
+    cantFail(std::move(ReadyError));
+
+  return std::move(Result);
+
+#else
+  if (ResolutionError) {
+    // ReadyError will never be assigned. Consume the success value.
+    cantFail(std::move(ReadyError));
+    return std::move(ResolutionError);
+  }
+
+  if (ReadyError)
+    return std::move(ReadyError);
+
+  return Result;
+#endif
+}
+
 Expected<SymbolMap> lookup(const VSOList &VSOs, SymbolNameSet Names) {
 
   if (VSOs.empty())
@@ -1625,7 +1377,18 @@
 
   auto &ES = (*VSOs.begin())->getExecutionSession();
 
-  return ES.lookup(VSOs, Names, NoDependenciesToRegister, true);
+  auto LookupFn = [&](std::shared_ptr<AsynchronousSymbolQuery> Q,
+                      SymbolNameSet Unresolved) {
+    for (auto *V : VSOs) {
+      assert(V && "VSOs entries must not be null");
+      if (Unresolved.empty())
+        break;
+      Unresolved = V->lookup(Q, std::move(Unresolved));
+    }
+    return Unresolved;
+  };
+
+  return blockingLookup(ES, std::move(LookupFn), Names, true);
 }
 
 /// Look up a symbol by searching a list of VSOs.
diff --git a/llvm/lib/ExecutionEngine/Orc/Legacy.cpp b/llvm/lib/ExecutionEngine/Orc/Legacy.cpp
index 22775ef..6fde689 100644
--- a/llvm/lib/ExecutionEngine/Orc/Legacy.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Legacy.cpp
@@ -29,14 +29,8 @@
     return R.lookup(std::move(Q), std::move(Unresolved));
   };
 
-  auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
-    if (MR)
-      MR->addDependencies(Deps);
-  };
-
-  auto InternedResult =
-      ES.legacyLookup(ES, std::move(LookupFn), std::move(InternedSymbols),
-                      false, RegisterDependencies);
+  auto InternedResult = blockingLookup(ES, std::move(LookupFn),
+                                       std::move(InternedSymbols), false, MR);
 
   if (!InternedResult)
     return InternedResult.takeError();
diff --git a/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
index b9f8a37..6c44f43 100644
--- a/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
+++ b/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
@@ -156,11 +156,11 @@
             Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
             Query->notifySymbolReady();
           } else {
-            Stack.ES.legacyFailQuery(*Query, Addr.takeError());
+            Stack.ES.failQuery(*Query, Addr.takeError());
             return orc::SymbolNameSet();
           }
         } else if (auto Err = Sym.takeError()) {
-          Stack.ES.legacyFailQuery(*Query, std::move(Err));
+          Stack.ES.failQuery(*Query, std::move(Err));
           return orc::SymbolNameSet();
         } else
           UnresolvedSymbols.insert(S);
diff --git a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
index abe89ce..ded53ac 100644
--- a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
+++ b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
@@ -178,11 +178,11 @@
             Query->notifySymbolReady();
             NewSymbolsResolved = true;
           } else {
-            M.ES.legacyFailQuery(*Query, Addr.takeError());
+            M.ES.failQuery(*Query, Addr.takeError());
             return SymbolNameSet();
           }
         } else if (auto Err = Sym.takeError()) {
-          M.ES.legacyFailQuery(*Query, std::move(Err));
+          M.ES.failQuery(*Query, std::move(Err));
           return SymbolNameSet();
         } else {
           if (auto Sym2 = M.ClientResolver->findSymbol(*S)) {
@@ -191,11 +191,11 @@
               Query->notifySymbolReady();
               NewSymbolsResolved = true;
             } else {
-              M.ES.legacyFailQuery(*Query, Addr.takeError());
+              M.ES.failQuery(*Query, Addr.takeError());
               return SymbolNameSet();
             }
           } else if (auto Err = Sym2.takeError()) {
-            M.ES.legacyFailQuery(*Query, std::move(Err));
+            M.ES.failQuery(*Query, std::move(Err));
             return SymbolNameSet();
           } else
             UnresolvedSymbols.insert(S);
diff --git a/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp
index 6edf616..7cdc6b3 100644
--- a/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp
@@ -16,23 +16,30 @@
 
 class VSOSearchOrderResolver : public JITSymbolResolver {
 public:
-  VSOSearchOrderResolver(MaterializationResponsibility &MR) : MR(MR) {}
+  VSOSearchOrderResolver(ExecutionSession &ES,
+                         MaterializationResponsibility &MR)
+      : ES(ES), MR(MR) {}
 
   Expected<LookupResult> lookup(const LookupSet &Symbols) {
-    auto &ES = MR.getTargetVSO().getExecutionSession();
     SymbolNameSet InternedSymbols;
 
     for (auto &S : Symbols)
       InternedSymbols.insert(ES.getSymbolStringPool().intern(S));
 
-    auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
-      MR.addDependencies(Deps);
+    auto AsyncLookup = [&](std::shared_ptr<AsynchronousSymbolQuery> Q,
+                           SymbolNameSet Names) {
+      SymbolNameSet Unresolved = std::move(Names);
+      MR.getTargetVSO().withSearchOrderDo([&](const VSOList &SearchOrder) {
+        for (auto *V : SearchOrder) {
+          assert(V && "VSOList entry can not be null");
+          Unresolved = V->lookup(Q, std::move(Unresolved));
+        }
+      });
+      return Unresolved;
     };
 
-    auto InternedResult =
-        MR.getTargetVSO().withSearchOrderDo([&](const VSOList &VSOs) {
-          return ES.lookup(VSOs, InternedSymbols, RegisterDependencies, false);
-        });
+    auto InternedResult = blockingLookup(
+        ES, std::move(AsyncLookup), std::move(InternedSymbols), false, &MR);
 
     if (!InternedResult)
       return InternedResult.takeError();
@@ -45,8 +52,6 @@
   }
 
   Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) {
-    auto &ES = MR.getTargetVSO().getExecutionSession();
-
     SymbolNameSet InternedSymbols;
 
     for (auto &S : Symbols)
@@ -70,6 +75,7 @@
   }
 
 private:
+  ExecutionSession &ES;
   MaterializationResponsibility &MR;
 };
 
@@ -100,7 +106,7 @@
 
   auto MemoryManager = GetMemoryManager(K);
 
-  VSOSearchOrderResolver Resolver(R);
+  VSOSearchOrderResolver Resolver(ES, R);
   auto RTDyld = llvm::make_unique<RuntimeDyld>(*MemoryManager, Resolver);
   RTDyld->setProcessAllSections(ProcessAllSections);