[llvm] r329934 - [ORC] Plumb error notifications through the VSO interface.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 12 11:35:08 PDT 2018


Author: lhames
Date: Thu Apr 12 11:35:08 2018
New Revision: 329934

URL: http://llvm.org/viewvc/llvm-project?rev=329934&view=rev
Log:
[ORC] Plumb error notifications through the VSO interface.

This allows materializers to notify the VSO that they were unable to
resolve or finalize symbols.

Modified:
    llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h
    llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h
    llvm/trunk/include/llvm/ExecutionEngine/Orc/Legacy.h
    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h
    llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp
    llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
    llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp
    llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
    llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp

Modified: llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h?rev=329934&r1=329933&r2=329934&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h Thu Apr 12 11:35:08 2018
@@ -52,11 +52,12 @@ public:
     Common = 1U << 2,
     Absolute = 1U << 3,
     Exported = 1U << 4,
-    NotMaterialized = 1U << 5
+    Lazy = 1U << 5,
+    Materializing = 1U << 6
   };
 
   static JITSymbolFlags stripTransientFlags(JITSymbolFlags Orig) {
-    return static_cast<FlagNames>(Orig.Flags & ~NotMaterialized);
+    return static_cast<FlagNames>(Orig.Flags & ~Lazy & ~Materializing);
   }
 
   /// @brief Default-construct a JITSymbolFlags instance.
@@ -75,9 +76,18 @@ public:
     return (Flags & HasError) == HasError;
   }
 
-  /// @brief Returns true if this symbol has been fully materialized (i.e. is
-  ///        callable).
-  bool isMaterialized() const { return !(Flags & NotMaterialized); }
+  /// @brief Returns true if this is a lazy symbol.
+  ///        This flag is used internally by the JIT APIs to track
+  ///        materialization states.
+  bool isLazy() const { return Flags & Lazy; }
+
+  /// @brief Returns true if this symbol is in the process of being
+  ///        materialized.
+  bool isMaterializing() const { return Flags & Materializing; }
+
+  /// @brief Returns true if this symbol is fully materialized.
+  ///        (i.e. neither lazy, nor materializing).
+  bool isMaterialized() const { return !(Flags & (Lazy | Materializing)); }
 
   /// @brief Returns true if the Weak flag is set.
   bool isWeak() const {

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=329934&r1=329933&r2=329934&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h Thu Apr 12 11:35:08 2018
@@ -17,6 +17,7 @@
 #include "llvm/ExecutionEngine/JITSymbol.h"
 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
 
+#include <list>
 #include <map>
 #include <memory>
 #include <set>
@@ -25,23 +26,71 @@
 namespace llvm {
 namespace orc {
 
+// Forward declare some classes.
+class VSO;
+
 /// VModuleKey provides a unique identifier (allocated and managed by
 /// ExecutionSessions) for a module added to the JIT.
 using VModuleKey = uint64_t;
 
-class VSO;
-
 /// @brief A set of symbol names (represented by SymbolStringPtrs for
 //         efficiency).
 using SymbolNameSet = std::set<SymbolStringPtr>;
 
+/// @brief Render a SymbolNameSet to an ostream.
+raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
+
 /// @brief A map from symbol names (as SymbolStringPtrs) to JITSymbols
 ///        (address/flags pairs).
 using SymbolMap = std::map<SymbolStringPtr, JITEvaluatedSymbol>;
 
+/// @brief Render a SymbolMap to an ostream.
+raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
+
 /// @brief A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
 using SymbolFlagsMap = std::map<SymbolStringPtr, JITSymbolFlags>;
 
+/// @brief Render a SymbolMap to an ostream.
+raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &Symbols);
+
+/// @brief 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;
+  virtual const SymbolNameSet &getSymbols() const = 0;
+};
+
+/// @brief Used to notify a VSO that the given set of symbols failed to resolve.
+class FailedToResolve : public ErrorInfo<FailedToResolve, FailedToMaterialize> {
+public:
+  static char ID;
+
+  FailedToResolve(SymbolNameSet Symbols);
+  std::error_code convertToErrorCode() const override;
+  void log(raw_ostream &OS) const override;
+  const SymbolNameSet &getSymbols() const override { return Symbols; }
+
+private:
+  SymbolNameSet Symbols;
+};
+
+/// @brief Used to notify a VSO that the given set of symbols failed to
+/// finalize.
+class FailedToFinalize
+    : public ErrorInfo<FailedToFinalize, FailedToMaterialize> {
+public:
+  static char ID;
+
+  FailedToFinalize(SymbolNameSet Symbols);
+  std::error_code convertToErrorCode() const override;
+  void log(raw_ostream &OS) const override;
+  const SymbolNameSet &getSymbols() const override { return Symbols; }
+
+private:
+  SymbolNameSet Symbols;
+};
+
 /// @brief A symbol query that returns results via a callback when results are
 ///        ready.
 ///
@@ -69,20 +118,20 @@ public:
   /// notify-finalized callback is called with the given error.
   ///
   /// It is illegal to call setFailed after both callbacks have been made.
-  void setFailed(Error Err);
+  void notifyFailed(Error Err);
 
   /// @brief Set the resolved symbol information for the given symbol name.
   ///
   /// 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 setDefinition(SymbolStringPtr Name, JITEvaluatedSymbol Sym);
+  void resolve(SymbolStringPtr Name, JITEvaluatedSymbol Sym);
 
   /// @brief Notify the query that a requested symbol is ready for execution.
   ///
   /// 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 notifySymbolFinalized();
+  void finalizeSymbol();
 
 private:
   SymbolMap Symbols;
@@ -240,10 +289,16 @@ public:
 
   /// @brief Add the given symbol/address mappings to the dylib, but do not
   ///        mark the symbols as finalized yet.
-  void resolve(SymbolMap SymbolValues);
+  void resolve(const SymbolMap &SymbolValues);
+
+  /// @brief Notify the VSO that the given symbols failed to finalize.
+  void notifyResolutionFailed(const SymbolNameSet &Names);
 
   /// @brief Finalize the given symbols.
-  void finalize(SymbolNameSet SymbolsToFinalize);
+  void finalize(const SymbolNameSet &SymbolsToFinalize);
+
+  /// @brief Notify the VSO that the given symbols failed to finalize.
+  void notifyFinalizationFailed(const SymbolNameSet &Names);
 
   /// @brief Look up the flags for the given symbols.
   ///
@@ -267,56 +322,72 @@ public:
                       SymbolNameSet Symbols);
 
 private:
-  class MaterializationInfo {
+  class UnmaterializedInfo {
   public:
-    using QueryList = std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
-
-    MaterializationInfo(size_t SymbolsRemaining,
-                        std::unique_ptr<MaterializationUnit> MU);
+    UnmaterializedInfo(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 UnmaterializedInfoList = std::list<UnmaterializedInfo>;
+
+  using UnmaterializedInfoIterator = UnmaterializedInfoList::iterator;
+
+  class MaterializingInfo {
+  public:
+    using QueryList = std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
+
+    QueryList PendingResolution;
+    QueryList PendingFinalization;
+  };
 
-  using MaterializationInfoIterator = MaterializationInfoSet::iterator;
+  using MaterializingInfoMap = std::map<SymbolStringPtr, MaterializingInfo>;
+
+  using MaterializingInfoIterator = MaterializingInfoMap::iterator;
 
   class SymbolTableEntry {
   public:
     SymbolTableEntry(JITSymbolFlags SymbolFlags,
-                     MaterializationInfoIterator MaterializationInfoItr);
+                     UnmaterializedInfoIterator UnmaterializedInfoItr);
     SymbolTableEntry(JITEvaluatedSymbol Sym);
-    SymbolTableEntry(SymbolTableEntry &&Other);
+    //     SymbolTableEntry(SymbolTableEntry &&Other);
+    //     SymbolTableEntry &operator=(SymbolTableEntry &&Other);
     ~SymbolTableEntry();
 
-    SymbolTableEntry &operator=(JITEvaluatedSymbol Sym);
+    // Change definition due to override. Only usable prior to materialization.
+    void replaceWith(VSO &V, SymbolStringPtr Name, JITEvaluatedSymbol Sym);
 
-    JITSymbolFlags getFlags() const;
+    // Change definition due to override. Only usable prior to materialization.
     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(VSO &V, SymbolStringPtr Name);
-    void discard(VSO &V, SymbolStringPtr Name);
+                     UnmaterializedInfoIterator NewUMII);
 
-  private:
-    void destroy();
+    // Move entry to materializing state, detach from UMII.
+    std::unique_ptr<MaterializationUnit> initMaterialize(VSO &V);
+
+    // Move entry to resolved state.
+    void resolve(VSO &V, JITEvaluatedSymbol Sym);
+
+    // Move entry to finalized state.
+    void finalize();
 
     JITSymbolFlags Flags;
-    MaterializationInfoIterator MII;
+
     union {
       JITTargetAddress Address;
-      MaterializationInfoIterator MaterializationInfoItr;
+      UnmaterializedInfoIterator UMII;
     };
+
+  private:
+    void destroy();
   };
 
+  void detach(UnmaterializedInfoIterator UMII);
+
   std::map<SymbolStringPtr, SymbolTableEntry> Symbols;
-  MaterializationInfoSet MaterializationInfos;
+  UnmaterializedInfoList UnmaterializedInfos;
+  MaterializingInfoMap MaterializingInfos;
 };
 
 /// @brief An ExecutionSession represents a running JIT program.

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=329934&r1=329933&r2=329934&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/Legacy.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/Legacy.h Thu Apr 12 11:35:08 2018
@@ -62,7 +62,7 @@ Expected<SymbolNameSet> lookupFlagsWithL
 ///        takes a const std::string& or StringRef and returns a JITSymbol) to
 ///        find the address and flags for each symbol in Symbols and store the
 ///        result in Query. If any JITSymbol returned by FindSymbol is in an
-///        error then Query.setFailed(...) is called with that error and the
+///        error then Query.notifyFailed(...) is called with that error and the
 ///        function returns immediately. On success, returns the set of symbols
 ///        not found.
 ///
@@ -76,14 +76,14 @@ SymbolNameSet lookupWithLegacyFn(Asynchr
   for (auto &S : Symbols) {
     if (JITSymbol Sym = FindSymbol(*S)) {
       if (auto Addr = Sym.getAddress()) {
-        Query.setDefinition(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
-        Query.notifySymbolFinalized();
+        Query.resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
+        Query.finalizeSymbol();
       } else {
-        Query.setFailed(Addr.takeError());
+        Query.notifyFailed(Addr.takeError());
         return SymbolNameSet();
       }
     } else if (auto Err = Sym.takeError()) {
-      Query.setFailed(std::move(Err));
+      Query.notifyFailed(std::move(Err));
       return SymbolNameSet();
     } else
       SymbolsNotFound.insert(S);

Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h?rev=329934&r1=329933&r2=329934&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h Thu Apr 12 11:35:08 2018
@@ -22,7 +22,8 @@ namespace orc {
 
 enum class OrcErrorCode : int {
   // RPC Errors
-  DuplicateDefinition = 1,
+  UnknownORCError = 1,
+  DuplicateDefinition,
   JITSymbolNotFound,
   RemoteAllocatorDoesNotExist,
   RemoteAllocatorIdAlreadyInUse,

Modified: llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp?rev=329934&r1=329933&r2=329934&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp Thu Apr 12 11:35:08 2018
@@ -9,6 +9,7 @@
 
 #include "llvm/ExecutionEngine/Orc/Core.h"
 #include "llvm/ExecutionEngine/Orc/OrcError.h"
+#include "llvm/Support/Format.h"
 
 #if LLVM_ENABLE_THREADS
 #include <future>
@@ -17,9 +18,100 @@
 namespace llvm {
 namespace orc {
 
+char FailedToMaterialize::ID = 0;
+char FailedToResolve::ID = 0;
+char FailedToFinalize::ID = 0;
+
 void MaterializationUnit::anchor() {}
 void SymbolResolver::anchor() {}
 
+raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
+  if (Flags.isWeak())
+    OS << 'W';
+  else if (Flags.isCommon())
+    OS << 'C';
+  else
+    OS << 'S';
+
+  if (Flags.isExported())
+    OS << 'E';
+  else
+    OS << 'H';
+
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const JITEvaluatedSymbol &Sym) {
+  OS << format("0x%016x", Sym.getAddress()) << " " << Sym.getFlags();
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) {
+  OS << "\"" << *KV.first << "\": " << KV.second;
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) {
+  OS << "{";
+  if (!Symbols.empty()) {
+    OS << " \"" << **Symbols.begin() << "\"";
+    for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end()))
+      OS << ", \"" << *Sym << "\"";
+  }
+  OS << " }";
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) {
+  OS << "{";
+  if (!Symbols.empty()) {
+    OS << " {" << *Symbols.begin() << "}";
+    for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end()))
+      OS << ", {" << Sym << "}";
+  }
+  OS << " }";
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {
+  OS << "{";
+  if (SymbolFlags.empty()) {
+    OS << " {\"" << *SymbolFlags.begin()->first
+       << "\": " << SymbolFlags.begin()->second << "}";
+    for (auto &KV :
+         make_range(std::next(SymbolFlags.begin()), SymbolFlags.end()))
+      OS << ", {\"" << *KV.first << "\": " << 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");
+}
+
+std::error_code FailedToResolve::convertToErrorCode() const {
+  return orcError(OrcErrorCode::UnknownORCError);
+}
+
+void FailedToResolve::log(raw_ostream &OS) const {
+  OS << "Failed to resolve symbols: " << Symbols;
+}
+
+FailedToFinalize::FailedToFinalize(SymbolNameSet Symbols)
+    : Symbols(std::move(Symbols)) {
+  assert(!this->Symbols.empty() && "Can not fail to finalize an empty set");
+}
+
+std::error_code FailedToFinalize::convertToErrorCode() const {
+  return orcError(OrcErrorCode::UnknownORCError);
+}
+
+void FailedToFinalize::log(raw_ostream &OS) const {
+  OS << "Failed to finalize symbols: " << Symbols;
+}
+
 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
     const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
     SymbolsReadyCallback NotifySymbolsReady)
@@ -31,16 +123,18 @@ AsynchronousSymbolQuery::AsynchronousSym
   OutstandingResolutions = OutstandingFinalizations = Symbols.size();
 }
 
-void AsynchronousSymbolQuery::setFailed(Error Err) {
-  OutstandingResolutions = OutstandingFinalizations = 0;
-  if (NotifySymbolsResolved)
+void AsynchronousSymbolQuery::notifyFailed(Error Err) {
+  if (OutstandingResolutions != 0)
     NotifySymbolsResolved(std::move(Err));
-  else
+  else if (OutstandingFinalizations != 0)
     NotifySymbolsReady(std::move(Err));
+  else
+    consumeError(std::move(Err));
+  OutstandingResolutions = OutstandingFinalizations = 0;
 }
 
-void AsynchronousSymbolQuery::setDefinition(SymbolStringPtr Name,
-                                            JITEvaluatedSymbol Sym) {
+void AsynchronousSymbolQuery::resolve(SymbolStringPtr Name,
+                                      JITEvaluatedSymbol Sym) {
   // If OutstandingResolutions is zero we must have errored out already. Just
   // ignore this.
   if (OutstandingResolutions == 0)
@@ -49,14 +143,11 @@ void AsynchronousSymbolQuery::setDefinit
   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) {
+  if (OutstandingResolutions == 0)
     NotifySymbolsResolved(std::move(Symbols));
-    // Null out NotifySymbolsResolved to indicate that we've already called it.
-    NotifySymbolsResolved = {};
-  }
 }
 
-void AsynchronousSymbolQuery::notifySymbolFinalized() {
+void AsynchronousSymbolQuery::finalizeSymbol() {
   // If OutstandingFinalizations is zero we must have errored out already. Just
   // ignore this.
   if (OutstandingFinalizations == 0)
@@ -68,173 +159,115 @@ void AsynchronousSymbolQuery::notifySymb
     NotifySymbolsReady(Error::success());
 }
 
-VSO::MaterializationInfo::MaterializationInfo(
+VSO::UnmaterializedInfo::UnmaterializedInfo(
     size_t SymbolsRemaining, std::unique_ptr<MaterializationUnit> MU)
     : SymbolsRemaining(SymbolsRemaining), MU(std::move(MU)) {}
 
-VSO::SymbolTableEntry::SymbolTableEntry(
-    JITSymbolFlags Flags, MaterializationInfoIterator MaterializationInfoItr)
-    : Flags(JITSymbolFlags::FlagNames(Flags | JITSymbolFlags::NotMaterialized)),
-      MaterializationInfoItr(std::move(MaterializationInfoItr)) {
-  // FIXME: Assert flag sanity.
+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;
 }
 
 VSO::SymbolTableEntry::SymbolTableEntry(JITEvaluatedSymbol Sym)
     : Flags(Sym.getFlags()), Address(Sym.getAddress()) {
-  // FIXME: Assert flag sanity.
+  assert(!Flags.isLazy() && !Flags.isMaterializing() &&
+         "This constructor is for final symbols only");
 }
 
-VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other)
-    : Flags(Other.Flags), Address(0) {
-  if (Flags.isMaterialized())
-    Address = Other.Address;
-  else
-    MaterializationInfoItr = std::move(Other.MaterializationInfoItr);
-}
+// VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other)
+//     : Flags(Other.Flags), Address(0) {
+//   if (this->Flags.isLazy())
+//     UMII = std::move(Other.UMII);
+//   else
+//     Address = Other.Address;
+// }
+
+// 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;
+// }
 
 VSO::SymbolTableEntry::~SymbolTableEntry() { destroy(); }
 
-VSO::SymbolTableEntry &VSO::SymbolTableEntry::
-operator=(JITEvaluatedSymbol Sym) {
+void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name,
+                                        JITEvaluatedSymbol Sym) {
+  assert(!Flags.isMaterializing() &&
+         "Attempting to replace definition during materialization?");
+  if (Flags.isLazy()) {
+    if (UMII->MU)
+      UMII->MU->discard(V, Name);
+    V.detach(UMII);
+  }
   destroy();
   Flags = Sym.getFlags();
   Address = Sym.getAddress();
-  return *this;
-}
-
-void VSO::SymbolTableEntry::destroy() {
-  if (!Flags.isMaterialized())
-    MaterializationInfoItr.~MaterializationInfoIterator();
 }
 
-JITSymbolFlags VSO::SymbolTableEntry::getFlags() const { return Flags; }
-
-void VSO::SymbolTableEntry::replaceWith(
-    VSO &V, SymbolStringPtr Name, JITSymbolFlags NewFlags,
-    MaterializationInfoIterator NewMaterializationInfoItr) {
-  bool ReplaceExistingLazyDefinition = !Flags.isMaterialized();
-  Flags = NewFlags;
-  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);
+void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name,
+                                        JITSymbolFlags NewFlags,
+                                        UnmaterializedInfoIterator NewUMII) {
+  assert(!Flags.isMaterializing() &&
+         "Attempting to replace definition during materialization?");
+  if (Flags.isLazy()) {
+    if (UMII->MU)
+      UMII->MU->discard(V, Name);
+    V.detach(UMII);
   }
-  MaterializationInfoItr = std::move(NewMaterializationInfoItr);
+  destroy();
+  Flags = NewFlags;
+  UMII = std::move(NewUMII);
 }
 
 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 {
-    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;
-      }
-    }
-  }
+VSO::SymbolTableEntry::initMaterialize(VSO &V) {
+  assert(Flags.isLazy() && "Can't materialize non-lazy symbol");
+  auto TmpMU = std::move(UMII->MU);
+  V.detach(UMII);
+  destroy();
+  Flags &= ~JITSymbolFlags::Lazy;
+  Flags |= JITSymbolFlags::Materializing;
+  Address = 0;
+  return TmpMU;
 }
 
-void VSO::SymbolTableEntry::resolve(VSO &V, SymbolStringPtr Name,
-                                    JITEvaluatedSymbol Sym) {
-  if (Flags.isMaterialized()) {
-    // FIXME: Should we assert flag state here (flags must match except for
-    //        materialization state, overrides must be legal) or in the caller
-    //        in VSO?
-    Flags = Sym.getFlags();
-    Address = Sym.getAddress();
-  } 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::resolve(VSO &V, JITEvaluatedSymbol Sym) {
+  if (Flags.isLazy()) {
+    assert(!UMII->MU && "Resolving with MaterializationUnit still attached?");
+    V.detach(UMII);
   }
+  destroy();
+  Flags = Sym.getFlags();
+  Flags |= JITSymbolFlags::Materializing;
+  Address = Sym.getAddress();
 }
 
-void VSO::SymbolTableEntry::finalize(VSO &V, SymbolStringPtr Name) {
-  if (!Flags.isMaterialized()) {
-    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);
-    }
+void VSO::SymbolTableEntry::finalize() {
+  assert(Flags.isMaterializing() && !Flags.isLazy() &&
+         "Symbol should be in materializing state");
+  Flags &= ~JITSymbolFlags::Materializing;
+}
 
-    if (--(*MaterializationInfoItr)->SymbolsRemaining == 0)
-      V.MaterializationInfos.erase(MaterializationInfoItr);
+void VSO::SymbolTableEntry::destroy() {
+  if (Flags.isLazy())
+    UMII.~UnmaterializedInfoIterator();
+}
 
-    // Destruct the iterator and re-define this entry using the final symbol
-    // value.
-    destroy();
-    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;
+void VSO::detach(UnmaterializedInfoIterator UMII) {
+  assert(UMII->SymbolsRemaining > 0 &&
+         "Detaching from empty UnmaterializedInfo?");
+  --UMII->SymbolsRemaining;
+  if (UMII->SymbolsRemaining == 0)
+    UnmaterializedInfos.erase(UMII);
 }
 
 VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old,
@@ -258,10 +291,9 @@ VSO::RelativeLinkageStrength VSO::compar
 VSO::RelativeLinkageStrength
 VSO::compareLinkage(SymbolStringPtr Name, JITSymbolFlags NewFlags) const {
   auto I = Symbols.find(Name);
-  return compareLinkage(I == Symbols.end()
-                            ? None
-                            : Optional<JITSymbolFlags>(I->second.getFlags()),
-                        NewFlags);
+  return compareLinkage(
+      I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags),
+      NewFlags);
 }
 
 Error VSO::define(SymbolMap NewSymbols) {
@@ -269,8 +301,7 @@ Error VSO::define(SymbolMap NewSymbols)
   for (auto &KV : NewSymbols) {
     auto I = Symbols.find(KV.first);
     auto LinkageResult = compareLinkage(
-        I == Symbols.end() ? None
-                           : Optional<JITSymbolFlags>(I->second.getFlags()),
+        I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags),
         KV.second.getFlags());
 
     // Silently discard weaker definitions.
@@ -284,11 +315,9 @@ Error VSO::define(SymbolMap NewSymbols)
       continue;
     }
 
-    if (I != Symbols.end()) {
-      // This is an override -- discard the overridden definition and overwrite.
-      I->second.discard(*this, KV.first);
-      I->second = std::move(KV.second);
-    } else
+    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;
@@ -298,27 +327,26 @@ Error VSO::defineLazy(std::unique_ptr<Ma
 
   auto NewSymbols = MU->getSymbols();
 
-  auto MaterializationInfoItr =
-      MaterializationInfos
-          .insert(llvm::make_unique<MaterializationInfo>(NewSymbols.size(),
-                                                         std::move(MU)))
-          .first;
+  auto UMII = UnmaterializedInfos.insert(
+      UnmaterializedInfos.end(),
+      UnmaterializedInfo(NewSymbols.size(), std::move(MU)));
 
   Error Err = Error::success();
   for (auto &KV : NewSymbols) {
     auto I = Symbols.find(KV.first);
 
+    assert(I == Symbols.end() ||
+           !I->second.Flags.isMaterializing() &&
+               "Attempt to replace materializing symbol definition");
+
     auto LinkageResult = compareLinkage(
-        I == Symbols.end() ? None
-                           : Optional<JITSymbolFlags>(I->second.getFlags()),
+        I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags),
         KV.second);
 
     // Discard weaker definitions.
     if (LinkageResult == ExistingDefinitionIsStronger) {
-      (*MaterializationInfoItr)->MU->discard(*this, KV.first);
-      assert((*MaterializationInfoItr)->SymbolsRemaining > 0 &&
-             "Discarding non-existant symbols?");
-      --(*MaterializationInfoItr)->SymbolsRemaining;
+      UMII->MU->discard(*this, KV.first);
+      detach(UMII);
       continue;
     }
 
@@ -328,41 +356,107 @@ Error VSO::defineLazy(std::unique_ptr<Ma
                        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;
+      detach(UMII);
       continue;
     }
 
+    // Existing definition was weaker. Replace it.
     if (I != Symbols.end())
-      I->second.replaceWith(*this, KV.first, KV.second, MaterializationInfoItr);
+      I->second.replaceWith(*this, KV.first, KV.second, UMII);
     else
-      Symbols.emplace(std::make_pair(
-          KV.first, SymbolTableEntry(KV.second, MaterializationInfoItr)));
+      Symbols.emplace(
+          std::make_pair(KV.first, SymbolTableEntry(KV.second, UMII)));
   }
 
-  // If we ended up overriding all definitions in this materializer then delete
-  // it.
-  if ((*MaterializationInfoItr)->SymbolsRemaining == 0)
-    MaterializationInfos.erase(MaterializationInfoItr);
-
   return Err;
 }
 
-void VSO::resolve(SymbolMap SymbolValues) {
+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.first, std::move(KV.second));
+    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::notifyResolutionFailed(const SymbolNameSet &Names) {
+  assert(!Names.empty() && "Failed to resolve empty set?");
+
+  std::map<std::shared_ptr<AsynchronousSymbolQuery>, SymbolNameSet>
+      QueriesToFail;
+
+  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()) {
+      assert(J->second.PendingFinalization.empty() &&
+             "Failed during resolution, but queries pending finalization?");
+      for (auto &Q : J->second.PendingResolution)
+        QueriesToFail[Q].insert(S);
+      MaterializingInfos.erase(J);
+    }
+    Symbols.erase(I);
   }
+
+  for (auto &KV : QueriesToFail)
+    KV.first->notifyFailed(make_error<FailedToResolve>(std::move(KV.second)));
 }
 
-void VSO::finalize(SymbolNameSet SymbolsToFinalize) {
+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");
-    I->second.finalize(*this, S);
+
+    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);
+    }
+    I->second.finalize();
+  }
+}
+
+void VSO::notifyFinalizationFailed(const SymbolNameSet &Names) {
+  assert(!Names.empty() && "Failed to finalize empty set?");
+
+  std::map<std::shared_ptr<AsynchronousSymbolQuery>, SymbolNameSet>
+      QueriesToFail;
+
+  for (auto &S : Names) {
+    auto I = Symbols.find(S);
+    assert(I != Symbols.end() && "Symbol not present in this VSO");
+    assert((I->second.Flags & JITSymbolFlags::Materializing) &&
+           "Failed to finalize symbol that was not materializing");
+
+    auto J = MaterializingInfos.find(S);
+    if (J != MaterializingInfos.end()) {
+      assert(J->second.PendingResolution.empty() &&
+             "Failed during finalization, but queries pending resolution?");
+      for (auto &Q : J->second.PendingFinalization)
+        QueriesToFail[Q].insert(S);
+      MaterializingInfos.erase(J);
+    }
+    Symbols.erase(I);
   }
+
+  for (auto &KV : QueriesToFail)
+    KV.first->notifyFailed(make_error<FailedToFinalize>(std::move(KV.second)));
 }
 
 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Names) {
@@ -378,7 +472,7 @@ SymbolNameSet VSO::lookupFlags(SymbolFla
     Names.erase(Tmp);
 
     Flags[SymI->first] =
-        JITSymbolFlags::stripTransientFlags(SymI->second.getFlags());
+        JITSymbolFlags::stripTransientFlags(SymI->second.Flags);
   }
 
   return Names;
@@ -396,14 +490,43 @@ VSO::LookupResult VSO::lookup(std::share
     if (SymI == Symbols.end())
       continue;
 
-    // The symbol is in the dylib. Erase it from Names and proceed.
+    // The symbol is in the VSO. Erase it from Names and proceed.
     Names.erase(Tmp);
 
-    // 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 MU = SymI->second.query(SymI->first, Query))
-      MaterializationUnits.push_back(std::move(MU));
+    // If this symbol has not been materialized yet, move it to materializing,
+    // then fall through to the materializing case below.
+    if (SymI->second.Flags.isLazy()) {
+      if (auto MU = SymI->second.initMaterialize(*this))
+        MaterializationUnits.push_back(std::move(MU));
+    }
+
+    // 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);
+    if (J == MaterializingInfos.end())
+      J = MaterializingInfos
+              .insert(std::make_pair(SymI->first, MaterializingInfo()))
+              .first;
+
+    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(MaterializationUnits), std::move(Names)};

Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h?rev=329934&r1=329933&r2=329934&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/OrcCBindingsStack.h Thu Apr 12 11:35:08 2018
@@ -153,13 +153,13 @@ private:
       for (auto &S : Symbols) {
         if (auto Sym = findSymbol(*S)) {
           if (auto Addr = Sym.getAddress())
-            Query->setDefinition(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
+            Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
           else {
-            Query->setFailed(Addr.takeError());
+            Query->notifyFailed(Addr.takeError());
             return orc::SymbolNameSet();
           }
         } else if (auto Err = Sym.takeError()) {
-          Query->setFailed(std::move(Err));
+          Query->notifyFailed(std::move(Err));
           return orc::SymbolNameSet();
         } else
           UnresolvedSymbols.insert(S);

Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp?rev=329934&r1=329933&r2=329934&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp Thu Apr 12 11:35:08 2018
@@ -29,6 +29,8 @@ public:
 
   std::string message(int condition) const override {
     switch (static_cast<OrcErrorCode>(condition)) {
+    case OrcErrorCode::UnknownORCError:
+      return "Unknown ORC error";
     case OrcErrorCode::DuplicateDefinition:
       return "Duplicate symbol definition";
     case OrcErrorCode::JITSymbolNotFound:

Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h?rev=329934&r1=329933&r2=329934&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h Thu Apr 12 11:35:08 2018
@@ -175,25 +175,24 @@ class OrcMCJITReplacement : public Execu
       for (auto &S : Symbols) {
         if (auto Sym = M.findMangledSymbol(*S)) {
           if (auto Addr = Sym.getAddress())
-            Query->setDefinition(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
+            Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
           else {
-            Query->setFailed(Addr.takeError());
+            Query->notifyFailed(Addr.takeError());
             return SymbolNameSet();
           }
         } else if (auto Err = Sym.takeError()) {
-          Query->setFailed(std::move(Err));
+          Query->notifyFailed(std::move(Err));
           return SymbolNameSet();
         } else {
           if (auto Sym2 = M.ClientResolver->findSymbol(*S)) {
             if (auto Addr = Sym2.getAddress())
-              Query->setDefinition(S,
-                                   JITEvaluatedSymbol(*Addr, Sym2.getFlags()));
+              Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym2.getFlags()));
             else {
-              Query->setFailed(Addr.takeError());
+              Query->notifyFailed(Addr.takeError());
               return SymbolNameSet();
             }
           } else if (auto Err = Sym2.takeError()) {
-            Query->setFailed(std::move(Err));
+            Query->notifyFailed(std::move(Err));
             return SymbolNameSet();
           } else
             UnresolvedSymbols.insert(S);

Modified: llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp?rev=329934&r1=329933&r2=329934&view=diff
==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp (original)
+++ llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp Thu Apr 12 11:35:08 2018
@@ -24,12 +24,19 @@ public:
   using GetSymbolsFunction = std::function<SymbolFlagsMap()>;
   using MaterializeFunction = std::function<Error(VSO &)>;
   using DiscardFunction = std::function<void(VSO &, SymbolStringPtr)>;
+  using DestructorFunction = std::function<void()>;
 
-  SimpleMaterializationUnit(GetSymbolsFunction GetSymbols,
-                            MaterializeFunction Materialize,
-                            DiscardFunction Discard)
+  SimpleMaterializationUnit(
+      GetSymbolsFunction GetSymbols, MaterializeFunction Materialize,
+      DiscardFunction Discard,
+      DestructorFunction Destructor = DestructorFunction())
       : GetSymbols(std::move(GetSymbols)), Materialize(std::move(Materialize)),
-        Discard(std::move(Discard)) {}
+        Discard(std::move(Discard)), Destructor(std::move(Destructor)) {}
+
+  ~SimpleMaterializationUnit() override {
+    if (Destructor)
+      Destructor();
+  }
 
   SymbolFlagsMap getSymbols() override { return GetSymbols(); }
 
@@ -43,6 +50,7 @@ private:
   GetSymbolsFunction GetSymbols;
   MaterializeFunction Materialize;
   DiscardFunction Discard;
+  DestructorFunction Destructor;
 };
 
 TEST(CoreAPIsTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) {
@@ -68,7 +76,7 @@ TEST(CoreAPIsTest, AsynchronousSymbolQue
 
   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
 
-  Q.setDefinition(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported));
+  Q.resolve(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported));
 
   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
@@ -95,7 +103,7 @@ TEST(CoreAPIsTest, AsynchronousSymbolQue
 
   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
 
-  Q.setFailed(make_error<StringError>("xyz", inconvertibleErrorCode()));
+  Q.notifyFailed(make_error<StringError>("xyz", inconvertibleErrorCode()));
 
   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
@@ -186,6 +194,44 @@ TEST(CoreAPIsTest, LookupFlagsTest) {
   EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
 }
 
+TEST(CoreAPIsTest, DropMaterializerWhenEmpty) {
+  SymbolStringPool SP;
+  auto Foo = SP.intern("foo");
+  auto Bar = SP.intern("bar");
+
+  bool DestructorRun = false;
+
+  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
+      [=]() {
+        return SymbolFlagsMap(
+            {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
+      },
+      [](VSO &V) -> Error {
+        llvm_unreachable("Unexpected call to materialize");
+      },
+      [&](VSO &V, SymbolStringPtr Name) {
+        EXPECT_TRUE(Name == Foo || Name == Bar)
+            << "Discard of unexpected symbol?";
+      },
+      [&]() { DestructorRun = true; });
+
+  VSO V;
+
+  cantFail(V.defineLazy(std::move(MU)));
+
+  auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
+  auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
+  cantFail(V.define(SymbolMap({{Foo, FooSym}})));
+
+  EXPECT_FALSE(DestructorRun)
+      << "MaterializationUnit should not have been destroyed yet";
+
+  cantFail(V.define(SymbolMap({{Bar, BarSym}})));
+
+  EXPECT_TRUE(DestructorRun)
+      << "MaterializationUnit should have been destroyed";
+}
+
 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
 
   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
@@ -264,6 +310,121 @@ TEST(CoreAPIsTest, AddAndMaterializeLazy
   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
 }
 
+TEST(CoreAPIsTest, FailResolution) {
+  SymbolStringPool SP;
+  auto Foo = SP.intern("foo");
+  auto Bar = SP.intern("bar");
+
+  SymbolNameSet Names({Foo, Bar});
+
+  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
+      [=]() {
+        return SymbolFlagsMap(
+            {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
+      },
+      [&](VSO &V) -> Error {
+        V.notifyResolutionFailed(Names);
+        return Error::success();
+      },
+      [&](VSO &V, SymbolStringPtr Name) {
+        llvm_unreachable("Unexpected call to discard");
+      });
+
+  VSO V;
+
+  cantFail(V.defineLazy(std::move(MU)));
+
+  auto OnResolution = [&](Expected<SymbolMap> Result) {
+    handleAllErrors(Result.takeError(),
+                    [&](FailedToResolve &F) {
+                      EXPECT_EQ(F.getSymbols(), Names)
+                          << "Expected to fail on symbols in Names";
+                    },
+                    [](ErrorInfoBase &EIB) {
+                      std::string ErrMsg;
+                      {
+                        raw_string_ostream ErrOut(ErrMsg);
+                        EIB.log(ErrOut);
+                      }
+                      ADD_FAILURE()
+                          << "Expected a FailedToResolve error. Got:\n"
+                          << ErrMsg;
+                    });
+  };
+
+  auto OnReady = [](Error Err) {
+    cantFail(std::move(Err));
+    ADD_FAILURE() << "OnReady should never be called";
+  };
+
+  auto Q =
+      std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
+
+  auto LR = V.lookup(std::move(Q), Names);
+  for (auto &SWKV : LR.MaterializationUnits)
+    cantFail(SWKV->materialize(V));
+}
+
+TEST(CoreAPIsTest, FailFinalization) {
+  SymbolStringPool SP;
+  auto Foo = SP.intern("foo");
+  auto Bar = SP.intern("bar");
+
+  SymbolNameSet Names({Foo, Bar});
+
+  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
+      [=]() {
+        return SymbolFlagsMap(
+            {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
+      },
+      [&](VSO &V) -> Error {
+        constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
+        constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
+
+        auto FooSym = JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
+        auto BarSym = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
+        V.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
+        V.notifyFinalizationFailed(Names);
+        return Error::success();
+      },
+      [&](VSO &V, SymbolStringPtr Name) {
+        llvm_unreachable("Unexpected call to discard");
+      });
+
+  VSO V;
+
+  cantFail(V.defineLazy(std::move(MU)));
+
+  auto OnResolution = [](Expected<SymbolMap> Result) {
+    cantFail(std::move(Result));
+  };
+
+  auto OnReady = [&](Error Err) {
+    handleAllErrors(std::move(Err),
+                    [&](FailedToFinalize &F) {
+                      EXPECT_EQ(F.getSymbols(), Names)
+                          << "Expected to fail on symbols in Names";
+                    },
+                    [](ErrorInfoBase &EIB) {
+                      std::string ErrMsg;
+                      {
+                        raw_string_ostream ErrOut(ErrMsg);
+                        EIB.log(ErrOut);
+                      }
+                      ADD_FAILURE()
+                          << "Expected a FailedToFinalize error. Got:\n"
+                          << ErrMsg;
+                    });
+  };
+
+  auto Q =
+      std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
+
+  auto LR = V.lookup(std::move(Q), Names);
+  for (auto &SWKV : LR.MaterializationUnits)
+    cantFail(SWKV->materialize(V));
+}
+
 TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
   JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
   JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);




More information about the llvm-commits mailing list