diff --git a/include/llvm/ExecutionEngine/JITSymbol.h b/include/llvm/ExecutionEngine/JITSymbol.h index 60b4f8fbc74..0ce16dca0b5 100644 --- a/include/llvm/ExecutionEngine/JITSymbol.h +++ b/include/llvm/ExecutionEngine/JITSymbol.h @@ -285,7 +285,7 @@ private: /// remote JITing, and expose opportunities for parallel compilation. class JITSymbolResolver { public: - using SymbolNameSet = std::set; + using LookupSet = std::set; using LookupResult = std::map; using LookupFlagsResult = std::map; @@ -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 lookup(const SymbolNameSet &Symbols) = 0; + virtual Expected 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 - lookupFlags(const SymbolNameSet &Symbols) = 0; + virtual Expected 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 lookup(const SymbolNameSet &Symbols) final; + Expected lookup(const LookupSet &Symbols) final; /// @brief Performs flags lookup by calling findSymbolInLogicalDylib and /// returning the flags value for that symbol. - Expected lookupFlags(const SymbolNameSet &Symbols) final; + Expected 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. diff --git a/include/llvm/ExecutionEngine/Orc/Core.h b/include/llvm/ExecutionEngine/Orc/Core.h index 443125b7951..ad7545f63be 100644 --- a/include/llvm/ExecutionEngine/Orc/Core.h +++ b/include/llvm/ExecutionEngine/Orc/Core.h @@ -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; using SourceWorkMap = std::map; - 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/include/llvm/ExecutionEngine/Orc/Legacy.h b/include/llvm/ExecutionEngine/Orc/Legacy.h new file mode 100644 index 00000000000..11143a872a5 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/Legacy.h @@ -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 lookup(const LookupSet &Symbols) override; + Expected lookupFlags(const LookupSet &Symbols) override; + +private: + ExecutionSession &ES; + std::set ResolvedStrings; + SymbolResolver &R; +}; + +} // End namespace orc +} // End namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_LEGACY_H diff --git a/lib/ExecutionEngine/Orc/CMakeLists.txt b/lib/ExecutionEngine/Orc/CMakeLists.txt index ee64990dfb4..ca1b9ee005c 100644 --- a/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -2,6 +2,7 @@ add_llvm_library(LLVMOrcJIT Core.cpp ExecutionUtils.cpp IndirectionUtils.cpp + Legacy.cpp NullResolver.cpp OrcABISupport.cpp OrcCBindings.cpp diff --git a/lib/ExecutionEngine/Orc/Core.cpp b/lib/ExecutionEngine/Orc/Core.cpp index 232c880b9dd..ff78ba19939 100644 --- a/lib/ExecutionEngine/Orc/Core.cpp +++ b/lib/ExecutionEngine/Orc/Core.cpp @@ -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/lib/ExecutionEngine/Orc/Legacy.cpp b/lib/ExecutionEngine/Orc/Legacy.cpp new file mode 100644 index 00000000000..e4eba8bd756 --- /dev/null +++ b/lib/ExecutionEngine/Orc/Legacy.cpp @@ -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::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 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("Unresolved symbols", + inconvertibleErrorCode())); + + if (Err) + return std::move(Err); + + return Result; +} + +Expected +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. diff --git a/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp b/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp index 670c6d2fa3f..2b3c00fd7d7 100644 --- a/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp @@ -52,7 +52,7 @@ ARMJITSymbolFlags llvm::ARMJITSymbolFlags::fromObjectSymbol( /// findSymbolInLogicalDylib and if that fails calling /// findSymbol. Expected -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 -LegacyJITSymbolResolver::lookupFlags(const SymbolNameSet &Symbols) { +LegacyJITSymbolResolver::lookupFlags(const LookupSet &Symbols) { JITSymbolResolver::LookupFlagsResult Result; for (auto &Symbol : Symbols) { diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 9741a48439d..5c4b8c12f34 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -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(); diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp index 0f4534f2c9f..3d944bf7b60 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -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: "); diff --git a/unittests/ExecutionEngine/Orc/CMakeLists.txt b/unittests/ExecutionEngine/Orc/CMakeLists.txt index 25697300e33..6dbff7c592a 100644 --- a/unittests/ExecutionEngine/Orc/CMakeLists.txt +++ b/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -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/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp b/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp new file mode 100644 index 00000000000..12c43b58625 --- /dev/null +++ b/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp @@ -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; + using LookupFn = std::function; + + 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