[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