[ORC] Add orc::SymbolResolver, a Orc/Legacy API interop header, and an
authorLang Hames <lhames@gmail.com>
Mon, 22 Jan 2018 03:00:31 +0000 (03:00 +0000)
committerLang Hames <lhames@gmail.com>
Mon, 22 Jan 2018 03:00:31 +0000 (03:00 +0000)
orc::SymbolResolver to JITSymbolResolver adapter.

The new orc::SymbolResolver interface uses asynchronous queries for better
performance. (Asynchronous queries with bulk lookup minimize RPC/IPC overhead,
support parallel incoming queries, and expose more available work for
distribution). Existing ORC layers will soon be updated to use the
orc::SymbolResolver API rather than the legacy llvm::JITSymbolResolver API.

Because RuntimeDyld still uses JITSymbolResolver, this patch also includes an
adapter that wraps an orc::SymbolResolver with a JITSymbolResolver API.

llvm-svn: 323073

llvm/include/llvm/ExecutionEngine/JITSymbol.h
llvm/include/llvm/ExecutionEngine/Orc/Core.h
llvm/include/llvm/ExecutionEngine/Orc/Legacy.h [new file with mode: 0644]
llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
llvm/lib/ExecutionEngine/Orc/Core.cpp
llvm/lib/ExecutionEngine/Orc/Legacy.cpp [new file with mode: 0644]
llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp
llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
llvm/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp [new file with mode: 0644]

index 60b4f8f..0ce16dc 100644 (file)
@@ -285,7 +285,7 @@ private:
 /// remote JITing, and expose opportunities for parallel compilation.
 class JITSymbolResolver {
 public:
-  using SymbolNameSet = std::set<StringRef>;
+  using LookupSet = std::set<StringRef>;
   using LookupResult = std::map<StringRef, JITEvaluatedSymbol>;
   using LookupFlagsResult = std::map<StringRef, JITSymbolFlags>;
 
@@ -296,14 +296,13 @@ public:
   ///
   /// This method will return an error if any of the given symbols can not be
   /// resolved, or if the resolution process itself triggers an error.
-  virtual Expected<LookupResult> lookup(const SymbolNameSet &Symbols) = 0;
+  virtual Expected<LookupResult> lookup(const LookupSet &Symbols) = 0;
 
   /// @brief Returns the symbol flags for each of the given symbols.
   ///
   /// This method does NOT return an error if any of the given symbols is
   /// missing. Instead, that symbol will be left out of the result map.
-  virtual Expected<LookupFlagsResult>
-  lookupFlags(const SymbolNameSet &Symbols) = 0;
+  virtual Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) = 0;
 
 private:
   virtual void anchor();
@@ -315,11 +314,11 @@ public:
   /// @brief Performs lookup by, for each symbol, first calling
   ///        findSymbolInLogicalDylib and if that fails calling
   ///        findSymbol.
-  Expected<LookupResult> lookup(const SymbolNameSet &Symbols) final;
+  Expected<LookupResult> lookup(const LookupSet &Symbols) final;
 
   /// @brief Performs flags lookup by calling findSymbolInLogicalDylib and
   ///        returning the flags value for that symbol.
-  Expected<LookupFlagsResult> lookupFlags(const SymbolNameSet &Symbols) final;
+  Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) final;
 
   /// This method returns the address of the specified symbol if it exists
   /// within the logical dynamic library represented by this JITSymbolResolver.
index 443125b..ad7545f 100644 (file)
@@ -92,6 +92,25 @@ private:
   SymbolsReadyCallback NotifySymbolsReady;
 };
 
+/// @brief A SymbolFlagsMap containing flags of found symbols, plus a set of
+///        not-found symbols. Shared between SymbolResolver::lookupFlags and
+///        VSO::lookupFlags for convenience.
+struct LookupFlagsResult {
+  SymbolFlagsMap SymbolFlags;
+  SymbolNameSet SymbolsNotFound;
+};
+
+class SymbolResolver {
+public:
+  virtual ~SymbolResolver() = default;
+  virtual LookupFlagsResult lookupFlags(const SymbolNameSet &Symbols) = 0;
+  virtual SymbolNameSet lookup(AsynchronousSymbolQuery &Query,
+                               SymbolNameSet Symbols) = 0;
+
+private:
+  virtual void anchor();
+};
+
 /// @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).
@@ -138,11 +157,6 @@ public:
       std::map<SymbolStringPtr, RelativeLinkageStrength>;
   using SourceWorkMap = std::map<SymbolSource *, SymbolNameSet>;
 
-  struct LookupFlagsResult {
-    SymbolFlagsMap SymbolFlags;
-    SymbolNameSet SymbolsNotFound;
-  };
-
   struct LookupResult {
     SourceWorkMap MaterializationWork;
     SymbolNameSet UnresolvedSymbols;
@@ -245,6 +259,14 @@ private:
 /// @brief An ExecutionSession represents a running JIT program.
 class ExecutionSession {
 public:
+  /// @brief Construct an ExecutionEngine.
+  ///
+  /// SymbolStringPools may be shared between ExecutionSessions.
+  ExecutionSession(SymbolStringPool &SSP);
+
+  /// @brief Returns the SymbolStringPool for this ExecutionSession.
+  SymbolStringPool &getSymbolStringPool() const { return SSP; }
+
   /// @brief Allocate a module key for a new module to add to the JIT.
   VModuleKey allocateVModule();
 
@@ -254,6 +276,7 @@ public:
   void releaseVModule(VModuleKey Key);
 
 public:
+  SymbolStringPool &SSP;
   VModuleKey LastKey = 0;
 };
 
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Legacy.h b/llvm/include/llvm/ExecutionEngine/Orc/Legacy.h
new file mode 100644 (file)
index 0000000..11143a8
--- /dev/null
@@ -0,0 +1,38 @@
+//===--- Legacy.h -- Adapters for ExecutionEngine API interop ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Contains core ORC APIs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_LEGACY_H
+#define LLVM_EXECUTIONENGINE_ORC_LEGACY_H
+
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
+
+namespace llvm {
+namespace orc {
+
+class JITSymbolResolverAdapter : public JITSymbolResolver {
+public:
+  JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R);
+  Expected<LookupResult> lookup(const LookupSet &Symbols) override;
+  Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) override;
+
+private:
+  ExecutionSession &ES;
+  std::set<SymbolStringPtr> ResolvedStrings;
+  SymbolResolver &R;
+};
+
+} // End namespace orc
+} // End namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_LEGACY_H
index ee64990..ca1b9ee 100644 (file)
@@ -2,6 +2,7 @@ add_llvm_library(LLVMOrcJIT
   Core.cpp
   ExecutionUtils.cpp
   IndirectionUtils.cpp
+  Legacy.cpp
   NullResolver.cpp
   OrcABISupport.cpp
   OrcCBindings.cpp
index 232c880..ff78ba1 100644 (file)
@@ -13,6 +13,7 @@
 namespace llvm {
 namespace orc {
 
+void SymbolResolver::anchor() {}
 void SymbolSource::anchor() {}
 
 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
@@ -287,7 +288,7 @@ void VSO::finalize(SymbolNameSet SymbolsToFinalize) {
   }
 }
 
-VSO::LookupFlagsResult VSO::lookupFlags(SymbolNameSet Names) {
+LookupFlagsResult VSO::lookupFlags(SymbolNameSet Names) {
   SymbolFlagsMap FlagsFound;
 
   for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) {
@@ -332,6 +333,8 @@ VSO::LookupResult VSO::lookup(AsynchronousSymbolQuery &Query,
   return {std::move(MaterializationWork), std::move(Names)};
 }
 
+ExecutionSession::ExecutionSession(SymbolStringPool &SSP) : SSP(SSP) {}
+
 VModuleKey ExecutionSession::allocateVModule() { return ++LastKey; }
 
 void ExecutionSession::releaseVModule(VModuleKey VMod) {
diff --git a/llvm/lib/ExecutionEngine/Orc/Legacy.cpp b/llvm/lib/ExecutionEngine/Orc/Legacy.cpp
new file mode 100644 (file)
index 0000000..e4eba8b
--- /dev/null
@@ -0,0 +1,75 @@
+//===------- Legacy.cpp - Adapters for ExecutionEngine API interop --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/Legacy.h"
+
+namespace llvm {
+namespace orc {
+
+JITSymbolResolverAdapter::JITSymbolResolverAdapter(ExecutionSession &ES,
+                                                   SymbolResolver &R)
+    : ES(ES), R(R) {}
+
+Expected<JITSymbolResolverAdapter::LookupResult>
+JITSymbolResolverAdapter::lookup(const LookupSet &Symbols) {
+  Error Err = Error::success();
+  JITSymbolResolver::LookupResult Result;
+
+  SymbolNameSet InternedSymbols;
+  for (auto &S : Symbols)
+    InternedSymbols.insert(ES.getSymbolStringPool().intern(S));
+
+  auto OnResolve = [&](Expected<SymbolMap> R) {
+    if (R) {
+      for (auto &KV : *R) {
+        ResolvedStrings.insert(KV.first);
+        Result[*KV.first] = KV.second;
+      }
+    } else
+      Err = joinErrors(std::move(Err), R.takeError());
+  };
+
+  auto OnReady = [](Error Err) {
+    // FIXME: Report error to ExecutionSession.
+    logAllUnhandledErrors(std::move(Err), errs(),
+                          "legacy resolver received on-ready error:\n");
+  };
+
+  AsynchronousSymbolQuery Query(InternedSymbols, OnResolve, OnReady);
+
+  auto UnresolvedSymbols = R.lookup(Query, InternedSymbols);
+
+  if (!UnresolvedSymbols.empty())
+    Err = joinErrors(std::move(Err),
+                     make_error<StringError>("Unresolved symbols",
+                                             inconvertibleErrorCode()));
+
+  if (Err)
+    return std::move(Err);
+
+  return Result;
+}
+
+Expected<JITSymbolResolverAdapter::LookupFlagsResult>
+JITSymbolResolverAdapter::lookupFlags(const LookupSet &Symbols) {
+  SymbolNameSet InternedSymbols;
+  for (auto &S : Symbols)
+    InternedSymbols.insert(ES.getSymbolStringPool().intern(S));
+
+  LookupFlagsResult Result;
+  for (auto &KV : R.lookupFlags(InternedSymbols).SymbolFlags) {
+    ResolvedStrings.insert(KV.first);
+    Result[*KV.first] = KV.second;
+  }
+
+  return Result;
+}
+
+} // End namespace orc.
+} // End namespace llvm.
index 670c6d2..2b3c00f 100644 (file)
@@ -52,7 +52,7 @@ ARMJITSymbolFlags llvm::ARMJITSymbolFlags::fromObjectSymbol(
 ///        findSymbolInLogicalDylib and if that fails calling
 ///        findSymbol.
 Expected<JITSymbolResolver::LookupResult>
-LegacyJITSymbolResolver::lookup(const SymbolNameSet &Symbols) {
+LegacyJITSymbolResolver::lookup(const LookupSet &Symbols) {
   JITSymbolResolver::LookupResult Result;
   for (auto &Symbol : Symbols) {
     std::string SymName = Symbol.str();
@@ -84,7 +84,7 @@ LegacyJITSymbolResolver::lookup(const SymbolNameSet &Symbols) {
 /// @brief Performs flags lookup by calling findSymbolInLogicalDylib and
 ///        returning the flags value for that symbol.
 Expected<JITSymbolResolver::LookupFlagsResult>
-LegacyJITSymbolResolver::lookupFlags(const SymbolNameSet &Symbols) {
+LegacyJITSymbolResolver::lookupFlags(const LookupSet &Symbols) {
   JITSymbolResolver::LookupFlagsResult Result;
 
   for (auto &Symbol : Symbols) {
index 9741a48..5c4b8c1 100644 (file)
@@ -211,7 +211,7 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
   // definitions occur elsewhere.
   JITSymbolResolver::LookupFlagsResult SymbolFlags;
   {
-    JITSymbolResolver::SymbolNameSet Symbols;
+    JITSymbolResolver::LookupSet Symbols;
     for (auto &Sym : Obj.symbols()) {
       uint32_t Flags = Sym.getFlags();
       if ((Flags & SymbolRef::SF_Common) || (Flags & SymbolRef::SF_Weak)) {
@@ -1000,10 +1000,10 @@ Error RuntimeDyldImpl::resolveExternalSymbols() {
   // Resolution can trigger emission of more symbols, so iterate until
   // we've resolved *everything*.
   {
-    JITSymbolResolver::SymbolNameSet ResolvedSymbols;
+    JITSymbolResolver::LookupSet ResolvedSymbols;
 
     while (true) {
-      JITSymbolResolver::SymbolNameSet NewSymbols;
+      JITSymbolResolver::LookupSet NewSymbols;
 
       for (auto &RelocKV : ExternalSymbolRelocations) {
         StringRef Name = RelocKV.first();
index 0f4534f..3d944bf 100644 (file)
@@ -731,7 +731,7 @@ bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix,
 bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const {
   if (getRTDyld().getSymbol(Symbol))
     return true;
-  JITSymbolResolver::SymbolNameSet Symbols({Symbol});
+  JITSymbolResolver::LookupSet Symbols({Symbol});
   auto Result = getRTDyld().Resolver.lookup(Symbols);
   if (!Result) {
     logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: ");
@@ -750,7 +750,7 @@ uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const {
   if (auto InternalSymbol = getRTDyld().getSymbol(Symbol))
     return InternalSymbol.getAddress();
 
-  JITSymbolResolver::SymbolNameSet Symbols({Symbol});
+  JITSymbolResolver::LookupSet Symbols({Symbol});
   auto Result = getRTDyld().Resolver.lookup(Symbols);
   if (!Result) {
     logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: ");
index 2569730..6dbff7c 100644 (file)
@@ -15,6 +15,7 @@ add_llvm_unittest(OrcJITTests
   IndirectionUtilsTest.cpp
   GlobalMappingLayerTest.cpp
   LazyEmittingLayerTest.cpp
+  LegacyAPIInteropTest.cpp
   ObjectTransformLayerTest.cpp
   OrcCAPITest.cpp
   OrcTestCommon.cpp
diff --git a/llvm/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp b/llvm/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp
new file mode 100644 (file)
index 0000000..12c43b5
--- /dev/null
@@ -0,0 +1,90 @@
+//===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OrcTestCommon.h"
+#include "llvm/ExecutionEngine/Orc/Legacy.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::orc;
+
+class SimpleORCResolver : public SymbolResolver {
+public:
+  using LookupFlagsFn = std::function<LookupFlagsResult(const SymbolNameSet &)>;
+  using LookupFn = std::function<SymbolNameSet(AsynchronousSymbolQuery &Q,
+                                               SymbolNameSet Symbols)>;
+
+  SimpleORCResolver(LookupFlagsFn LookupFlags, LookupFn Lookup)
+      : LookupFlags(std::move(LookupFlags)), Lookup(std::move(Lookup)) {}
+
+  LookupFlagsResult lookupFlags(const SymbolNameSet &Symbols) override {
+    return LookupFlags(Symbols);
+  }
+
+  SymbolNameSet lookup(AsynchronousSymbolQuery &Query,
+                       SymbolNameSet Symbols) override {
+    return Lookup(Query, std::move(Symbols));
+  };
+
+private:
+  LookupFlagsFn LookupFlags;
+  LookupFn Lookup;
+};
+
+namespace {
+
+TEST(LegacyAPIInteropTest, QueryAgainstVSO) {
+
+  SymbolStringPool SP;
+  ExecutionSession ES(SP);
+  auto Foo = SP.intern("foo");
+
+  VSO V;
+  SymbolMap Defs;
+  JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
+  Defs[Foo] = FooSym;
+  cantFail(V.define(std::move(Defs)));
+
+  auto LookupFlags = [&](const SymbolNameSet &Names) {
+    return V.lookupFlags(Names);
+  };
+
+  auto Lookup = [&](AsynchronousSymbolQuery &Query, SymbolNameSet Symbols) {
+    auto R = V.lookup(Query, Symbols);
+    EXPECT_TRUE(R.MaterializationWork.empty())
+        << "Query resulted in unexpected materialization work";
+    return std::move(R.UnresolvedSymbols);
+  };
+
+  SimpleORCResolver UnderlyingResolver(std::move(LookupFlags),
+                                       std::move(Lookup));
+  JITSymbolResolverAdapter Resolver(ES, UnderlyingResolver);
+
+  JITSymbolResolver::LookupSet Names{StringRef("foo")};
+
+  auto LFR = Resolver.lookupFlags(Names);
+  EXPECT_TRUE(!!LFR) << "lookupFlags failed";
+  EXPECT_EQ(LFR->size(), 1U)
+      << "lookupFlags returned the wrong number of results";
+  EXPECT_EQ(LFR->count(*Foo), 1U)
+      << "lookupFlags did not contain a result for 'foo'";
+  EXPECT_EQ((*LFR)[*Foo], FooSym.getFlags())
+      << "lookupFlags contained the wrong result for 'foo'";
+
+  auto LR = Resolver.lookup(Names);
+  EXPECT_TRUE(!!LR) << "lookup failed";
+  EXPECT_EQ(LR->size(), 1U) << "lookup returned the wrong number of results";
+  EXPECT_EQ(LR->count(*Foo), 1U) << "lookup did not contain a result for 'foo'";
+  EXPECT_EQ((*LR)[*Foo].getFlags(), FooSym.getFlags())
+      << "lookup returned the wrong result for flags of 'foo'";
+  EXPECT_EQ((*LR)[*Foo].getAddress(), FooSym.getAddress())
+      << "lookup returned the wrong result for address of 'foo'";
+}
+
+} // namespace