[ORC] Add orc::SymbolResolver, a Orc/Legacy API interop header, and an

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
This commit is contained in:
Lang Hames 2018-01-22 03:00:31 +00:00
parent ac471d6db2
commit 635fd9092b
11 changed files with 249 additions and 19 deletions

View 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.

View 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;
};

View File

@ -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

View File

@ -2,6 +2,7 @@ add_llvm_library(LLVMOrcJIT
Core.cpp
ExecutionUtils.cpp
IndirectionUtils.cpp
Legacy.cpp
NullResolver.cpp
OrcABISupport.cpp
OrcCBindings.cpp

View 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) {

View File

@ -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.

View 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) {

View 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();

View 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: ");

View File

@ -15,6 +15,7 @@ add_llvm_unittest(OrcJITTests
IndirectionUtilsTest.cpp
GlobalMappingLayerTest.cpp
LazyEmittingLayerTest.cpp
LegacyAPIInteropTest.cpp
ObjectTransformLayerTest.cpp
OrcCAPITest.cpp
OrcTestCommon.cpp

View File

@ -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