[llvm] r312511 - [ORC] Add a pair of ORC layers that forward object-layer operations via RPC.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 4 20:34:09 PDT 2017
Author: lhames
Date: Mon Sep 4 20:34:09 2017
New Revision: 312511
URL: http://llvm.org/viewvc/llvm-project?rev=312511&view=rev
Log:
[ORC] Add a pair of ORC layers that forward object-layer operations via RPC.
This patch introduces RemoteObjectClientLayer and RemoteObjectServerLayer,
which can be used to forward ORC object-layer operations from a JIT stack in
the client to a JIT stack (consisting only of object-layers) in the server.
This is a new way to support remote-JITing in LLVM. The previous approach
(supported by OrcRemoteTargetClient and OrcRemoteTargetServer) used a
remote-mapping memory manager that sat "beneath" the JIT stack and sent
fully-relocated binary blobs to the server. The main advantage of the new
approach is that relocatable objects can be cached on the server and re-used
(if the code that they represent hasn't changed), whereas fully-relocated blobs
can not (since the addresses they have been permanently bound to will change
from run to run).
Added:
llvm/trunk/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h
llvm/trunk/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp
Modified:
llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h
llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h
llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp
llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt
Modified: llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h?rev=312511&r1=312510&r2=312511&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/JITSymbol.h Mon Sep 4 20:34:09 2017
@@ -89,9 +89,15 @@ public:
/// @brief Implicitly convert to the underlying flags type.
operator UnderlyingType&() { return Flags; }
+ /// @brief Implicitly convert to the underlying flags type.
+ operator const UnderlyingType&() const { return Flags; }
+
/// @brief Return a reference to the target-specific flags.
TargetFlagsType& getTargetFlags() { return TargetFlags; }
+ /// @brief Return a reference to the target-specific flags.
+ const TargetFlagsType& getTargetFlags() const { return TargetFlags; }
+
/// Construct a JITSymbolFlags value based on the flags of the given global
/// value.
static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
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=312511&r1=312510&r2=312511&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h Mon Sep 4 20:34:09 2017
@@ -33,7 +33,8 @@ enum class OrcErrorCode : int {
RPCResponseAbandoned,
UnexpectedRPCCall,
UnexpectedRPCResponse,
- UnknownErrorCodeFromRemote
+ UnknownErrorCodeFromRemote,
+ UnknownResourceHandle
};
std::error_code orcError(OrcErrorCode ErrCode);
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h?rev=312511&r1=312510&r2=312511&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h Mon Sep 4 20:34:09 2017
@@ -25,6 +25,37 @@ namespace orc {
namespace remote {
+/// Template error for missing resources.
+template <typename ResourceIdT>
+class ResourceNotFound
+ : public ErrorInfo<ResourceNotFound<ResourceIdT>> {
+public:
+ static char ID;
+
+ ResourceNotFound(ResourceIdT ResourceId,
+ std::string ResourceDescription = "")
+ : ResourceId(std::move(ResourceId)),
+ ResourceDescription(std::move(ResourceDescription)) {}
+
+ std::error_code convertToErrorCode() const override {
+ return orcError(OrcErrorCode::UnknownResourceHandle);
+ }
+
+ void log(raw_ostream &OS) const override {
+ OS << (ResourceDescription.empty()
+ ? "Remote resource with id "
+ : ResourceDescription)
+ << " " << ResourceId << " not found";
+ }
+
+private:
+ ResourceIdT ResourceId;
+ std::string ResourceDescription;
+};
+
+template <typename ResourceIdT>
+char ResourceNotFound<ResourceIdT>::ID = 0;
+
class DirectBufferWriter {
public:
DirectBufferWriter() = default;
@@ -45,6 +76,32 @@ private:
namespace rpc {
+template <>
+class RPCTypeName<JITSymbolFlags> {
+public:
+ static const char *getName() { return "JITSymbolFlags"; }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, JITSymbolFlags> {
+public:
+
+ static Error serialize(ChannelT &C, const JITSymbolFlags &Flags) {
+ return serializeSeq(C, static_cast<JITSymbolFlags::UnderlyingType>(Flags),
+ Flags.getTargetFlags());
+ }
+
+ static Error deserialize(ChannelT &C, JITSymbolFlags &Flags) {
+ JITSymbolFlags::UnderlyingType JITFlags;
+ JITSymbolFlags::TargetFlagsType TargetFlags;
+ if (auto Err = deserializeSeq(C, JITFlags, TargetFlags))
+ return Err;
+ Flags = JITSymbolFlags(static_cast<JITSymbolFlags::FlagNames>(JITFlags),
+ TargetFlags);
+ return Error::success();
+ }
+};
+
template <> class RPCTypeName<remote::DirectBufferWriter> {
public:
static const char *getName() { return "DirectBufferWriter"; }
Added: llvm/trunk/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h?rev=312511&view=auto
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h (added)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h Mon Sep 4 20:34:09 2017
@@ -0,0 +1,498 @@
+//===------ RemoteObjectLayer.h - Forwards objs to a remote -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Forwards objects to a remote object layer via RPC.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
+#define LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
+
+#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
+#include <map>
+
+namespace llvm {
+namespace orc {
+
+/// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
+class RemoteObjectLayerAPI {
+public:
+
+ using ObjHandleT = remote::ResourceIdMgr::ResourceId;
+
+protected:
+
+ using RemoteSymbolId = remote::ResourceIdMgr::ResourceId;
+ using RemoteSymbol = std::pair<RemoteSymbolId, JITSymbolFlags>;
+
+public:
+
+ using BadSymbolHandleError = remote::ResourceNotFound<RemoteSymbolId>;
+ using BadObjectHandleError = remote::ResourceNotFound<ObjHandleT>;
+
+protected:
+
+ static const ObjHandleT InvalidObjectHandleId = 0;
+ static const RemoteSymbolId NullSymbolId = 0;
+
+ class AddObject
+ : public rpc::Function<AddObject, Expected<ObjHandleT>(std::string)> {
+ public:
+ static const char *getName() { return "AddObject"; }
+ };
+
+ class RemoveObject
+ : public rpc::Function<RemoveObject, Error(ObjHandleT)> {
+ public:
+ static const char *getName() { return "RemoveObject"; }
+ };
+
+ class FindSymbol
+ : public rpc::Function<FindSymbol, Expected<RemoteSymbol>(std::string,
+ bool)> {
+ public:
+ static const char *getName() { return "FindSymbol"; }
+ };
+
+ class FindSymbolIn
+ : public rpc::Function<FindSymbolIn,
+ Expected<RemoteSymbol>(ObjHandleT, std::string,
+ bool)> {
+ public:
+ static const char *getName() { return "FindSymbolIn"; }
+ };
+
+ class EmitAndFinalize
+ : public rpc::Function<EmitAndFinalize,
+ Error(ObjHandleT)> {
+ public:
+ static const char *getName() { return "EmitAndFinalize"; }
+ };
+
+ class Lookup
+ : public rpc::Function<Lookup,
+ Expected<RemoteSymbol>(ObjHandleT, std::string)> {
+ public:
+ static const char *getName() { return "Lookup"; }
+ };
+
+ class LookupInLogicalDylib
+ : public rpc::Function<LookupInLogicalDylib,
+ Expected<RemoteSymbol>(ObjHandleT, std::string)> {
+ public:
+ static const char *getName() { return "LookupInLogicalDylib"; }
+ };
+
+ class ReleaseRemoteSymbol
+ : public rpc::Function<ReleaseRemoteSymbol, Error(RemoteSymbolId)> {
+ public:
+ static const char *getName() { return "ReleaseRemoteSymbol"; }
+ };
+
+ class MaterializeRemoteSymbol
+ : public rpc::Function<MaterializeRemoteSymbol,
+ Expected<JITTargetAddress>(RemoteSymbolId)> {
+ public:
+ static const char *getName() { return "MaterializeRemoteSymbol"; }
+ };
+};
+
+/// Base class containing common utilities for RemoteObjectClientLayer and
+/// RemoteObjectServerLayer.
+template <typename RPCEndpoint>
+class RemoteObjectLayer : public RemoteObjectLayerAPI {
+public:
+
+ RemoteObjectLayer(RPCEndpoint &Remote,
+ std::function<void(Error)> ReportError)
+ : Remote(Remote), ReportError(std::move(ReportError)),
+ SymbolIdMgr(NullSymbolId + 1) {
+ using ThisT = RemoteObjectLayer<RPCEndpoint>;
+ Remote.template addHandler<ReleaseRemoteSymbol>(
+ *this, &ThisT::handleReleaseRemoteSymbol);
+ Remote.template addHandler<MaterializeRemoteSymbol>(
+ *this, &ThisT::handleMaterializeRemoteSymbol);
+ }
+
+protected:
+
+ class RemoteSymbolMaterializer {
+ public:
+
+ RemoteSymbolMaterializer(RemoteObjectLayer &C,
+ RemoteSymbolId Id)
+ : C(C), Id(Id) {}
+
+ RemoteSymbolMaterializer(const RemoteSymbolMaterializer &Other)
+ : C(Other.C), Id(Other.Id) {
+ // FIXME: This is a horrible, auto_ptr-style, copy-as-move operation.
+ // It should be removed as soon as LLVM has C++14's generalized
+ // lambda capture (at which point the materializer can be moved
+ // into the lambda in remoteToJITSymbol below).
+ const_cast<RemoteSymbolMaterializer&>(Other).Id = 0;
+ }
+
+ RemoteSymbolMaterializer&
+ operator=(const RemoteSymbolMaterializer&) = delete;
+
+ ~RemoteSymbolMaterializer() {
+ if (Id)
+ C.releaseRemoteSymbol(Id);
+ }
+
+ Expected<JITTargetAddress> materialize() {
+ auto Addr = C.materializeRemoteSymbol(Id);
+ Id = 0;
+ return Addr;
+ }
+
+ private:
+ RemoteObjectLayer &C;
+ RemoteSymbolId Id;
+ };
+
+ RemoteSymbol nullRemoteSymbol() {
+ return RemoteSymbol(0, JITSymbolFlags());
+ }
+
+ // Creates a StringError that contains a copy of Err's log message, then
+ // sends that StringError to ReportError.
+ //
+ // This allows us to locally log error messages for errors that will actually
+ // be delivered to the remote.
+ Error teeLog(Error Err) {
+ return handleErrors(std::move(Err),
+ [this](std::unique_ptr<ErrorInfoBase> EIB) {
+ ReportError(make_error<StringError>(
+ EIB->message(),
+ EIB->convertToErrorCode()));
+ return Error(std::move(EIB));
+ });
+ }
+
+ Error badRemoteSymbolIdError(RemoteSymbolId Id) {
+ return make_error<BadSymbolHandleError>(Id, "Remote JIT Symbol");
+ }
+
+ Error badObjectHandleError(ObjHandleT H) {
+ return make_error<RemoteObjectLayerAPI::BadObjectHandleError>(
+ H, "Bad object handle");
+ }
+
+ Expected<RemoteSymbol> jitSymbolToRemote(JITSymbol Sym) {
+ if (Sym) {
+ auto Id = SymbolIdMgr.getNext();
+ auto Flags = Sym.getFlags();
+ assert(!InUseSymbols.count(Id) && "Symbol id already in use");
+ InUseSymbols.insert(std::make_pair(Id, std::move(Sym)));
+ return RemoteSymbol(Id, Flags);
+ } else if (auto Err = Sym.takeError())
+ return teeLog(std::move(Err));
+ // else...
+ return nullRemoteSymbol();
+ }
+
+ JITSymbol remoteToJITSymbol(Expected<RemoteSymbol> RemoteSymOrErr) {
+ if (RemoteSymOrErr) {
+ auto &RemoteSym = *RemoteSymOrErr;
+ RemoteSymbolMaterializer RSM(*this, RemoteSym.first);
+ auto Sym =
+ JITSymbol([RSM]() mutable { return RSM.materialize(); },
+ RemoteSym.second);
+ return Sym;
+ } else
+ return RemoteSymOrErr.takeError();
+ }
+
+ template <typename Func, typename... ArgTs>
+ using CallBResult = decltype(foldRemoteERror(
+ std::declval<RPCEndpoint>()
+ .template callB<Func>(
+ std::declval<const ArgTs&>()...)));
+
+ /// API checked callB function.
+ template <typename Func, typename... ArgTs>
+ CallBResult<Func> callB(const ArgTs &... Args) {
+ return foldRemoteError(Remote.template callB<Func>(Args...));
+ }
+
+ RPCEndpoint &Remote;
+ std::function<void(Error)> ReportError;
+
+private:
+
+ void releaseRemoteSymbol(RemoteSymbolId Id) {
+ if (auto Err = Remote.template callB<ReleaseRemoteSymbol>(Id))
+ ReportError(std::move(Err));
+ }
+
+ Expected<JITTargetAddress> materializeRemoteSymbol(RemoteSymbolId Id) {
+ return Remote.template callB<MaterializeRemoteSymbol>(Id);
+ }
+
+ Error handleReleaseRemoteSymbol(RemoteSymbolId Id) {
+ auto SI = InUseSymbols.find(Id);
+ if (SI != InUseSymbols.end()) {
+ InUseSymbols.erase(SI);
+ return Error::success();
+ } else
+ return teeLog(badRemoteSymbolIdError(Id));
+ }
+
+ Expected<JITTargetAddress> handleMaterializeRemoteSymbol(RemoteSymbolId Id) {
+ auto SI = InUseSymbols.find(Id);
+ if (SI != InUseSymbols.end()) {
+ auto AddrOrErr = SI->second.getAddress();
+ InUseSymbols.erase(SI);
+ SymbolIdMgr.release(Id);
+ if (AddrOrErr)
+ return *AddrOrErr;
+ else
+ return teeLog(AddrOrErr.takeError());
+ } else {
+ return teeLog(badRemoteSymbolIdError(Id));
+ }
+ }
+
+ remote::ResourceIdMgr SymbolIdMgr;
+ std::map<RemoteSymbolId, JITSymbol> InUseSymbols;
+};
+
+template <typename RPCEndpoint>
+class RemoteObjectClientLayer : public RemoteObjectLayer<RPCEndpoint> {
+private:
+
+ using AddObject = RemoteObjectLayerAPI::AddObject;
+ using RemoveObject = RemoteObjectLayerAPI::RemoveObject;
+ using FindSymbol = RemoteObjectLayerAPI::FindSymbol;
+ using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn;
+ using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize;
+ using Lookup = RemoteObjectLayerAPI::Lookup;
+ using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib;
+
+ using RemoteObjectLayer<RPCEndpoint>::teeLog;
+ using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError;
+ using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol;
+
+public:
+
+ using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
+ using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
+
+ using ObjectPtr =
+ std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
+
+ RemoteObjectClientLayer(RPCEndpoint &Remote,
+ std::function<void(Error)> ReportError)
+ : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)) {
+ using ThisT = RemoteObjectClientLayer<RPCEndpoint>;
+ Remote.template addHandler<Lookup>(*this, &ThisT::lookup);
+ Remote.template addHandler<LookupInLogicalDylib>(
+ *this, &ThisT::lookupInLogicalDylib);
+ }
+
+ Expected<ObjHandleT>
+ addObject(ObjectPtr Object, std::shared_ptr<JITSymbolResolver> Resolver) {
+ StringRef ObjBuffer = Object->getBinary()->getData();
+ if (auto HandleOrErr =
+ this->Remote.template callB<AddObject>(ObjBuffer)) {
+ auto &Handle = *HandleOrErr;
+ // FIXME: Return an error for this:
+ assert(!Resolvers.count(Handle) && "Handle already in use?");
+ Resolvers[Handle] = std::move(Resolver);
+ return Handle;
+ } else
+ return HandleOrErr.takeError();
+ }
+
+ Error removeObject(ObjHandleT H) {
+ return this->Remote.template callB<RemoveObject>(H);
+ }
+
+ JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
+ return remoteToJITSymbol(
+ this->Remote.template callB<FindSymbol>(Name,
+ ExportedSymbolsOnly));
+ }
+
+ JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) {
+ return remoteToJITSymbol(
+ this->Remote.template callB<FindSymbolIn>(H, Name,
+ ExportedSymbolsOnly));
+ }
+
+ Error emitAndFinalize(ObjHandleT H) {
+ return this->Remote.template callB<EmitAndFinalize>(H);
+ }
+
+private:
+
+ Expected<RemoteSymbol> lookup(ObjHandleT H, const std::string &Name) {
+ auto RI = Resolvers.find(H);
+ if (RI != Resolvers.end()) {
+ return this->jitSymbolToRemote(RI->second->findSymbol(Name));
+ } else
+ return teeLog(badObjectHandleError(H));
+ }
+
+ Expected<RemoteSymbol> lookupInLogicalDylib(ObjHandleT H,
+ const std::string &Name) {
+ auto RI = Resolvers.find(H);
+ if (RI != Resolvers.end())
+ return this->jitSymbolToRemote(
+ RI->second->findSymbolInLogicalDylib(Name));
+ else
+ return teeLog(badObjectHandleError(H));
+ }
+
+ std::map<remote::ResourceIdMgr::ResourceId,
+ std::shared_ptr<JITSymbolResolver>> Resolvers;
+};
+
+template <typename BaseLayerT, typename RPCEndpoint>
+class RemoteObjectServerLayer : public RemoteObjectLayer<RPCEndpoint> {
+private:
+
+ using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
+ using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
+
+ using AddObject = RemoteObjectLayerAPI::AddObject;
+ using RemoveObject = RemoteObjectLayerAPI::RemoveObject;
+ using FindSymbol = RemoteObjectLayerAPI::FindSymbol;
+ using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn;
+ using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize;
+ using Lookup = RemoteObjectLayerAPI::Lookup;
+ using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib;
+
+ using RemoteObjectLayer<RPCEndpoint>::teeLog;
+ using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError;
+ using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol;
+
+public:
+
+ RemoteObjectServerLayer(BaseLayerT &BaseLayer,
+ RPCEndpoint &Remote,
+ std::function<void(Error)> ReportError)
+ : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)),
+ BaseLayer(BaseLayer), HandleIdMgr(1) {
+ using ThisT = RemoteObjectServerLayer<BaseLayerT, RPCEndpoint>;
+
+ Remote.template addHandler<AddObject>(*this, &ThisT::addObject);
+ Remote.template addHandler<RemoveObject>(*this, &ThisT::removeObject);
+ Remote.template addHandler<FindSymbol>(*this, &ThisT::findSymbol);
+ Remote.template addHandler<FindSymbolIn>(*this, &ThisT::findSymbolIn);
+ Remote.template addHandler<EmitAndFinalize>(*this, &ThisT::emitAndFinalize);
+ }
+
+private:
+
+ class StringMemoryBuffer : public MemoryBuffer {
+ public:
+ StringMemoryBuffer(std::string Buffer)
+ : Buffer(std::move(Buffer)) {
+ init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(),
+ false);
+ }
+
+ BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
+ private:
+ std::string Buffer;
+ };
+
+ JITSymbol lookup(ObjHandleT Id, const std::string &Name) {
+ return remoteToJITSymbol(
+ this->Remote.template callB<Lookup>(Id, Name));
+ }
+
+ JITSymbol lookupInLogicalDylib(ObjHandleT Id, const std::string &Name) {
+ return remoteToJITSymbol(
+ this->Remote.template callB<LookupInLogicalDylib>(Id, Name));
+ }
+
+ Expected<ObjHandleT> addObject(std::string ObjBuffer) {
+ auto Buffer = llvm::make_unique<StringMemoryBuffer>(std::move(ObjBuffer));
+ if (auto ObjectOrErr =
+ object::ObjectFile::createObjectFile(Buffer->getMemBufferRef())) {
+ auto Object =
+ std::make_shared<object::OwningBinary<object::ObjectFile>>(
+ std::move(*ObjectOrErr), std::move(Buffer));
+
+ auto Id = HandleIdMgr.getNext();
+ assert(!BaseLayerHandles.count(Id) && "Id already in use?");
+
+ auto Resolver =
+ createLambdaResolver(
+ [this, Id](const std::string &Name) { return lookup(Id, Name); },
+ [this, Id](const std::string &Name) {
+ return lookupInLogicalDylib(Id, Name);
+ });
+
+ if (auto HandleOrErr =
+ BaseLayer.addObject(std::move(Object), std::move(Resolver))) {
+ BaseLayerHandles[Id] = std::move(*HandleOrErr);
+ return Id;
+ } else
+ return teeLog(HandleOrErr.takeError());
+ } else
+ return teeLog(ObjectOrErr.takeError());
+ }
+
+ Error removeObject(ObjHandleT H) {
+ auto HI = BaseLayerHandles.find(H);
+ if (HI != BaseLayerHandles.end()) {
+ if (auto Err = BaseLayer.removeObject(HI->second))
+ return teeLog(std::move(Err));
+ return Error::success();
+ } else
+ return teeLog(badObjectHandleError(H));
+ }
+
+ Expected<RemoteSymbol> findSymbol(const std::string &Name,
+ bool ExportedSymbolsOnly) {
+ if (auto Sym = BaseLayer.findSymbol(Name, ExportedSymbolsOnly))
+ return this->jitSymbolToRemote(std::move(Sym));
+ else if (auto Err = Sym.takeError())
+ return teeLog(std::move(Err));
+ return this->nullRemoteSymbol();
+ }
+
+ Expected<RemoteSymbol> findSymbolIn(ObjHandleT H, const std::string &Name,
+ bool ExportedSymbolsOnly) {
+ auto HI = BaseLayerHandles.find(H);
+ if (HI != BaseLayerHandles.end()) {
+ if (auto Sym = BaseLayer.findSymbolIn(HI->second, Name, ExportedSymbolsOnly))
+ return this->jitSymbolToRemote(std::move(Sym));
+ else if (auto Err = Sym.takeError())
+ return teeLog(std::move(Err));
+ return this->nullRemoteSymbol();
+ } else
+ return teeLog(badObjectHandleError(H));
+ }
+
+ Error emitAndFinalize(ObjHandleT H) {
+ auto HI = BaseLayerHandles.find(H);
+ if (HI != BaseLayerHandles.end()) {
+ if (auto Err = BaseLayer.emitAndFinalize(HI->second))
+ return teeLog(std::move(Err));
+ return Error::success();
+ } else
+ return teeLog(badObjectHandleError(H));
+ }
+
+ BaseLayerT &BaseLayer;
+ remote::ResourceIdMgr HandleIdMgr;
+ std::map<ObjHandleT, typename BaseLayerT::ObjHandleT> BaseLayerHandles;
+};
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp?rev=312511&r1=312510&r2=312511&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp Mon Sep 4 20:34:09 2017
@@ -54,6 +54,8 @@ public:
case OrcErrorCode::UnknownErrorCodeFromRemote:
return "Unknown error returned from remote RPC function "
"(Use StringError to get error message)";
+ case OrcErrorCode::UnknownResourceHandle:
+ return "Unknown resource handle";
}
llvm_unreachable("Unhandled error code");
}
Modified: llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt?rev=312511&r1=312510&r2=312511&view=diff
==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt (original)
+++ llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt Mon Sep 4 20:34:09 2017
@@ -18,6 +18,7 @@ add_llvm_unittest(OrcJITTests
OrcCAPITest.cpp
OrcTestCommon.cpp
QueueChannel.cpp
+ RemoteObjectLayerTest.cpp
RPCUtilsTest.cpp
RTDyldObjectLinkingLayerTest.cpp
)
Added: llvm/trunk/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp?rev=312511&view=auto
==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp (added)
+++ llvm/trunk/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp Mon Sep 4 20:34:09 2017
@@ -0,0 +1,576 @@
+//===---------------------- RemoteObjectLayerTest.cpp ---------------------===//
+//
+// 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/CompileUtils.h"
+#include "llvm/ExecutionEngine/Orc/NullResolver.h"
+#include "llvm/ExecutionEngine/Orc/RemoteObjectLayer.h"
+#include "OrcTestCommon.h"
+#include "QueueChannel.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::orc;
+
+namespace {
+
+class MockObjectLayer {
+public:
+
+ using ObjHandleT = uint64_t;
+
+ using ObjectPtr =
+ std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
+
+ using LookupFn = std::function<JITSymbol(StringRef, bool)>;
+ using SymbolLookupTable = std::map<ObjHandleT, LookupFn>;
+
+ using AddObjectFtor =
+ std::function<Expected<ObjHandleT>(ObjectPtr, SymbolLookupTable&)>;
+
+ class ObjectNotFound : public remote::ResourceNotFound<ObjHandleT> {
+ public:
+ ObjectNotFound(ObjHandleT H) : ResourceNotFound(H, "Object handle") {}
+ };
+
+ MockObjectLayer(AddObjectFtor AddObject)
+ : AddObject(std::move(AddObject)) {}
+
+ Expected<ObjHandleT> addObject(ObjectPtr Obj,
+ std::shared_ptr<JITSymbolResolver> Resolver) {
+ return AddObject(Obj, SymTab);
+ }
+
+ Error removeObject(ObjHandleT H) {
+ if (SymTab.count(H))
+ return Error::success();
+ else
+ return make_error<ObjectNotFound>(H);
+ }
+
+ JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
+ for (auto KV : SymTab) {
+ if (auto Sym = KV.second(Name, ExportedSymbolsOnly))
+ return Sym;
+ else if (auto Err = Sym.takeError())
+ return std::move(Err);
+ }
+ return JITSymbol(nullptr);
+ }
+
+ JITSymbol findSymbolIn(ObjHandleT H, StringRef Name,
+ bool ExportedSymbolsOnly) {
+ auto LI = SymTab.find(H);
+ if (LI != SymTab.end())
+ return LI->second(Name, ExportedSymbolsOnly);
+ else
+ return make_error<ObjectNotFound>(H);
+ }
+
+ Error emitAndFinalize(ObjHandleT H) {
+ if (SymTab.count(H))
+ return Error::success();
+ else
+ return make_error<ObjectNotFound>(H);
+ }
+
+private:
+ AddObjectFtor AddObject;
+ SymbolLookupTable SymTab;
+};
+
+using RPCEndpoint = rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>;
+
+MockObjectLayer::ObjectPtr createTestObject() {
+ OrcNativeTarget::initialize();
+ auto TM = std::unique_ptr<TargetMachine>(EngineBuilder().selectTarget());
+
+ if (!TM)
+ return nullptr;
+
+ LLVMContext Ctx;
+ ModuleBuilder MB(Ctx, TM->getTargetTriple().str(), "TestModule");
+ MB.getModule()->setDataLayout(TM->createDataLayout());
+ auto *Main = MB.createFunctionDecl<void(int, char**)>("main");
+ Main->getBasicBlockList().push_back(BasicBlock::Create(Ctx));
+ IRBuilder<> B(&Main->back());
+ B.CreateRet(ConstantInt::getSigned(Type::getInt32Ty(Ctx), 42));
+
+ SimpleCompiler IRCompiler(*TM);
+ return std::make_shared<object::OwningBinary<object::ObjectFile>>(
+ IRCompiler(*MB.getModule()));
+}
+
+TEST(RemoteObjectLayer, AddObject) {
+ llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
+ auto TestObject = createTestObject();
+ if (!TestObject)
+ return;
+
+ auto Channels = createPairedQueueChannels();
+
+ auto ReportError =
+ [](Error Err) {
+ logAllUnhandledErrors(std::move(Err), llvm::errs(), "");
+ };
+
+ // Copy the bytes out of the test object: the copy will be used to verify
+ // that the original is correctly transmitted over RPC to the mock layer.
+ StringRef ObjBytes = TestObject->getBinary()->getData();
+ std::vector<char> ObjContents(ObjBytes.size());
+ std::copy(ObjBytes.begin(), ObjBytes.end(), ObjContents.begin());
+
+ RPCEndpoint ClientEP(*Channels.first, true);
+ RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
+
+ RPCEndpoint ServerEP(*Channels.second, true);
+ MockObjectLayer BaseLayer(
+ [&ObjContents](MockObjectLayer::ObjectPtr Obj,
+ MockObjectLayer::SymbolLookupTable &SymTab) {
+
+ // Check that the received object file content matches the original.
+ StringRef RPCObjContents = Obj->getBinary()->getData();
+ EXPECT_EQ(RPCObjContents.size(), ObjContents.size())
+ << "RPC'd object file has incorrect size";
+ EXPECT_TRUE(std::equal(RPCObjContents.begin(), RPCObjContents.end(),
+ ObjContents.begin()))
+ << "RPC'd object file content does not match original content";
+
+ return 1;
+ });
+ RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
+ ServerEP,
+ ReportError);
+
+ bool Finished = false;
+ ServerEP.addHandler<remote::utils::TerminateSession>(
+ [&]() { Finished = true; }
+ );
+
+ auto ServerThread =
+ std::thread([&]() {
+ while (!Finished)
+ cantFail(ServerEP.handleOne());
+ });
+
+ cantFail(Client.addObject(std::move(TestObject),
+ std::make_shared<NullResolver>()));
+ cantFail(ClientEP.callB<remote::utils::TerminateSession>());
+ ServerThread.join();
+}
+
+TEST(RemoteObjectLayer, AddObjectFailure) {
+ llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
+ auto TestObject = createTestObject();
+ if (!TestObject)
+ return;
+
+ auto Channels = createPairedQueueChannels();
+
+ auto ReportError =
+ [](Error Err) {
+ auto ErrMsg = toString(std::move(Err));
+ EXPECT_EQ(ErrMsg, "AddObjectFailure - Test Message")
+ << "Expected error string to be \"AddObjectFailure - Test Message\"";
+ };
+
+ RPCEndpoint ClientEP(*Channels.first, true);
+ RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
+
+ RPCEndpoint ServerEP(*Channels.second, true);
+ MockObjectLayer BaseLayer(
+ [](MockObjectLayer::ObjectPtr Obj,
+ MockObjectLayer::SymbolLookupTable &SymTab)
+ -> Expected<MockObjectLayer::ObjHandleT> {
+ return make_error<StringError>("AddObjectFailure - Test Message",
+ inconvertibleErrorCode());
+ });
+ RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
+ ServerEP,
+ ReportError);
+
+ bool Finished = false;
+ ServerEP.addHandler<remote::utils::TerminateSession>(
+ [&]() { Finished = true; }
+ );
+
+ auto ServerThread =
+ std::thread([&]() {
+ while (!Finished)
+ cantFail(ServerEP.handleOne());
+ });
+
+ auto HandleOrErr =
+ Client.addObject(std::move(TestObject), std::make_shared<NullResolver>());
+
+ EXPECT_FALSE(HandleOrErr) << "Expected error from addObject";
+
+ auto ErrMsg = toString(HandleOrErr.takeError());
+ EXPECT_EQ(ErrMsg, "AddObjectFailure - Test Message")
+ << "Expected error string to be \"AddObjectFailure - Test Message\"";
+
+ cantFail(ClientEP.callB<remote::utils::TerminateSession>());
+ ServerThread.join();
+}
+
+
+TEST(RemoteObjectLayer, RemoveObject) {
+ llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
+ auto TestObject = createTestObject();
+ if (!TestObject)
+ return;
+
+ auto Channels = createPairedQueueChannels();
+
+ auto ReportError =
+ [](Error Err) {
+ logAllUnhandledErrors(std::move(Err), llvm::errs(), "");
+ };
+
+ RPCEndpoint ClientEP(*Channels.first, true);
+ RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
+
+ RPCEndpoint ServerEP(*Channels.second, true);
+
+ MockObjectLayer BaseLayer(
+ [](MockObjectLayer::ObjectPtr Obj,
+ MockObjectLayer::SymbolLookupTable &SymTab) {
+ SymTab[1] = MockObjectLayer::LookupFn();
+ return 1;
+ });
+ RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
+ ServerEP,
+ ReportError);
+
+ bool Finished = false;
+ ServerEP.addHandler<remote::utils::TerminateSession>(
+ [&]() { Finished = true; }
+ );
+
+ auto ServerThread =
+ std::thread([&]() {
+ while (!Finished)
+ cantFail(ServerEP.handleOne());
+ });
+
+ auto H = cantFail(Client.addObject(std::move(TestObject),
+ std::make_shared<NullResolver>()));
+
+ cantFail(Client.removeObject(H));
+
+ cantFail(ClientEP.callB<remote::utils::TerminateSession>());
+ ServerThread.join();
+}
+
+TEST(RemoteObjectLayer, RemoveObjectFailure) {
+ llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
+ auto TestObject = createTestObject();
+ if (!TestObject)
+ return;
+
+ auto Channels = createPairedQueueChannels();
+
+ auto ReportError =
+ [](Error Err) {
+ auto ErrMsg = toString(std::move(Err));
+ EXPECT_EQ(ErrMsg, "Object handle 42 not found")
+ << "Expected error string to be \"Object handle 42 not found\"";
+ };
+
+ RPCEndpoint ClientEP(*Channels.first, true);
+ RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
+
+ RPCEndpoint ServerEP(*Channels.second, true);
+
+ // AddObject lambda does not update symbol table, so removeObject will treat
+ // this as a bad object handle.
+ MockObjectLayer BaseLayer(
+ [](MockObjectLayer::ObjectPtr Obj,
+ MockObjectLayer::SymbolLookupTable &SymTab) {
+ return 42;
+ });
+ RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
+ ServerEP,
+ ReportError);
+
+ bool Finished = false;
+ ServerEP.addHandler<remote::utils::TerminateSession>(
+ [&]() { Finished = true; }
+ );
+
+ auto ServerThread =
+ std::thread([&]() {
+ while (!Finished)
+ cantFail(ServerEP.handleOne());
+ });
+
+ auto H = cantFail(Client.addObject(std::move(TestObject),
+ std::make_shared<NullResolver>()));
+
+ auto Err = Client.removeObject(H);
+ EXPECT_TRUE(!!Err) << "Expected error from removeObject";
+
+ auto ErrMsg = toString(std::move(Err));
+ EXPECT_EQ(ErrMsg, "Object handle 42 not found")
+ << "Expected error string to be \"Object handle 42 not found\"";
+
+ cantFail(ClientEP.callB<remote::utils::TerminateSession>());
+ ServerThread.join();
+}
+
+TEST(RemoteObjectLayer, FindSymbol) {
+ llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
+ auto TestObject = createTestObject();
+ if (!TestObject)
+ return;
+
+ auto Channels = createPairedQueueChannels();
+
+ auto ReportError =
+ [](Error Err) {
+ auto ErrMsg = toString(std::move(Err));
+ EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
+ << "Expected error string to be \"Object handle 42 not found\"";
+ };
+
+ RPCEndpoint ClientEP(*Channels.first, true);
+ RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
+
+ RPCEndpoint ServerEP(*Channels.second, true);
+
+ // AddObject lambda does not update symbol table, so removeObject will treat
+ // this as a bad object handle.
+ MockObjectLayer BaseLayer(
+ [](MockObjectLayer::ObjectPtr Obj,
+ MockObjectLayer::SymbolLookupTable &SymTab) {
+ SymTab[42] =
+ [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol {
+ if (Name == "foobar")
+ return JITSymbol(0x12348765, JITSymbolFlags::Exported);
+ return make_error<JITSymbolNotFound>(Name);
+ };
+ return 42;
+ });
+ RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
+ ServerEP,
+ ReportError);
+
+ bool Finished = false;
+ ServerEP.addHandler<remote::utils::TerminateSession>(
+ [&]() { Finished = true; }
+ );
+
+ auto ServerThread =
+ std::thread([&]() {
+ while (!Finished)
+ cantFail(ServerEP.handleOne());
+ });
+
+ cantFail(Client.addObject(std::move(TestObject),
+ std::make_shared<NullResolver>()));
+
+ auto Sym1 = Client.findSymbol("foobar", true);
+
+ EXPECT_TRUE(!!Sym1) << "Symbol 'foobar' should be findable";
+ EXPECT_EQ(cantFail(Sym1.getAddress()), 0x12348765ULL)
+ << "Symbol 'foobar' does not return the correct address";
+
+ auto Sym2 = Client.findSymbol("barbaz", true);
+ EXPECT_FALSE(!!Sym2) << "Symbol 'barbaz' should not be findable";
+ auto Err = Sym2.takeError();
+ EXPECT_TRUE(!!Err) << "Sym2 should contain an error value";
+ auto ErrMsg = toString(std::move(Err));
+ EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
+ << "Expected symbol-not-found error for Sym2";
+
+ cantFail(ClientEP.callB<remote::utils::TerminateSession>());
+ ServerThread.join();
+}
+
+TEST(RemoteObjectLayer, FindSymbolIn) {
+ llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
+ auto TestObject = createTestObject();
+ if (!TestObject)
+ return;
+
+ auto Channels = createPairedQueueChannels();
+
+ auto ReportError =
+ [](Error Err) {
+ auto ErrMsg = toString(std::move(Err));
+ EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
+ << "Expected error string to be \"Object handle 42 not found\"";
+ };
+
+ RPCEndpoint ClientEP(*Channels.first, true);
+ RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
+
+ RPCEndpoint ServerEP(*Channels.second, true);
+
+ // AddObject lambda does not update symbol table, so removeObject will treat
+ // this as a bad object handle.
+ MockObjectLayer BaseLayer(
+ [](MockObjectLayer::ObjectPtr Obj,
+ MockObjectLayer::SymbolLookupTable &SymTab) {
+ SymTab[42] =
+ [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol {
+ if (Name == "foobar")
+ return JITSymbol(0x12348765, JITSymbolFlags::Exported);
+ return make_error<JITSymbolNotFound>(Name);
+ };
+ // Dummy symbol table entry - this should not be visible to
+ // findSymbolIn.
+ SymTab[43] =
+ [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol {
+ if (Name == "barbaz")
+ return JITSymbol(0xdeadbeef, JITSymbolFlags::Exported);
+ return make_error<JITSymbolNotFound>(Name);
+ };
+
+ return 42;
+ });
+ RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
+ ServerEP,
+ ReportError);
+
+ bool Finished = false;
+ ServerEP.addHandler<remote::utils::TerminateSession>(
+ [&]() { Finished = true; }
+ );
+
+ auto ServerThread =
+ std::thread([&]() {
+ while (!Finished)
+ cantFail(ServerEP.handleOne());
+ });
+
+ auto H = cantFail(Client.addObject(std::move(TestObject),
+ std::make_shared<NullResolver>()));
+
+ auto Sym1 = Client.findSymbolIn(H, "foobar", true);
+
+ EXPECT_TRUE(!!Sym1) << "Symbol 'foobar' should be findable";
+ EXPECT_EQ(cantFail(Sym1.getAddress()), 0x12348765ULL)
+ << "Symbol 'foobar' does not return the correct address";
+
+ auto Sym2 = Client.findSymbolIn(H, "barbaz", true);
+ EXPECT_FALSE(!!Sym2) << "Symbol 'barbaz' should not be findable";
+ auto Err = Sym2.takeError();
+ EXPECT_TRUE(!!Err) << "Sym2 should contain an error value";
+ auto ErrMsg = toString(std::move(Err));
+ EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
+ << "Expected symbol-not-found error for Sym2";
+
+ cantFail(ClientEP.callB<remote::utils::TerminateSession>());
+ ServerThread.join();
+}
+
+TEST(RemoteObjectLayer, EmitAndFinalize) {
+ llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
+ auto TestObject = createTestObject();
+ if (!TestObject)
+ return;
+
+ auto Channels = createPairedQueueChannels();
+
+ auto ReportError =
+ [](Error Err) {
+ logAllUnhandledErrors(std::move(Err), llvm::errs(), "");
+ };
+
+ RPCEndpoint ClientEP(*Channels.first, true);
+ RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
+
+ RPCEndpoint ServerEP(*Channels.second, true);
+
+ MockObjectLayer BaseLayer(
+ [](MockObjectLayer::ObjectPtr Obj,
+ MockObjectLayer::SymbolLookupTable &SymTab) {
+ SymTab[1] = MockObjectLayer::LookupFn();
+ return 1;
+ });
+ RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
+ ServerEP,
+ ReportError);
+
+ bool Finished = false;
+ ServerEP.addHandler<remote::utils::TerminateSession>(
+ [&]() { Finished = true; }
+ );
+
+ auto ServerThread =
+ std::thread([&]() {
+ while (!Finished)
+ cantFail(ServerEP.handleOne());
+ });
+
+ auto H = cantFail(Client.addObject(std::move(TestObject),
+ std::make_shared<NullResolver>()));
+
+ auto Err = Client.emitAndFinalize(H);
+ EXPECT_FALSE(!!Err) << "emitAndFinalize should work";
+
+ cantFail(ClientEP.callB<remote::utils::TerminateSession>());
+ ServerThread.join();
+}
+
+TEST(RemoteObjectLayer, EmitAndFinalizeFailure) {
+ llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
+ auto TestObject = createTestObject();
+ if (!TestObject)
+ return;
+
+ auto Channels = createPairedQueueChannels();
+
+ auto ReportError =
+ [](Error Err) {
+ auto ErrMsg = toString(std::move(Err));
+ EXPECT_EQ(ErrMsg, "Object handle 1 not found")
+ << "Expected bad handle error";
+ };
+
+ RPCEndpoint ClientEP(*Channels.first, true);
+ RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
+
+ RPCEndpoint ServerEP(*Channels.second, true);
+
+ MockObjectLayer BaseLayer(
+ [](MockObjectLayer::ObjectPtr Obj,
+ MockObjectLayer::SymbolLookupTable &SymTab) {
+ return 1;
+ });
+ RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
+ ServerEP,
+ ReportError);
+
+ bool Finished = false;
+ ServerEP.addHandler<remote::utils::TerminateSession>(
+ [&]() { Finished = true; }
+ );
+
+ auto ServerThread =
+ std::thread([&]() {
+ while (!Finished)
+ cantFail(ServerEP.handleOne());
+ });
+
+ auto H = cantFail(Client.addObject(std::move(TestObject),
+ std::make_shared<NullResolver>()));
+
+ auto Err = Client.emitAndFinalize(H);
+ EXPECT_TRUE(!!Err) << "emitAndFinalize should work";
+
+ auto ErrMsg = toString(std::move(Err));
+ EXPECT_EQ(ErrMsg, "Object handle 1 not found")
+ << "emitAndFinalize returned incorrect error";
+
+ cantFail(ClientEP.callB<remote::utils::TerminateSession>());
+ ServerThread.join();
+}
+
+}
More information about the llvm-commits
mailing list