[ORC] Rename SymbolSource to MaterializationUnit, and make the materialization
authorLang Hames <lhames@gmail.com>
Tue, 20 Mar 2018 03:49:29 +0000 (03:49 +0000)
committerLang Hames <lhames@gmail.com>
Tue, 20 Mar 2018 03:49:29 +0000 (03:49 +0000)
operation all-or-nothing, rather than allowing materialization on a per-symbol
basis.

This addresses a shortcoming of per-symbol materialization: If a
MaterializationUnit (/SymbolSource) wants to materialize more symbols than
requested (which is likely: most materializers will want to materialize whole
modules) then it needs a way to notify the symbol table about the extra symbols
being materialized. This process (checking what has been requested against what
is being provided and notifying the symbol table about the difference) has to
be repeated at every level of the JIT stack. Making materialization
all-or-nothing eliminates this issue, simplifying both materializer
implementations and the symbol table (VSO class) API. The cost is that
per-symbol materialization (e.g. for individual symbols in a module) now
requires multiple MaterializationUnits.

llvm-svn: 327946

llvm/include/llvm/ExecutionEngine/Orc/Core.h
llvm/lib/ExecutionEngine/Orc/Core.cpp
llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp
llvm/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp

index bddef0e..26fec8b 100644 (file)
@@ -157,22 +157,25 @@ createSymbolResolver(LookupFlagsFn &&LookupFlags, LookupFn &&Lookup) {
       std::forward<LookupFlagsFn>(LookupFlags), std::forward<LookupFn>(Lookup));
 }
 
-/// @brief Represents a source of symbol definitions which may be materialized
-///        (turned into data / code through some materialization process) or
-///        discarded (if the definition is overridden by a stronger one).
+/// @brief A MaterializationUnit represents a set of symbol definitions that can
+///        be materialized as a group, or individually discarded (when
+///        overriding definitions are encountered).
 ///
-/// SymbolSources 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 SymbolSource {
+/// 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 ~SymbolSource() {}
+  virtual ~MaterializationUnit() {}
 
-  /// @brief Implementations of this method should materialize the given
-  ///        symbols (plus any additional symbols required) by adding a
-  ///        Materializer to the ExecutionSession's MaterializationQueue.
-  virtual Error materialize(VSO &V, SymbolNameSet Symbols) = 0;
+  /// @brief Return the set of symbols that this source provides.
+  virtual SymbolFlagsMap getSymbols() = 0;
+
+  /// @brief Implementations of this method should materialize all symbols
+  ///        in the materialzation unit, except for those that have been
+  ///        previously discarded.
+  virtual Error materialize(VSO &V) = 0;
 
   /// @brief Implementations of this method should discard the given symbol
   ///        from the source (e.g. if the source is an LLVM IR Module and the
@@ -201,10 +204,12 @@ public:
 
   using SetDefinitionsResult =
       std::map<SymbolStringPtr, RelativeLinkageStrength>;
-  using SourceWorkMap = std::map<std::shared_ptr<SymbolSource>, SymbolNameSet>;
+
+  using MaterializationUnitList =
+      std::vector<std::unique_ptr<MaterializationUnit>>;
 
   struct LookupResult {
-    SourceWorkMap MaterializationWork;
+    MaterializationUnitList MaterializationUnits;
     SymbolNameSet UnresolvedSymbols;
   };
 
@@ -231,8 +236,7 @@ public:
   Error define(SymbolMap NewSymbols);
 
   /// @brief Adds the given symbols to the mapping as lazy symbols.
-  Error defineLazy(const SymbolFlagsMap &NewSymbols,
-                   std::shared_ptr<SymbolSource> Source);
+  Error defineLazy(std::unique_ptr<MaterializationUnit> Source);
 
   /// @brief Add the given symbol/address mappings to the dylib, but do not
   ///        mark the symbols as finalized yet.
@@ -265,50 +269,54 @@ public:
 private:
   class MaterializationInfo {
   public:
-    MaterializationInfo(JITSymbolFlags Flags,
-                        std::shared_ptr<SymbolSource> Query);
-    JITSymbolFlags getFlags() const;
-    JITTargetAddress getAddress() const;
-    void replaceWithSource(VSO &V, SymbolStringPtr Name,
-                           JITSymbolFlags NewFlags,
-                           std::shared_ptr<SymbolSource> NewSource);
-    std::shared_ptr<SymbolSource>
-    query(SymbolStringPtr Name, std::shared_ptr<AsynchronousSymbolQuery> Query);
-    void resolve(VSO &V, SymbolStringPtr Name, JITEvaluatedSymbol Sym);
-    void finalize();
+    using QueryList = std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
 
-  private:
-    JITSymbolFlags Flags;
-    JITTargetAddress Address = 0;
-    std::shared_ptr<SymbolSource> Source;
-    std::vector<std::shared_ptr<AsynchronousSymbolQuery>> PendingResolution;
-    std::vector<std::shared_ptr<AsynchronousSymbolQuery>> PendingFinalization;
+    MaterializationInfo(size_t SymbolsRemaining,
+                        std::unique_ptr<MaterializationUnit> MU);
+
+    uint64_t SymbolsRemaining;
+    std::unique_ptr<MaterializationUnit> MU;
+    SymbolMap Symbols;
+    std::map<SymbolStringPtr, QueryList> PendingResolution;
+    std::map<SymbolStringPtr, QueryList> PendingFinalization;
   };
 
+  using MaterializationInfoSet = std::set<std::unique_ptr<MaterializationInfo>>;
+
+  using MaterializationInfoIterator = MaterializationInfoSet::iterator;
+
   class SymbolTableEntry {
   public:
-    SymbolTableEntry(JITSymbolFlags Flags,
-                     std::shared_ptr<SymbolSource> Source);
+    SymbolTableEntry(JITSymbolFlags SymbolFlags,
+                     MaterializationInfoIterator MaterializationInfoItr);
     SymbolTableEntry(JITEvaluatedSymbol Sym);
     SymbolTableEntry(SymbolTableEntry &&Other);
     ~SymbolTableEntry();
+
+    SymbolTableEntry &operator=(JITEvaluatedSymbol Sym);
+
     JITSymbolFlags getFlags() const;
-    void replaceWithSource(VSO &V, SymbolStringPtr Name, JITSymbolFlags Flags,
-                           std::shared_ptr<SymbolSource> NewSource);
-    std::shared_ptr<SymbolSource>
+    void replaceWith(VSO &V, SymbolStringPtr Name, JITSymbolFlags Flags,
+                     MaterializationInfoIterator NewMaterializationInfoItr);
+    std::unique_ptr<MaterializationUnit>
     query(SymbolStringPtr Name, std::shared_ptr<AsynchronousSymbolQuery> Query);
     void resolve(VSO &V, SymbolStringPtr Name, JITEvaluatedSymbol Sym);
-    void finalize();
+    void finalize(VSO &V, SymbolStringPtr Name);
+    void discard(VSO &V, SymbolStringPtr Name);
 
   private:
+    void destroy();
+
     JITSymbolFlags Flags;
+    MaterializationInfoIterator MII;
     union {
       JITTargetAddress Address;
-      std::unique_ptr<MaterializationInfo> MatInfo;
+      MaterializationInfoIterator MaterializationInfoItr;
     };
   };
 
   std::map<SymbolStringPtr, SymbolTableEntry> Symbols;
+  MaterializationInfoSet MaterializationInfos;
 };
 
 /// @brief An ExecutionSession represents a running JIT program.
@@ -350,15 +358,14 @@ public:
   ErrorReporter ReportError = logErrorsToStdErr;
 };
 
-/// Runs SymbolSource materializations on the current thread and reports errors
-/// to the given ExecutionSession.
+/// Runs Materializers on the current thread and reports errors to the given
+/// ExecutionSession.
 class MaterializeOnCurrentThread {
 public:
   MaterializeOnCurrentThread(ExecutionSession &ES) : ES(ES) {}
 
-  void operator()(VSO &V, std::shared_ptr<SymbolSource> Source,
-                  SymbolNameSet Names) {
-    if (auto Err = Source->materialize(V, std::move(Names)))
+  void operator()(VSO &V, std::unique_ptr<MaterializationUnit> MU) {
+    if (auto Err = MU->materialize(V))
       ES.reportError(std::move(Err));
   }
 
@@ -367,8 +374,8 @@ private:
 };
 
 /// Materialization function object wrapper for the lookup method.
-using MaterializationDispatcher = std::function<void(
-    VSO &V, std::shared_ptr<SymbolSource> S, SymbolNameSet Names)>;
+using MaterializationDispatcher =
+    std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> S)>;
 
 /// @brief Look up a set of symbols by searching a list of VSOs.
 ///
index 19ca781..cb8304b 100644 (file)
@@ -1,4 +1,4 @@
-//===--------- Core.cpp - Core ORC APIs (SymbolSource, VSO, etc.) ---------===//
+//===----- Core.cpp - Core ORC APIs (MaterializationUnit, VSO, etc.) ------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -17,8 +17,8 @@
 namespace llvm {
 namespace orc {
 
+void MaterializationUnit::anchor() {}
 void SymbolResolver::anchor() {}
-void SymbolSource::anchor() {}
 
 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
     const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
@@ -69,68 +69,13 @@ void AsynchronousSymbolQuery::notifySymbolFinalized() {
 }
 
 VSO::MaterializationInfo::MaterializationInfo(
-    JITSymbolFlags Flags, std::shared_ptr<SymbolSource> Source)
-    : Flags(std::move(Flags)), Source(std::move(Source)) {}
+    size_t SymbolsRemaining, std::unique_ptr<MaterializationUnit> MU)
+    : SymbolsRemaining(SymbolsRemaining), MU(std::move(MU)) {}
 
-JITSymbolFlags VSO::MaterializationInfo::getFlags() const { return Flags; }
-
-JITTargetAddress VSO::MaterializationInfo::getAddress() const {
-  return Address;
-}
-
-void VSO::MaterializationInfo::replaceWithSource(
-    VSO &V, SymbolStringPtr Name, JITSymbolFlags NewFlags,
-    std::shared_ptr<SymbolSource> NewSource) {
-  assert(Address == 0 && PendingResolution.empty() &&
-         PendingFinalization.empty() &&
-         "Cannot replace source during or after materialization");
-  Source->discard(V, Name);
-  Flags = std::move(NewFlags);
-  Source = std::move(NewSource);
-}
-
-std::shared_ptr<SymbolSource> VSO::MaterializationInfo::query(
-    SymbolStringPtr Name, std::shared_ptr<AsynchronousSymbolQuery> Query) {
-  if (Address == 0) {
-    PendingResolution.push_back(std::move(Query));
-    auto S = std::move(Source);
-    Source = nullptr;
-    return S;
-  }
-
-  Query->setDefinition(Name, JITEvaluatedSymbol(Address, Flags));
-  PendingFinalization.push_back(std::move(Query));
-  return nullptr;
-}
-
-void VSO::MaterializationInfo::resolve(VSO &V, SymbolStringPtr Name,
-                                       JITEvaluatedSymbol Sym) {
-  if (Source) {
-    Source->discard(V, Name);
-    Source = nullptr;
-  }
-
-  // FIXME: Sanity check flags?
-  Flags = Sym.getFlags();
-  Address = Sym.getAddress();
-  for (auto &Query : PendingResolution) {
-    Query->setDefinition(Name, std::move(Sym));
-    PendingFinalization.push_back(std::move(Query));
-  }
-  PendingResolution = {};
-}
-
-void VSO::MaterializationInfo::finalize() {
-  for (auto &Query : PendingFinalization)
-    Query->notifySymbolFinalized();
-  PendingFinalization = {};
-}
-
-VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags,
-                                        std::shared_ptr<SymbolSource> Source)
+VSO::SymbolTableEntry::SymbolTableEntry(
+    JITSymbolFlags Flags, MaterializationInfoIterator MaterializationInfoItr)
     : Flags(JITSymbolFlags::FlagNames(Flags | JITSymbolFlags::NotMaterialized)),
-      MatInfo(
-          llvm::make_unique<MaterializationInfo>(Flags, std::move(Source))) {
+      MaterializationInfoItr(std::move(MaterializationInfoItr)) {
   // FIXME: Assert flag sanity.
 }
 
@@ -144,37 +89,83 @@ VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other)
   if (Flags.isMaterialized())
     Address = Other.Address;
   else
-    MatInfo = std::move(Other.MatInfo);
+    MaterializationInfoItr = std::move(Other.MaterializationInfoItr);
 }
 
-VSO::SymbolTableEntry::~SymbolTableEntry() {
+VSO::SymbolTableEntry::~SymbolTableEntry() { destroy(); }
+
+VSO::SymbolTableEntry &VSO::SymbolTableEntry::
+operator=(JITEvaluatedSymbol Sym) {
+  destroy();
+  Flags = Sym.getFlags();
+  Address = Sym.getAddress();
+  return *this;
+}
+
+void VSO::SymbolTableEntry::destroy() {
   if (!Flags.isMaterialized())
-    MatInfo.std::unique_ptr<MaterializationInfo>::~unique_ptr();
+    MaterializationInfoItr
+        .MaterializationInfoIterator::~MaterializationInfoIterator();
 }
 
 JITSymbolFlags VSO::SymbolTableEntry::getFlags() const { return Flags; }
 
-void VSO::SymbolTableEntry::replaceWithSource(
+void VSO::SymbolTableEntry::replaceWith(
     VSO &V, SymbolStringPtr Name, JITSymbolFlags NewFlags,
-    std::shared_ptr<SymbolSource> NewSource) {
-  bool ReplaceExisting = !Flags.isMaterialized();
+    MaterializationInfoIterator NewMaterializationInfoItr) {
+  bool ReplaceExistingLazyDefinition = !Flags.isMaterialized();
   Flags = NewFlags;
-  if (ReplaceExisting)
-    MatInfo->replaceWithSource(V, Name, Flags, std::move(NewSource));
-  else
-    new (&MatInfo) std::unique_ptr<MaterializationInfo>(
-        llvm::make_unique<MaterializationInfo>(Flags, std::move(NewSource)));
+  if (ReplaceExistingLazyDefinition) {
+    // If we are replacing an existing lazy definition with a stronger one,
+    // we need to notify the old lazy definition to discard its definition.
+    assert((*MaterializationInfoItr)->MU != nullptr &&
+           (*MaterializationInfoItr)->Symbols.count(Name) == 0 &&
+           (*MaterializationInfoItr)->PendingResolution.count(Name) == 0 &&
+           (*MaterializationInfoItr)->PendingFinalization.count(Name) == 0 &&
+           "Attempt to replace materializer during materialization");
+
+    if (--(*MaterializationInfoItr)->SymbolsRemaining == 0)
+      V.MaterializationInfos.erase(MaterializationInfoItr);
+  }
+  MaterializationInfoItr = std::move(NewMaterializationInfoItr);
 }
 
-std::shared_ptr<SymbolSource>
+std::unique_ptr<MaterializationUnit>
 VSO::SymbolTableEntry::query(SymbolStringPtr Name,
                              std::shared_ptr<AsynchronousSymbolQuery> Query) {
   if (Flags.isMaterialized()) {
     Query->setDefinition(std::move(Name), JITEvaluatedSymbol(Address, Flags));
     Query->notifySymbolFinalized();
     return nullptr;
-  } else
-    return MatInfo->query(std::move(Name), std::move(Query));
+  } else {
+    if ((*MaterializationInfoItr)->MU) {
+      assert((*MaterializationInfoItr)->PendingResolution.count(Name) == 0 &&
+             (*MaterializationInfoItr)->PendingFinalization.count(Name) == 0 &&
+             "Materializer should have been activated on first query");
+      (*MaterializationInfoItr)
+          ->PendingResolution[Name]
+          .push_back(std::move(Query));
+      return std::move((*MaterializationInfoItr)->MU);
+    } else {
+      assert((*MaterializationInfoItr)->MU == nullptr &&
+             "Materializer should have been activated on first query");
+      auto SymValueItr = (*MaterializationInfoItr)->Symbols.find(Name);
+      if (SymValueItr == (*MaterializationInfoItr)->Symbols.end()) {
+        // Symbol has not been resolved yet.
+        (*MaterializationInfoItr)
+            ->PendingResolution[Name]
+            .push_back(std::move(Query));
+        return nullptr;
+      } else {
+        // Symbol has already resolved, is just waiting on finalization.
+        Query->setDefinition(Name, SymValueItr->second);
+        (*MaterializationInfoItr)
+            ->PendingFinalization[Name]
+            .push_back(std::move(Query));
+        return nullptr;
+      }
+    }
+  }
 }
 
 void VSO::SymbolTableEntry::resolve(VSO &V, SymbolStringPtr Name,
@@ -185,22 +176,69 @@ void VSO::SymbolTableEntry::resolve(VSO &V, SymbolStringPtr Name,
     //        in VSO?
     Flags = Sym.getFlags();
     Address = Sym.getAddress();
-  } else
-    MatInfo->resolve(V, std::move(Name), std::move(Sym));
+  } else {
+    assert((*MaterializationInfoItr)->MU == nullptr &&
+           "Can not resolve a symbol that has not been materialized");
+    assert((*MaterializationInfoItr)->Symbols.count(Name) == 0 &&
+           "Symbol resolved more than once");
+
+    // Add the symbol to the MaterializationInfo Symbols table.
+    (*MaterializationInfoItr)->Symbols[Name] = Sym;
+
+    // If there are any queries waiting on this symbol then notify them that it
+    // has been resolved, then move them to the PendingFinalization list.
+    auto I = (*MaterializationInfoItr)->PendingResolution.find(Name);
+    if (I != (*MaterializationInfoItr)->PendingResolution.end()) {
+      assert((*MaterializationInfoItr)->PendingFinalization.count(Name) == 0 &&
+             "Queries already pending finalization on newly resolved symbol");
+      auto &PendingFinalization =
+          (*MaterializationInfoItr)->PendingFinalization[Name];
+
+      for (auto &Query : I->second) {
+        Query->setDefinition(Name, Sym);
+        PendingFinalization.push_back(Query);
+      }
+
+      // Clear the PendingResolution list for this symbol.
+      (*MaterializationInfoItr)->PendingResolution.erase(I);
+    }
+  }
 }
 
-void VSO::SymbolTableEntry::finalize() {
+void VSO::SymbolTableEntry::finalize(VSO &V, SymbolStringPtr Name) {
   if (!Flags.isMaterialized()) {
-    auto TmpMatInfo = std::move(MatInfo);
-    MatInfo.std::unique_ptr<MaterializationInfo>::~unique_ptr();
-    // FIXME: Assert flag sanity?
-    Flags = TmpMatInfo->getFlags();
-    Address = TmpMatInfo->getAddress();
-    TmpMatInfo->finalize();
+    auto SymI = (*MaterializationInfoItr)->Symbols.find(Name);
+    assert(SymI != (*MaterializationInfoItr)->Symbols.end() &&
+           "Finalizing an unresolved symbol");
+    auto Sym = SymI->second;
+    (*MaterializationInfoItr)->Symbols.erase(SymI);
+    auto I = (*MaterializationInfoItr)->PendingFinalization.find(Name);
+    if (I != (*MaterializationInfoItr)->PendingFinalization.end()) {
+      for (auto &Query : I->second)
+        Query->notifySymbolFinalized();
+      (*MaterializationInfoItr)->PendingFinalization.erase(I);
+    }
+
+    if (--(*MaterializationInfoItr)->SymbolsRemaining == 0)
+      V.MaterializationInfos.erase(MaterializationInfoItr);
+
+    // Destruct the iterator and re-define this entry using the final symbol
+    // value.
+    MaterializationInfoItr
+        .MaterializationInfoIterator::~MaterializationInfoIterator();
+    Flags = Sym.getFlags();
+    Address = Sym.getAddress();
   }
   assert(Flags.isMaterialized() && "Trying to finalize not-emitted symbol");
 }
 
+void VSO::SymbolTableEntry::discard(VSO &V, SymbolStringPtr Name) {
+  assert((*MaterializationInfoItr)->MU != nullptr &&
+         "Can not override a symbol after it has been materialized");
+  (*MaterializationInfoItr)->MU->discard(V, Name);
+  --(*MaterializationInfoItr)->SymbolsRemaining;
+}
+
 VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old,
                                                  JITSymbolFlags New) {
   if (Old == None)
@@ -249,16 +287,25 @@ Error VSO::define(SymbolMap NewSymbols) {
     }
 
     if (I != Symbols.end()) {
-      I->second.resolve(*this, KV.first, std::move(KV.second));
-      I->second.finalize();
+      // This is an override -- discard the overridden definition and overwrite.
+      I->second.discard(*this, KV.first);
+      I->second = std::move(KV.second);
     } else
       Symbols.insert(std::make_pair(KV.first, std::move(KV.second)));
   }
   return Err;
 }
 
-Error VSO::defineLazy(const SymbolFlagsMap &NewSymbols,
-                      std::shared_ptr<SymbolSource> Source) {
+Error VSO::defineLazy(std::unique_ptr<MaterializationUnit> MU) {
+
+  auto NewSymbols = MU->getSymbols();
+
+  auto MaterializationInfoItr =
+      MaterializationInfos
+          .insert(llvm::make_unique<MaterializationInfo>(NewSymbols.size(),
+                                                         std::move(MU)))
+          .first;
+
   Error Err = Error::success();
   for (auto &KV : NewSymbols) {
     auto I = Symbols.find(KV.first);
@@ -269,22 +316,38 @@ Error VSO::defineLazy(const SymbolFlagsMap &NewSymbols,
         KV.second);
 
     // Discard weaker definitions.
-    if (LinkageResult == ExistingDefinitionIsStronger)
-      Source->discard(*this, KV.first);
+    if (LinkageResult == ExistingDefinitionIsStronger) {
+      (*MaterializationInfoItr)->MU->discard(*this, KV.first);
+      assert((*MaterializationInfoItr)->SymbolsRemaining > 0 &&
+             "Discarding non-existant symbols?");
+      --(*MaterializationInfoItr)->SymbolsRemaining;
+      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.
+      assert((*MaterializationInfoItr)->SymbolsRemaining > 0 &&
+             "Discarding non-existant symbols?");
+      --(*MaterializationInfoItr)->SymbolsRemaining;
       continue;
     }
 
     if (I != Symbols.end())
-      I->second.replaceWithSource(*this, KV.first, KV.second, Source);
+      I->second.replaceWith(*this, KV.first, KV.second, MaterializationInfoItr);
     else
-      Symbols.emplace(
-          std::make_pair(KV.first, SymbolTableEntry(KV.second, Source)));
+      Symbols.emplace(std::make_pair(
+          KV.first, SymbolTableEntry(KV.second, MaterializationInfoItr)));
   }
+
+  // If we ended up overriding all definitions in this materializer then delete
+  // it.
+  if ((*MaterializationInfoItr)->SymbolsRemaining == 0)
+    MaterializationInfos.erase(MaterializationInfoItr);
+
   return Err;
 }
 
@@ -300,7 +363,7 @@ void VSO::finalize(SymbolNameSet SymbolsToFinalize) {
   for (auto &S : SymbolsToFinalize) {
     auto I = Symbols.find(S);
     assert(I != Symbols.end() && "Finalizing symbol not present in this dylib");
-    I->second.finalize();
+    I->second.finalize(*this, S);
   }
 }
 
@@ -325,7 +388,7 @@ SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Names) {
 
 VSO::LookupResult VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
                               SymbolNameSet Names) {
-  SourceWorkMap MaterializationWork;
+  MaterializationUnitList MaterializationUnits;
 
   for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) {
     auto Tmp = I++;
@@ -341,11 +404,11 @@ VSO::LookupResult VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
     // Forward the query to the given SymbolTableEntry, and if it return a
     // layer to perform materialization with, add that to the
     // MaterializationWork map.
-    if (auto Source = SymI->second.query(SymI->first, Query))
-      MaterializationWork[Source].insert(SymI->first);
+    if (auto MU = SymI->second.query(SymI->first, Query))
+      MaterializationUnits.push_back(std::move(MU));
   }
 
-  return {std::move(MaterializationWork), std::move(Names)};
+  return {std::move(MaterializationUnits), std::move(Names)};
 }
 
 Expected<SymbolMap> lookup(const std::vector<VSO *> &VSOs, SymbolNameSet Names,
@@ -400,24 +463,17 @@ Expected<SymbolMap> lookup(const std::vector<VSO *> &VSOs, SymbolNameSet Names,
       Names, std::move(OnResolve), std::move(OnReady));
   SymbolNameSet UnresolvedSymbols(std::move(Names));
 
-  for (auto *VSO : VSOs) {
+  for (auto *V : VSOs) {
 
     if (UnresolvedSymbols.empty())
       break;
 
-    assert(VSO && "VSO pointers in VSOs list should be non-null");
-    auto LR = VSO->lookup(Query, UnresolvedSymbols);
+    assert(V && "VSO pointers in VSOs list should be non-null");
+    auto LR = V->lookup(Query, UnresolvedSymbols);
     UnresolvedSymbols = std::move(LR.UnresolvedSymbols);
 
-    for (auto I = LR.MaterializationWork.begin(),
-              E = LR.MaterializationWork.end();
-         I != E;) {
-      auto Tmp = I++;
-      std::shared_ptr<SymbolSource> Source = Tmp->first;
-      SymbolNameSet Names = std::move(Tmp->second);
-      LR.MaterializationWork.erase(Tmp);
-      DispatchMaterialization(*VSO, std::move(Source), std::move(Names));
-    }
+    for (auto &MU : LR.MaterializationUnits)
+      DispatchMaterialization(*V, std::move(MU));
   }
 
 #if LLVM_ENABLE_THREADS
index 5a74246..d37596e 100644 (file)
@@ -19,23 +19,28 @@ using namespace llvm::orc;
 
 namespace {
 
-class SimpleSource : public SymbolSource {
+class SimpleMaterializationUnit : public MaterializationUnit {
 public:
-  using MaterializeFunction = std::function<Error(VSO &, SymbolNameSet)>;
+  using GetSymbolsFunction = std::function<SymbolFlagsMap()>;
+  using MaterializeFunction = std::function<Error(VSO &)>;
   using DiscardFunction = std::function<void(VSO &, SymbolStringPtr)>;
 
-  SimpleSource(MaterializeFunction Materialize, DiscardFunction Discard)
-      : Materialize(std::move(Materialize)), Discard(std::move(Discard)) {}
+  SimpleMaterializationUnit(GetSymbolsFunction GetSymbols,
+                            MaterializeFunction Materialize,
+                            DiscardFunction Discard)
+      : GetSymbols(std::move(GetSymbols)), Materialize(std::move(Materialize)),
+        Discard(std::move(Discard)) {}
 
-  Error materialize(VSO &V, SymbolNameSet Symbols) override {
-    return Materialize(V, std::move(Symbols));
-  }
+  SymbolFlagsMap getSymbols() override { return GetSymbols(); }
+
+  Error materialize(VSO &V) override { return Materialize(V); }
 
   void discard(VSO &V, SymbolStringPtr Name) override {
     Discard(V, std::move(Name));
   }
 
 private:
+  GetSymbolsFunction GetSymbols;
   MaterializeFunction Materialize;
   DiscardFunction Discard;
 };
@@ -142,26 +147,28 @@ TEST(CoreAPIsTest, LookupFlagsTest) {
   auto Bar = SP.intern("bar");
   auto Baz = SP.intern("baz");
 
+  JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
+  JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>(
+      JITSymbolFlags::Exported | JITSymbolFlags::Weak);
+
   VSO V;
 
-  auto Source = std::make_shared<SimpleSource>(
-      [](VSO &V, SymbolNameSet Symbols) -> Error {
+  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
+      [=]() {
+        return SymbolFlagsMap({{Bar, BarFlags}});
+      },
+      [](VSO &V) -> Error {
         llvm_unreachable("Symbol materialized on flags lookup");
       },
       [](VSO &V, SymbolStringPtr Name) -> Error {
         llvm_unreachable("Symbol finalized on flags lookup");
       });
 
-  JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
-  JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>(
-      JITSymbolFlags::Exported | JITSymbolFlags::Weak);
-
   SymbolMap InitialDefs;
   InitialDefs[Foo] = JITEvaluatedSymbol(0xdeadbeef, FooFlags);
   cantFail(V.define(std::move(InitialDefs)));
 
-  SymbolFlagsMap InitialLazyDefs({{Bar, BarFlags}});
-  cantFail(V.defineLazy(InitialLazyDefs, Source));
+  cantFail(V.defineLazy(std::move(MU)));
 
   SymbolNameSet Names({Foo, Bar, Baz});
 
@@ -193,12 +200,15 @@ TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
 
   VSO V;
 
-  auto Source = std::make_shared<SimpleSource>(
-      [&](VSO &V, SymbolNameSet Symbols) {
-        EXPECT_EQ(Symbols.size(), 1U)
-            << "Expected Symbols set size to be 1 ({ Foo })";
-        EXPECT_EQ(*Symbols.begin(), Foo) << "Expected Symbols == { Foo }";
-
+  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
+      [=]() {
+        return SymbolFlagsMap(
+            {{Foo, JITSymbolFlags::Exported},
+             {Bar, static_cast<JITSymbolFlags::FlagNames>(
+                       JITSymbolFlags::Exported | JITSymbolFlags::Weak)}});
+      },
+      [&](VSO &V) {
+        assert(BarDiscarded && "Bar should have been discarded by this point");
         SymbolMap SymbolsToResolve;
         SymbolsToResolve[Foo] =
             JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
@@ -214,11 +224,7 @@ TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
         BarDiscarded = true;
       });
 
-  SymbolFlagsMap InitialSymbols(
-      {{Foo, JITSymbolFlags::Exported},
-       {Bar, static_cast<JITSymbolFlags::FlagNames>(JITSymbolFlags::Exported |
-                                                    JITSymbolFlags::Weak)}});
-  cantFail(V.defineLazy(InitialSymbols, Source));
+  cantFail(V.defineLazy(std::move(MU)));
 
   SymbolMap BarOverride;
   BarOverride[Bar] = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
@@ -248,8 +254,8 @@ TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
 
   auto LR = V.lookup(std::move(Q), Names);
 
-  for (auto &SWKV : LR.MaterializationWork)
-    cantFail(SWKV.first->materialize(V, std::move(SWKV.second)));
+  for (auto &SWKV : LR.MaterializationUnits)
+    cantFail(SWKV->materialize(V));
 
   EXPECT_TRUE(LR.UnresolvedSymbols.empty()) << "Could not find Foo in dylib";
   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
@@ -276,9 +282,8 @@ TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
       },
       [&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) {
         auto LR = V.lookup(std::move(Q), Symbols);
-        assert(LR.MaterializationWork.empty() &&
-               "Test generated unexpected materialization "
-               "work?");
+        assert(LR.MaterializationUnits.empty() &&
+               "Test generated unexpected materialization work?");
         return std::move(LR.UnresolvedSymbols);
       });
 
@@ -333,8 +338,11 @@ TEST(CoreAPIsTest, TestLookupWithUnthreadedMaterialization) {
   SymbolStringPool SSP;
   auto Foo = SSP.intern("foo");
 
-  auto Source = std::make_shared<SimpleSource>(
-      [&](VSO &V, SymbolNameSet Symbols) -> Error {
+  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
+      [=]() {
+        return SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}});
+      },
+      [&](VSO &V) -> Error {
         V.resolve({{Foo, FooSym}});
         V.finalize({Foo});
         return Error::success();
@@ -345,8 +353,7 @@ TEST(CoreAPIsTest, TestLookupWithUnthreadedMaterialization) {
 
   VSO V;
 
-  SymbolFlagsMap InitialSymbols({{Foo, JITSymbolFlags::Exported}});
-  cantFail(V.defineLazy(InitialSymbols, Source));
+  cantFail(V.defineLazy(std::move(MU)));
 
   ExecutionSession ES(SSP);
   auto FooLookupResult =
@@ -366,8 +373,11 @@ TEST(CoreAPIsTest, TestLookupWithThreadedMaterialization) {
   SymbolStringPool SSP;
   auto Foo = SSP.intern("foo");
 
-  auto Source = std::make_shared<SimpleSource>(
-      [&](VSO &V, SymbolNameSet Symbols) -> Error {
+  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
+      [=]() {
+        return SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}});
+      },
+      [&](VSO &V) -> Error {
         V.resolve({{Foo, FooSym}});
         V.finalize({Foo});
         return Error::success();
@@ -378,19 +388,20 @@ TEST(CoreAPIsTest, TestLookupWithThreadedMaterialization) {
 
   VSO V;
 
-  SymbolFlagsMap InitialSymbols({{Foo, JITSymbolFlags::Exported}});
-  cantFail(V.defineLazy(InitialSymbols, Source));
+  cantFail(V.defineLazy(std::move(MU)));
 
   ExecutionSession ES(SSP);
 
-  auto MaterializeOnNewThread =
-    [&ES](VSO &V, std::shared_ptr<SymbolSource> Source, SymbolNameSet Names) {
-      std::thread(
-        [&ES, &V, Source, Names]() {
-          if (auto Err = Source->materialize(V, std::move(Names)))
-            ES.reportError(std::move(Err));
-        }).detach();
-    };
+  auto MaterializeOnNewThread = [&ES](VSO &V,
+                                      std::unique_ptr<MaterializationUnit> MU) {
+    // FIXME: Use move capture once we move to C++14.
+    std::shared_ptr<MaterializationUnit> SharedMU = std::move(MU);
+    std::thread([&ES, &V, SharedMU]() {
+      if (auto Err = SharedMU->materialize(V))
+        ES.reportError(std::move(Err));
+    })
+        .detach();
+  };
 
   auto FooLookupResult =
     cantFail(lookup({&V}, Foo, MaterializeOnNewThread));
index 9fce90f..6c7384a 100644 (file)
@@ -36,7 +36,7 @@ TEST(LegacyAPIInteropTest, QueryAgainstVSO) {
   auto Lookup = [&](std::shared_ptr<AsynchronousSymbolQuery> Query,
                     SymbolNameSet Symbols) {
     auto R = V.lookup(std::move(Query), Symbols);
-    EXPECT_TRUE(R.MaterializationWork.empty())
+    EXPECT_TRUE(R.MaterializationUnits.empty())
         << "Query resulted in unexpected materialization work";
     return std::move(R.UnresolvedSymbols);
   };