[llvm] r286639 - [ORC] Re-apply 286620 with fixes for the ErrorSuccess class.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 14 15:38:37 PST 2016


>
> I had been looking into this as a modules bug, but I've just realized that
> I failed to properly define those variables. I should have a fix
> momentarily.


Nope, nope - they are properly defined. Back to assuming this is a modules
bug. Let me see if I can come up with a workaround. If I can't come up with
a good one I'll revert.

- Lang.

On Mon, Nov 14, 2016 at 3:29 PM, Lang Hames <lhames at gmail.com> wrote:

> HI Vedant,
>
> I had been looking into this as a modules bug, but I've just realized that
> I failed to properly define those variables. I should have a fix
> momentarily.
>
> - Lang.
>
>
> On Mon, Nov 14, 2016 at 12:36 PM, Vedant Kumar <vsk at apple.com> wrote:
>
>> Hi Lang,
>>
>> This commit seems to break the modules RDA bot:
>>
>> http://lab.llvm.org:8080/green/job/clang-stage2-cmake-module
>> sRDA_build/1631
>>
>> FAILED: bin/lli
>>
>> : && /Users/buildslave/jenkins/sharedspace/clang-stage2-cmake-
>> modulesRDA at 2/host-compiler/bin/clang++   -fPIC
>> -fvisibility-inlines-hidden -Wall -W -Wno-unused-parameter -Wwrite-strings
>> -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long
>> -Wcovered-switch-default -Wnon-virtual-dtor -Wdelete-non-virtual-dtor
>> -Werror=date-time -std=c++11 -fmodules -fmodules-cache-path=/Users/bu
>> ildslave/jenkins/sharedspace/clang-stage2-cmake-modulesRDA at 2/clang-build/module.cache
>> -fcxx-modules -gmodules -fcolor-diagnostics -O2 -g -DNDEBUG
>> -Wl,-search_paths_first -Wl,-headerpad_max_install_names -Wl,-dead_strip
>> -rdynamic tools/lli/CMakeFiles/lli.dir/lli.cpp.o
>> tools/lli/CMakeFiles/lli.dir/OrcLazyJIT.cpp.o  -o bin/lli
>> lib/libLLVMCodeGen.a lib/libLLVMCore.a lib/libLLVMExecutionEngine.a
>> lib/libLLVMIRReader.a lib/libLLVMInstrumentation.a lib/libLLVMInterpreter.a
>> lib/libLLVMMC.a lib/libLLVMMCJIT.a lib/libLLVMObject.a lib/libLLVMOrcJIT.a
>> lib/libLLVMRuntimeDyld.a lib/libLLVMSelectionDAG.a lib/libLLVMSupport.a
>> lib/libLLVMTarget.a lib/libLLVMTransformUtils.a lib/libLLVMX86CodeGen.a
>> lib/libLLVMX86AsmPrinter.a lib/libLLVMX86AsmParser.a lib/libLLVMX86Desc.a
>> lib/libLLVMX86Info.a lib/libLLVMX86Disassembler.a lib/libLLVMAsmParser.a
>> lib/libLLVMExecutionEngine.a lib/libLLVMRuntimeDyld.a
>> lib/libLLVMSelectionDAG.a lib/libLLVMAsmPrinter.a lib/libLLVMCodeGen.a
>> lib/libLLVMInstrumentation.a lib/libLLVMBitWriter.a lib/libLLVMScalarOpts.a
>> lib/libLLVMInstCombine.a lib/libLLVMTarget.a lib/libLLVMTransformUtils.a
>> lib/libLLVMAnalysis.a lib/libLLVMProfileData.a
>> lib/libLLVMDebugInfoCodeView.a lib/libLLVMDebugInfoMSF.a
>> lib/libLLVMObject.a lib/libLLVMBitReader.a lib/libLLVMX86AsmPrinter.a
>> lib/libLLVMX86Utils.a lib/libLLVMCore.a lib/libLLVMMCParser.a
>> lib/libLLVMX86Info.a lib/libLLVMMCDisassembler.a lib/libLLVMMC.a
>> lib/libLLVMSupport.a -lcurses -lz -lm lib/libLLVMDemangle.a
>> -Wl,-rpath, at loader_path/../lib && :
>> Undefined symbols for architecture x86_64:
>>   "llvm::orc::rpc::Function<llvm::orc::rpc::detail::RPCBase<
>> llvm::orc::rpc::SingleThreadedRPC<llvm::orc::rpc::RawByteChannel,
>> unsigned int, unsigned int>, llvm::orc::rpc::RawByteChannel, unsigned
>> int, unsigned int>::OrcRPCNegotiate, unsigned int
>> (std::__1::basic_string<char, std::__1::char_traits<char>,
>> std::__1::allocator<char> >)>::Name", referenced from:
>>       llvm::orc::rpc::Function<llvm::orc::rpc::detail::RPCBase<llv
>> m::orc::rpc::SingleThreadedRPC<llvm::orc::rpc::RawByteChannel, unsigned
>> int, unsigned int>, llvm::orc::rpc::RawByteChannel, unsigned int,
>> unsigned int>::OrcRPCNegotiate, unsigned int (std::__1::basic_string<char,
>> std::__1::char_traits<char>, std::__1::allocator<char> >)>::getPrototype()
>> in lli.cpp.o
>>   "llvm::orc::rpc::Function<llvm::orc::rpc::detail::RPCBase<
>> llvm::orc::rpc::SingleThreadedRPC<llvm::orc::rpc::RawByteChannel,
>> unsigned int, unsigned int>, llvm::orc::rpc::RawByteChannel, unsigned
>> int, unsigned int>::OrcRPCNegotiate, unsigned int
>> (std::__1::basic_string<char, std::__1::char_traits<char>,
>> std::__1::allocator<char> >)>::NameMutex", referenced from:
>>       llvm::orc::rpc::Function<llvm::orc::rpc::detail::RPCBase<llv
>> m::orc::rpc::SingleThreadedRPC<llvm::orc::rpc::RawByteChannel, unsigned
>> int, unsigned int>, llvm::orc::rpc::RawByteChannel, unsigned int,
>> unsigned int>::OrcRPCNegotiate, unsigned int (std::__1::basic_string<char,
>> std::__1::char_traits<char>, std::__1::allocator<char> >)>::getPrototype()
>> in lli.cpp.o
>>   "llvm::orc::rpc::Function<llvm::orc::rpc::detail::RPCBase<
>> llvm::orc::rpc::SingleThreadedRPC<llvm::orc::rpc::RawByteChannel,
>> unsigned int, unsigned int>, llvm::orc::rpc::RawByteChannel, unsigned
>> int, unsigned int>::OrcRPCResponse, void ()>::Name", referenced from:
>>       llvm::orc::rpc::Function<llvm::orc::rpc::detail::RPCBase<llv
>> m::orc::rpc::SingleThreadedRPC<llvm::orc::rpc::RawByteChannel, unsigned
>> int, unsigned int>, llvm::orc::rpc::RawByteChannel, unsigned int,
>> unsigned int>::OrcRPCResponse, void ()>::getPrototype() in lli.cpp.o
>>   "llvm::orc::rpc::Function<llvm::orc::rpc::detail::RPCBase<
>> llvm::orc::rpc::SingleThreadedRPC<llvm::orc::rpc::RawByteChannel,
>> unsigned int, unsigned int>, llvm::orc::rpc::RawByteChannel, unsigned
>> int, unsigned int>::OrcRPCResponse, void ()>::NameMutex", referenced from:
>>       llvm::orc::rpc::Function<llvm::orc::rpc::detail::RPCBase<llv
>> m::orc::rpc::SingleThreadedRPC<llvm::orc::rpc::RawByteChannel, unsigned
>> int, unsigned int>, llvm::orc::rpc::RawByteChannel, unsigned int,
>> unsigned int>::OrcRPCResponse, void ()>::getPrototype() in lli.cpp.o
>> ld: symbol(s) not found for architecture x86_64
>>
>> I'm not sure why this isn't breaking the non-modules build.
>>
>> Could you revert this until we understand the failure better?
>>
>> vedant
>>
>> > On Nov 11, 2016, at 1:42 PM, Lang Hames via llvm-commits <
>> llvm-commits at lists.llvm.org> wrote:
>> >
>> > Author: lhames
>> > Date: Fri Nov 11 15:42:09 2016
>> > New Revision: 286639
>> >
>> > URL: http://llvm.org/viewvc/llvm-project?rev=286639&view=rev
>> > Log:
>> > [ORC] Re-apply 286620 with fixes for the ErrorSuccess class.
>> >
>> > Added:
>> >    llvm/trunk/include/llvm/ExecutionEngine/Orc/RawByteChannel.h
>> >      - copied unchanged from r286620, llvm/trunk/include/llvm/Execut
>> ionEngine/Orc/RawByteChannel.h
>> > Removed:
>> >    llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCByteChannel.h
>> >    llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp
>> > Modified:
>> >    llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/
>> RemoteJITUtils.h
>> >    llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.cpp
>> >    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h
>> >    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
>> >    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
>> >    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
>> >    llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization.h
>> >    llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h
>> >    llvm/trunk/lib/ExecutionEngine/Orc/CMakeLists.txt
>> >    llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp
>> >    llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp
>> >    llvm/trunk/tools/lli/RemoteJITUtils.h
>> >    llvm/trunk/tools/lli/lli.cpp
>> >    llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
>> >
>> > Modified: llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/
>> RemoteJITUtils.h
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/examples/Kale
>> idoscope/BuildingAJIT/Chapter5/RemoteJITUtils.h?rev=286639&
>> r1=286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/RemoteJITUtils.h
>> (original)
>> > +++ llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/RemoteJITUtils.h
>> Fri Nov 11 15:42:09 2016
>> > @@ -14,7 +14,7 @@
>> > #ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H
>> > #define LLVM_TOOLS_LLI_REMOTEJITUTILS_H
>> >
>> > -#include "llvm/ExecutionEngine/Orc/RPCByteChannel.h"
>> > +#include "llvm/ExecutionEngine/Orc/RawByteChannel.h"
>> > #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
>> > #include <mutex>
>> >
>> > @@ -25,7 +25,7 @@
>> > #endif
>> >
>> > /// RPC channel that reads from and writes from file descriptors.
>> > -class FDRPCChannel final : public llvm::orc::remote::RPCByteChannel {
>> > +class FDRPCChannel final : public llvm::orc::rpc::RawByteChannel {
>> > public:
>> >   FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
>> >
>> >
>> > Modified: llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.
>> cpp
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/examples/Kale
>> idoscope/BuildingAJIT/Chapter5/toy.cpp?rev=286639&r1=286638&
>> r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.cpp
>> (original)
>> > +++ llvm/trunk/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.cpp Fri
>> Nov 11 15:42:09 2016
>> > @@ -1265,8 +1265,8 @@ int main(int argc, char *argv[]) {
>> >   BinopPrecedence['*'] = 40; // highest.
>> >
>> >   auto TCPChannel = connect();
>> > -  MyRemote Remote = ExitOnErr(MyRemote::Create(*TCPChannel));
>> > -  TheJIT = llvm::make_unique<KaleidoscopeJIT>(Remote);
>> > +  auto Remote = ExitOnErr(MyRemote::Create(*TCPChannel));
>> > +  TheJIT = llvm::make_unique<KaleidoscopeJIT>(*Remote);
>> >
>> >   // Automatically inject a definition for 'printExprResult'.
>> >   FunctionProtos["printExprResult"] =
>> > @@ -1288,7 +1288,7 @@ int main(int argc, char *argv[]) {
>> >   TheJIT = nullptr;
>> >
>> >   // Send a terminate message to the remote to tell it to exit cleanly.
>> > -  ExitOnErr(Remote.terminateSession());
>> > +  ExitOnErr(Remote->terminateSession());
>> >
>> >   return 0;
>> > }
>> >
>> > 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=286639&r1=286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h (original)
>> > +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h Fri Nov 11
>> 15:42:09 2016
>> > @@ -29,6 +29,7 @@ enum class OrcErrorCode : int {
>> >   RemoteIndirectStubsOwnerIdAlreadyInUse,
>> >   UnexpectedRPCCall,
>> >   UnexpectedRPCResponse,
>> > +  UnknownRPCFunction
>> > };
>> >
>> > Error orcError(OrcErrorCode ErrCode);
>> >
>> > Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetC
>> lient.h
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/
>> ExecutionEngine/Orc/OrcRemoteTargetClient.h?rev=286639&r1=
>> 286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
>> (original)
>> > +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
>> Fri Nov 11 15:42:09 2016
>> > @@ -8,7 +8,7 @@
>> > //===-------------------------------------------------------
>> ---------------===//
>> > //
>> > // This file defines the OrcRemoteTargetClient class and helpers. This
>> class
>> > -// can be used to communicate over an RPCByteChannel with an
>> > +// can be used to communicate over an RawByteChannel with an
>> > // OrcRemoteTargetServer instance to support remote-JITing.
>> > //
>> > //===-------------------------------------------------------
>> ---------------===//
>> > @@ -36,23 +36,6 @@ namespace remote {
>> > template <typename ChannelT>
>> > class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
>> > public:
>> > -  // FIXME: Remove move/copy ops once MSVC supports synthesizing move
>> ops.
>> > -
>> > -  OrcRemoteTargetClient(const OrcRemoteTargetClient &) = delete;
>> > -  OrcRemoteTargetClient &operator=(const OrcRemoteTargetClient &) =
>> delete;
>> > -
>> > -  OrcRemoteTargetClient(OrcRemoteTargetClient &&Other)
>> > -      : Channel(Other.Channel), ExistingError(std::move(Other.
>> ExistingError)),
>> > -        RemoteTargetTriple(std::move(Other.RemoteTargetTriple)),
>> > -        RemotePointerSize(std::move(Other.RemotePointerSize)),
>> > -        RemotePageSize(std::move(Other.RemotePageSize)),
>> > -        RemoteTrampolineSize(std::move(Other.RemoteTrampolineSize)),
>> > -        RemoteIndirectStubSize(std::move(Other.RemoteIndirectStubSiz
>> e)),
>> > -        AllocatorIds(std::move(Other.AllocatorIds)),
>> > -        IndirectStubOwnerIds(std::move(Other.IndirectStubOwnerIds)),
>> > -        CallbackManager(std::move(Other.CallbackManager)) {}
>> > -
>> > -  OrcRemoteTargetClient &operator=(OrcRemoteTargetClient &&) = delete;
>> >
>> >   /// Remote memory manager.
>> >   class RCMemoryManager : public RuntimeDyld::MemoryManager {
>> > @@ -62,18 +45,10 @@ public:
>> >       DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
>> >     }
>> >
>> > -    RCMemoryManager(RCMemoryManager &&Other)
>> > -        : Client(std::move(Other.Client)), Id(std::move(Other.Id)),
>> > -          Unmapped(std::move(Other.Unmapped)),
>> > -          Unfinalized(std::move(Other.Unfinalized)) {}
>> > -
>> > -    RCMemoryManager operator=(RCMemoryManager &&Other) {
>> > -      Client = std::move(Other.Client);
>> > -      Id = std::move(Other.Id);
>> > -      Unmapped = std::move(Other.Unmapped);
>> > -      Unfinalized = std::move(Other.Unfinalized);
>> > -      return *this;
>> > -    }
>> > +    RCMemoryManager(const RCMemoryManager&) = delete;
>> > +    RCMemoryManager& operator=(const RCMemoryManager&) = delete;
>> > +    RCMemoryManager(RCMemoryManager&&) = default;
>> > +    RCMemoryManager& operator=(RCMemoryManager&&) = default;
>> >
>> >     ~RCMemoryManager() override {
>> >       Client.destroyRemoteAllocator(Id);
>> > @@ -367,18 +342,10 @@ public:
>> >       Alloc(uint64_t Size, unsigned Align)
>> >           : Size(Size), Align(Align), Contents(new char[Size + Align -
>> 1]) {}
>> >
>> > -      Alloc(Alloc &&Other)
>> > -          : Size(std::move(Other.Size)), Align(std::move(Other.Align)),
>> > -            Contents(std::move(Other.Contents)),
>> > -            RemoteAddr(std::move(Other.RemoteAddr)) {}
>> > -
>> > -      Alloc &operator=(Alloc &&Other) {
>> > -        Size = std::move(Other.Size);
>> > -        Align = std::move(Other.Align);
>> > -        Contents = std::move(Other.Contents);
>> > -        RemoteAddr = std::move(Other.RemoteAddr);
>> > -        return *this;
>> > -      }
>> > +      Alloc(const Alloc&) = delete;
>> > +      Alloc& operator=(const Alloc&) = delete;
>> > +      Alloc(Alloc&&) = default;
>> > +      Alloc& operator=(Alloc&&) = default;
>> >
>> >       uint64_t getSize() const { return Size; }
>> >
>> > @@ -405,24 +372,10 @@ public:
>> >
>> >     struct ObjectAllocs {
>> >       ObjectAllocs() = default;
>> > -
>> > -      ObjectAllocs(ObjectAllocs &&Other)
>> > -          : RemoteCodeAddr(std::move(Other.RemoteCodeAddr)),
>> > -            RemoteRODataAddr(std::move(Other.RemoteRODataAddr)),
>> > -            RemoteRWDataAddr(std::move(Other.RemoteRWDataAddr)),
>> > -            CodeAllocs(std::move(Other.CodeAllocs)),
>> > -            RODataAllocs(std::move(Other.RODataAllocs)),
>> > -            RWDataAllocs(std::move(Other.RWDataAllocs)) {}
>> > -
>> > -      ObjectAllocs &operator=(ObjectAllocs &&Other) {
>> > -        RemoteCodeAddr = std::move(Other.RemoteCodeAddr);
>> > -        RemoteRODataAddr = std::move(Other.RemoteRODataAddr);
>> > -        RemoteRWDataAddr = std::move(Other.RemoteRWDataAddr);
>> > -        CodeAllocs = std::move(Other.CodeAllocs);
>> > -        RODataAllocs = std::move(Other.RODataAllocs);
>> > -        RWDataAllocs = std::move(Other.RWDataAllocs);
>> > -        return *this;
>> > -      }
>> > +      ObjectAllocs(const ObjectAllocs &) = delete;
>> > +      ObjectAllocs& operator=(const ObjectAllocs &) = delete;
>> > +      ObjectAllocs(ObjectAllocs&&) = default;
>> > +      ObjectAllocs& operator=(ObjectAllocs&&) = default;
>> >
>> >       JITTargetAddress RemoteCodeAddr = 0;
>> >       JITTargetAddress RemoteRODataAddr = 0;
>> > @@ -588,23 +541,21 @@ public:
>> >   /// Create an OrcRemoteTargetClient.
>> >   /// Channel is the ChannelT instance to communicate on. It is assumed
>> that
>> >   /// the channel is ready to be read from and written to.
>> > -  static Expected<OrcRemoteTargetClient> Create(ChannelT &Channel) {
>> > +  static Expected<std::unique_ptr<OrcRemoteTargetClient>>
>> > +  Create(ChannelT &Channel) {
>> >     Error Err = Error::success();
>> > -    OrcRemoteTargetClient H(Channel, Err);
>> > +    std::unique_ptr<OrcRemoteTargetClient>
>> > +      Client(new OrcRemoteTargetClient(Channel, Err));
>> >     if (Err)
>> >       return std::move(Err);
>> > -    return Expected<OrcRemoteTargetClient>(std::move(H));
>> > +    return std::move(Client);
>> >   }
>> >
>> >   /// Call the int(void) function at the given address in the target
>> and return
>> >   /// its result.
>> >   Expected<int> callIntVoid(JITTargetAddress Addr) {
>> >     DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr)
>> << "\n");
>> > -
>> > -    auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
>> > -      return listenForCompileRequests(C, Id);
>> > -    };
>> > -    return callSTHandling<CallIntVoid>(Channel, Listen, Addr);
>> > +    return callB<CallIntVoid>(Addr);
>> >   }
>> >
>> >   /// Call the int(int, char*[]) function at the given address in the
>> target and
>> > @@ -613,11 +564,7 @@ public:
>> >                          const std::vector<std::string> &Args) {
>> >     DEBUG(dbgs() << "Calling int(*)(int, char*[]) " <<
>> format("0x%016x", Addr)
>> >                  << "\n");
>> > -
>> > -    auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
>> > -      return listenForCompileRequests(C, Id);
>> > -    };
>> > -    return callSTHandling<CallMain>(Channel, Listen, Addr, Args);
>> > +    return callB<CallMain>(Addr, Args);
>> >   }
>> >
>> >   /// Call the void() function at the given address in the target and
>> wait for
>> > @@ -625,11 +572,7 @@ public:
>> >   Error callVoidVoid(JITTargetAddress Addr) {
>> >     DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
>> >                  << "\n");
>> > -
>> > -    auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
>> > -      return listenForCompileRequests(C, Id);
>> > -    };
>> > -    return callSTHandling<CallVoidVoid>(Channel, Listen, Addr);
>> > +    return callB<CallVoidVoid>(Addr);
>> >   }
>> >
>> >   /// Create an RCMemoryManager which will allocate its memory on the
>> remote
>> > @@ -638,7 +581,7 @@ public:
>> >     assert(!MM && "MemoryManager should be null before creation.");
>> >
>> >     auto Id = AllocatorIds.getNext();
>> > -    if (auto Err = callST<CreateRemoteAllocator>(Channel, Id))
>> > +    if (auto Err = callB<CreateRemoteAllocator>(Id))
>> >       return Err;
>> >     MM = llvm::make_unique<RCMemoryManager>(*this, Id);
>> >     return Error::success();
>> > @@ -649,7 +592,7 @@ public:
>> >   Error createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager>
>> &I) {
>> >     assert(!I && "Indirect stubs manager should be null before
>> creation.");
>> >     auto Id = IndirectStubOwnerIds.getNext();
>> > -    if (auto Err = callST<CreateIndirectStubsOwner>(Channel, Id))
>> > +    if (auto Err = callB<CreateIndirectStubsOwner>(Id))
>> >       return Err;
>> >     I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);
>> >     return Error::success();
>> > @@ -662,7 +605,7 @@ public:
>> >       return std::move(ExistingError);
>> >
>> >     // Emit the resolver block on the JIT server.
>> > -    if (auto Err = callST<EmitResolverBlock>(Channel))
>> > +    if (auto Err = callB<EmitResolverBlock>())
>> >       return std::move(Err);
>> >
>> >     // Create the callback manager.
>> > @@ -679,18 +622,28 @@ public:
>> >     if (ExistingError)
>> >       return std::move(ExistingError);
>> >
>> > -    return callST<GetSymbolAddress>(Channel, Name);
>> > +    return callB<GetSymbolAddress>(Name);
>> >   }
>> >
>> >   /// Get the triple for the remote target.
>> >   const std::string &getTargetTriple() const { return
>> RemoteTargetTriple; }
>> >
>> > -  Error terminateSession() { return callST<TerminateSession>(Channel);
>> }
>> > +  Error terminateSession() { return callB<TerminateSession>(); }
>> >
>> > private:
>> > -  OrcRemoteTargetClient(ChannelT &Channel, Error &Err) :
>> Channel(Channel) {
>> > +
>> > +  OrcRemoteTargetClient(ChannelT &Channel, Error &Err)
>> > +      : OrcRemoteTargetRPCAPI(Channel) {
>> >     ErrorAsOutParameter EAO(&Err);
>> > -    if (auto RIOrErr = callST<GetRemoteInfo>(Channel)) {
>> > +
>> > +    addHandler<RequestCompile>(
>> > +        [this](JITTargetAddress Addr) -> JITTargetAddress {
>> > +          if (CallbackManager)
>> > +            return CallbackManager->executeCompileCallback(Addr);
>> > +          return 0;
>> > +        });
>> > +
>> > +    if (auto RIOrErr = callB<GetRemoteInfo>()) {
>> >       std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
>> >                RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
>> >       Err = Error::success();
>> > @@ -700,11 +653,11 @@ private:
>> >   }
>> >
>> >   Error deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
>> > -    return callST<RegisterEHFrames>(Channel, Addr, Size);
>> > +    return callB<RegisterEHFrames>(Addr, Size);
>> >   }
>> >
>> >   void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
>> > -    if (auto Err = callST<DestroyRemoteAllocator>(Channel, Id)) {
>> > +    if (auto Err = callB<DestroyRemoteAllocator>(Id)) {
>> >       // FIXME: This will be triggered by a removeModuleSet call:
>> Propagate
>> >       //        error return up through that.
>> >       llvm_unreachable("Failed to destroy remote allocator.");
>> > @@ -714,12 +667,12 @@ private:
>> >
>> >   Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
>> >     IndirectStubOwnerIds.release(Id);
>> > -    return callST<DestroyIndirectStubsOwner>(Channel, Id);
>> > +    return callB<DestroyIndirectStubsOwner>(Id);
>> >   }
>> >
>> >   Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
>> >   emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t
>> NumStubsRequired) {
>> > -    return callST<EmitIndirectStubs>(Channel, Id, NumStubsRequired);
>> > +    return callB<EmitIndirectStubs>(Id, NumStubsRequired);
>> >   }
>> >
>> >   Expected<std::tuple<JITTargetAddress, uint32_t>>
>> emitTrampolineBlock() {
>> > @@ -727,7 +680,7 @@ private:
>> >     if (ExistingError)
>> >       return std::move(ExistingError);
>> >
>> > -    return callST<EmitTrampolineBlock>(Channel);
>> > +    return callB<EmitTrampolineBlock>();
>> >   }
>> >
>> >   uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize;
>> }
>> > @@ -736,42 +689,17 @@ private:
>> >
>> >   uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
>> >
>> > -  Error listenForCompileRequests(RPCByteChannel &C, uint32_t &Id) {
>> > -    assert(CallbackManager &&
>> > -           "No calback manager. enableCompileCallbacks must be called
>> first");
>> > -
>> > -    // Check for an 'out-of-band' error, e.g. from an MM destructor.
>> > -    if (ExistingError)
>> > -      return std::move(ExistingError);
>> > -
>> > -    // FIXME: CompileCallback could be an anonymous lambda defined at
>> the use
>> > -    //        site below, but that triggers a GCC 4.7 ICE. When we
>> move off
>> > -    //        GCC 4.7, tidy this up.
>> > -    auto CompileCallback =
>> > -      [this](JITTargetAddress Addr) -> Expected<JITTargetAddress> {
>> > -        return this->CallbackManager->executeCompileCallback(Addr);
>> > -      };
>> > -
>> > -    if (Id == RequestCompileId) {
>> > -      if (auto Err = handle<RequestCompile>(C, CompileCallback))
>> > -        return Err;
>> > -      return Error::success();
>> > -    }
>> > -    // else
>> > -    return orcError(OrcErrorCode::UnexpectedRPCCall);
>> > -  }
>> > -
>> >   Expected<std::vector<char>> readMem(char *Dst, JITTargetAddress Src,
>> >                                       uint64_t Size) {
>> >     // Check for an 'out-of-band' error, e.g. from an MM destructor.
>> >     if (ExistingError)
>> >       return std::move(ExistingError);
>> >
>> > -    return callST<ReadMem>(Channel, Src, Size);
>> > +    return callB<ReadMem>(Src, Size);
>> >   }
>> >
>> >   Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) {
>> > -    return callST<RegisterEHFrames>(Channel, RAddr, Size);
>> > +    return callB<RegisterEHFrames>(RAddr, Size);
>> >   }
>> >
>> >   Expected<JITTargetAddress> reserveMem(ResourceIdMgr::ResourceId Id,
>> > @@ -781,12 +709,12 @@ private:
>> >     if (ExistingError)
>> >       return std::move(ExistingError);
>> >
>> > -    return callST<ReserveMem>(Channel, Id, Size, Align);
>> > +    return callB<ReserveMem>(Id, Size, Align);
>> >   }
>> >
>> >   Error setProtections(ResourceIdMgr::ResourceId Id,
>> >                        JITTargetAddress RemoteSegAddr, unsigned
>> ProtFlags) {
>> > -    return callST<SetProtections>(Channel, Id, RemoteSegAddr,
>> ProtFlags);
>> > +    return callB<SetProtections>(Id, RemoteSegAddr, ProtFlags);
>> >   }
>> >
>> >   Error writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size)
>> {
>> > @@ -794,7 +722,7 @@ private:
>> >     if (ExistingError)
>> >       return std::move(ExistingError);
>> >
>> > -    return callST<WriteMem>(Channel, DirectBufferWriter(Src, Addr,
>> Size));
>> > +    return callB<WriteMem>(DirectBufferWriter(Src, Addr, Size));
>> >   }
>> >
>> >   Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
>> > @@ -802,12 +730,11 @@ private:
>> >     if (ExistingError)
>> >       return std::move(ExistingError);
>> >
>> > -    return callST<WritePtr>(Channel, Addr, PtrVal);
>> > +    return callB<WritePtr>(Addr, PtrVal);
>> >   }
>> >
>> >   static Error doNothing() { return Error::success(); }
>> >
>> > -  ChannelT &Channel;
>> >   Error ExistingError = Error::success();
>> >   std::string RemoteTargetTriple;
>> >   uint32_t RemotePointerSize = 0;
>> >
>> > Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetR
>> PCAPI.h
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/
>> ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h?rev=286639&r1=
>> 286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
>> (original)
>> > +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
>> Fri Nov 11 15:42:09 2016
>> > @@ -16,7 +16,7 @@
>> > #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
>> > #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
>> >
>> > -#include "RPCByteChannel.h"
>> > +#include "RawByteChannel.h"
>> > #include "RPCUtils.h"
>> > #include "llvm/ExecutionEngine/JITSymbol.h"
>> >
>> > @@ -40,13 +40,24 @@ private:
>> >   uint64_t Size;
>> > };
>> >
>> > +} // end namespace remote
>> > +
>> > +namespace rpc {
>> > +
>> > template <>
>> > -class SerializationTraits<RPCByteChannel, DirectBufferWriter> {
>> > +class RPCTypeName<remote::DirectBufferWriter> {
>> > public:
>> > +  static const char *getName() { return "DirectBufferWriter"; }
>> > +};
>> >
>> > -  static const char* getName() { return "DirectBufferWriter"; }
>> > +template <typename ChannelT>
>> > +class SerializationTraits<ChannelT, remote::DirectBufferWriter,
>> remote::DirectBufferWriter,
>> > +                               typename std::enable_if<
>> > +                                 std::is_base_of<RawByteChannel,
>> ChannelT>::
>> > +                                 value>::type> {
>> > +public:
>> >
>> > -  static Error serialize(RPCByteChannel &C, const DirectBufferWriter
>> &DBW) {
>> > +  static Error serialize(ChannelT &C, const remote::DirectBufferWriter
>> &DBW) {
>> >     if (auto EC = serializeSeq(C, DBW.getDst()))
>> >       return EC;
>> >     if (auto EC = serializeSeq(C, DBW.getSize()))
>> > @@ -54,7 +65,7 @@ public:
>> >     return C.appendBytes(DBW.getSrc(), DBW.getSize());
>> >   }
>> >
>> > -  static Error deserialize(RPCByteChannel &C, DirectBufferWriter &DBW)
>> {
>> > +  static Error deserialize(ChannelT &C, remote::DirectBufferWriter
>> &DBW) {
>> >     JITTargetAddress Dst;
>> >     if (auto EC = deserializeSeq(C, Dst))
>> >       return EC;
>> > @@ -63,13 +74,18 @@ public:
>> >       return EC;
>> >     char *Addr = reinterpret_cast<char *>(static_cast<uintptr_t>(Dst));
>> >
>> > -    DBW = DirectBufferWriter(0, Dst, Size);
>> > +    DBW = remote::DirectBufferWriter(0, Dst, Size);
>> >
>> >     return C.readBytes(Addr, Size);
>> >   }
>> > };
>> >
>> > -class OrcRemoteTargetRPCAPI : public RPC<RPCByteChannel> {
>> > +} // end namespace rpc
>> > +
>> > +namespace remote {
>> > +
>> > +class OrcRemoteTargetRPCAPI
>> > +  : public rpc::SingleThreadedRPC<rpc::RawByteChannel> {
>> > protected:
>> >   class ResourceIdMgr {
>> >   public:
>> > @@ -93,119 +109,162 @@ protected:
>> >
>> > public:
>> >   // FIXME: Remove constructors once MSVC supports synthesizing
>> move-ops.
>> > -  OrcRemoteTargetRPCAPI() = default;
>> > -  OrcRemoteTargetRPCAPI(const OrcRemoteTargetRPCAPI &) = delete;
>> > -  OrcRemoteTargetRPCAPI &operator=(const OrcRemoteTargetRPCAPI &) =
>> delete;
>> > -
>> > -  OrcRemoteTargetRPCAPI(OrcRemoteTargetRPCAPI &&) {}
>> > -  OrcRemoteTargetRPCAPI &operator=(OrcRemoteTargetRPCAPI &&) { return
>> *this; }
>> > -
>> > -  enum JITFuncId : uint32_t {
>> > -    InvalidId = RPCFunctionIdTraits<JITFuncId>::InvalidId,
>> > -    CallIntVoidId = RPCFunctionIdTraits<JITFuncId>::FirstValidId,
>> > -    CallMainId,
>> > -    CallVoidVoidId,
>> > -    CreateRemoteAllocatorId,
>> > -    CreateIndirectStubsOwnerId,
>> > -    DeregisterEHFramesId,
>> > -    DestroyRemoteAllocatorId,
>> > -    DestroyIndirectStubsOwnerId,
>> > -    EmitIndirectStubsId,
>> > -    EmitResolverBlockId,
>> > -    EmitTrampolineBlockId,
>> > -    GetSymbolAddressId,
>> > -    GetRemoteInfoId,
>> > -    ReadMemId,
>> > -    RegisterEHFramesId,
>> > -    ReserveMemId,
>> > -    RequestCompileId,
>> > -    SetProtectionsId,
>> > -    TerminateSessionId,
>> > -    WriteMemId,
>> > -    WritePtrId
>> > -  };
>> > -
>> > -  static const char *getJITFuncIdName(JITFuncId Id);
>> > -
>> > -  typedef Function<CallIntVoidId, int32_t(JITTargetAddress Addr)>
>> CallIntVoid;
>> > -
>> > -  typedef Function<CallMainId,
>> > -                   int32_t(JITTargetAddress Addr,
>> > -                           std::vector<std::string> Args)>
>> > -      CallMain;
>> > -
>> > -  typedef Function<CallVoidVoidId, void(JITTargetAddress FnAddr)>
>> CallVoidVoid;
>> > -
>> > -  typedef Function<CreateRemoteAllocatorId,
>> > -                   void(ResourceIdMgr::ResourceId AllocatorID)>
>> > -      CreateRemoteAllocator;
>> > -
>> > -  typedef Function<CreateIndirectStubsOwnerId,
>> > -                   void(ResourceIdMgr::ResourceId StubOwnerID)>
>> > -      CreateIndirectStubsOwner;
>> > -
>> > -  typedef Function<DeregisterEHFramesId,
>> > -                   void(JITTargetAddress Addr, uint32_t Size)>
>> > -      DeregisterEHFrames;
>> > -
>> > -  typedef Function<DestroyRemoteAllocatorId,
>> > -                   void(ResourceIdMgr::ResourceId AllocatorID)>
>> > -      DestroyRemoteAllocator;
>> > -
>> > -  typedef Function<DestroyIndirectStubsOwnerId,
>> > -                   void(ResourceIdMgr::ResourceId StubsOwnerID)>
>> > -      DestroyIndirectStubsOwner;
>> > +  OrcRemoteTargetRPCAPI(rpc::RawByteChannel &C)
>> > +      : rpc::SingleThreadedRPC<rpc::RawByteChannel>(C, true) {}
>> > +
>> > +  class CallIntVoid : public rpc::Function<CallIntVoid,
>> > +                                           int32_t(JITTargetAddress
>> Addr)> {
>> > +  public:
>> > +    static const char* getName() { return "CallIntVoid"; }
>> > +  };
>> > +
>> > +  class CallMain
>> > +    : public rpc::Function<CallMain,
>> > +                           int32_t(JITTargetAddress Addr,
>> > +                                   std::vector<std::string> Args)> {
>> > +  public:
>> > +    static const char* getName() { return "CallMain"; }
>> > +  };
>> > +
>> > +  class CallVoidVoid : public rpc::Function<CallVoidVoid,
>> > +                                            void(JITTargetAddress
>> FnAddr)> {
>> > +  public:
>> > +    static const char* getName() { return "CallVoidVoid"; }
>> > +  };
>> > +
>> > +  class CreateRemoteAllocator
>> > +    : public rpc::Function<CreateRemoteAllocator,
>> > +                           void(ResourceIdMgr::ResourceId
>> AllocatorID)> {
>> > +  public:
>> > +    static const char* getName() { return "CreateRemoteAllocator"; }
>> > +  };
>> > +
>> > +  class CreateIndirectStubsOwner
>> > +    : public rpc::Function<CreateIndirectStubsOwner,
>> > +                           void(ResourceIdMgr::ResourceId
>> StubOwnerID)> {
>> > +  public:
>> > +    static const char* getName() { return "CreateIndirectStubsOwner"; }
>> > +  };
>> > +
>> > +  class DeregisterEHFrames
>> > +    : public rpc::Function<DeregisterEHFrames,
>> > +                           void(JITTargetAddress Addr, uint32_t Size)>
>> {
>> > +  public:
>> > +    static const char* getName() { return "DeregisterEHFrames"; }
>> > +  };
>> > +
>> > +  class DestroyRemoteAllocator
>> > +    : public rpc::Function<DestroyRemoteAllocator,
>> > +                           void(ResourceIdMgr::ResourceId
>> AllocatorID)> {
>> > +  public:
>> > +    static const char* getName() { return "DestroyRemoteAllocator"; }
>> > +  };
>> > +
>> > +  class DestroyIndirectStubsOwner
>> > +    : public rpc::Function<DestroyIndirectStubsOwner,
>> > +                           void(ResourceIdMgr::ResourceId
>> StubsOwnerID)> {
>> > +  public:
>> > +    static const char* getName() { return "DestroyIndirectStubsOwner";
>> }
>> > +  };
>> >
>> >   /// EmitIndirectStubs result is (StubsBase, PtrsBase,
>> NumStubsEmitted).
>> > -  typedef Function<EmitIndirectStubsId,
>> > -                   std::tuple<JITTargetAddress, JITTargetAddress,
>> uint32_t>(
>> > -                       ResourceIdMgr::ResourceId StubsOwnerID,
>> > -                       uint32_t NumStubsRequired)>
>> > -      EmitIndirectStubs;
>> > +  class EmitIndirectStubs
>> > +    : public rpc::Function<EmitIndirectStubs,
>> > +                           std::tuple<JITTargetAddress,
>> JITTargetAddress,
>> > +                                      uint32_t>(
>> > +                               ResourceIdMgr::ResourceId StubsOwnerID,
>> > +                               uint32_t NumStubsRequired)> {
>> > +  public:
>> > +    static const char* getName() { return "EmitIndirectStubs"; }
>> > +  };
>> >
>> > -  typedef Function<EmitResolverBlockId, void()> EmitResolverBlock;
>> > +  class EmitResolverBlock : public rpc::Function<EmitResolverBlock,
>> void()> {
>> > +  public:
>> > +    static const char* getName() { return "EmitResolverBlock"; }
>> > +  };
>> >
>> >   /// EmitTrampolineBlock result is (BlockAddr, NumTrampolines).
>> > -  typedef Function<EmitTrampolineBlockId,
>> > -                   std::tuple<JITTargetAddress, uint32_t>()>
>> > -      EmitTrampolineBlock;
>> > +  class EmitTrampolineBlock
>> > +    : public rpc::Function<EmitTrampolineBlock,
>> > +                           std::tuple<JITTargetAddress, uint32_t>()> {
>> > +  public:
>> > +    static const char* getName() { return "EmitTrampolineBlock"; }
>> > +  };
>> >
>> > -  typedef Function<GetSymbolAddressId, JITTargetAddress(std::string
>> SymbolName)>
>> > -      GetSymbolAddress;
>> > +  class GetSymbolAddress
>> > +    : public rpc::Function<GetSymbolAddress,
>> > +                           JITTargetAddress(std::string SymbolName)> {
>> > +  public:
>> > +    static const char* getName() { return "GetSymbolAddress"; }
>> > +  };
>> >
>> >   /// GetRemoteInfo result is (Triple, PointerSize, PageSize,
>> TrampolineSize,
>> >   ///                          IndirectStubsSize).
>> > -  typedef Function<GetRemoteInfoId, std::tuple<std::string, uint32_t,
>> uint32_t,
>> > -                                               uint32_t, uint32_t>()>
>> > -      GetRemoteInfo;
>> > +  class GetRemoteInfo
>> > +    : public rpc::Function<GetRemoteInfo,
>> > +                           std::tuple<std::string, uint32_t, uint32_t,
>> > +                                      uint32_t, uint32_t>()> {
>> > +  public:
>> > +    static const char* getName() { return "GetRemoteInfo"; }
>> > +  };
>> >
>> > -  typedef Function<ReadMemId,
>> > -                   std::vector<char>(JITTargetAddress Src, uint64_t
>> Size)>
>> > -      ReadMem;
>> > +  class ReadMem
>> > +    : public rpc::Function<ReadMem,
>> > +                           std::vector<uint8_t>(JITTargetAddress Src,
>> > +                                                uint64_t Size)> {
>> > +  public:
>> > +    static const char* getName() { return "ReadMem"; }
>> > +  };
>> >
>> > -  typedef Function<RegisterEHFramesId, void(JITTargetAddress Addr,
>> uint32_t Size)>
>> > -      RegisterEHFrames;
>> > +  class RegisterEHFrames
>> > +    : public rpc::Function<RegisterEHFrames,
>> > +                           void(JITTargetAddress Addr, uint32_t Size)>
>> {
>> > +  public:
>> > +    static const char* getName() { return "RegisterEHFrames"; }
>> > +  };
>> >
>> > -  typedef Function<ReserveMemId,
>> > -                   JITTargetAddress(ResourceIdMgr::ResourceId AllocID,
>> > -                                    uint64_t Size, uint32_t Align)>
>> > -      ReserveMem;
>> > +  class ReserveMem
>> > +    : public rpc::Function<ReserveMem,
>> > +                           JITTargetAddress(ResourceIdMgr::ResourceId
>> AllocID,
>> > +                                            uint64_t Size, uint32_t
>> Align)> {
>> > +  public:
>> > +    static const char* getName() { return "ReserveMem"; }
>> > +  };
>> >
>> > -  typedef Function<RequestCompileId,
>> > -                   JITTargetAddress(JITTargetAddress TrampolineAddr)>
>> > -      RequestCompile;
>> > +  class RequestCompile
>> > +    : public rpc::Function<RequestCompile,
>> > +                           JITTargetAddress(JITTargetAddress
>> TrampolineAddr)> {
>> > +  public:
>> > +    static const char* getName() { return "RequestCompile"; }
>> > +  };
>> > +
>> > +  class SetProtections
>> > +    : public rpc::Function<SetProtections,
>> > +                           void(ResourceIdMgr::ResourceId AllocID,
>> > +                                JITTargetAddress Dst,
>> > +                                uint32_t ProtFlags)> {
>> > +  public:
>> > +    static const char* getName() { return "SetProtections"; }
>> > +  };
>> >
>> > -  typedef Function<SetProtectionsId,
>> > -                   void(ResourceIdMgr::ResourceId AllocID,
>> JITTargetAddress Dst,
>> > -                        uint32_t ProtFlags)>
>> > -      SetProtections;
>> > +  class TerminateSession : public rpc::Function<TerminateSession,
>> void()> {
>> > +  public:
>> > +    static const char* getName() { return "TerminateSession"; }
>> > +  };
>> >
>> > -  typedef Function<TerminateSessionId, void()> TerminateSession;
>> > +  class WriteMem : public rpc::Function<WriteMem,
>> > +                                        void(remote::DirectBufferWriter
>> DB)> {
>> > +  public:
>> > +    static const char* getName() { return "WriteMem"; }
>> > +  };
>> >
>> > -  typedef Function<WriteMemId, void(DirectBufferWriter DB)> WriteMem;
>> > +  class WritePtr
>> > +    : public rpc::Function<WritePtr,
>> > +                           void(JITTargetAddress Dst, JITTargetAddress
>> Val)> {
>> > +  public:
>> > +    static const char* getName() { return "WritePtr"; }
>> > +  };
>> >
>> > -  typedef Function<WritePtrId, void(JITTargetAddress Dst,
>> JITTargetAddress Val)>
>> > -      WritePtr;
>> > };
>> >
>> > } // end namespace remote
>> >
>> > Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetS
>> erver.h
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/
>> ExecutionEngine/Orc/OrcRemoteTargetServer.h?rev=286639&r1=
>> 286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
>> (original)
>> > +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
>> Fri Nov 11 15:42:09 2016
>> > @@ -41,94 +41,51 @@ public:
>> >   OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor
>> SymbolLookup,
>> >                         EHFrameRegistrationFtor EHFramesRegister,
>> >                         EHFrameRegistrationFtor EHFramesDeregister)
>> > -      : Channel(Channel), SymbolLookup(std::move(SymbolLookup)),
>> > +      : OrcRemoteTargetRPCAPI(Channel), SymbolLookup(std::move(SymbolL
>> ookup)),
>> >         EHFramesRegister(std::move(EHFramesRegister)),
>> > -        EHFramesDeregister(std::move(EHFramesDeregister)) {}
>> > +        EHFramesDeregister(std::move(EHFramesDeregister)),
>> > +        TerminateFlag(false) {
>> > +
>> > +    using ThisT = typename std::remove_reference<decltype
>> (*this)>::type;
>> > +    addHandler<CallIntVoid>(*this, &ThisT::handleCallIntVoid);
>> > +    addHandler<CallMain>(*this, &ThisT::handleCallMain);
>> > +    addHandler<CallVoidVoid>(*this, &ThisT::handleCallVoidVoid);
>> > +    addHandler<CreateRemoteAllocator>(*this,
>> > +                                      &ThisT::handleCreateRemoteAllo
>> cator);
>> > +    addHandler<CreateIndirectStubsOwner>(*this,
>> > +                                         &ThisT::handleCreateIndirectS
>> tubsOwner);
>> > +    addHandler<DeregisterEHFrames>(*this,
>> &ThisT::handleDeregisterEHFrames);
>> > +    addHandler<DestroyRemoteAllocator>(*this,
>> > +                                       &ThisT::handleDestroyRemoteAl
>> locator);
>> > +    addHandler<DestroyIndirectStubsOwner>(*this,
>> > +
>> &ThisT::handleDestroyIndirectStubsOwner);
>> > +    addHandler<EmitIndirectStubs>(*this,
>> &ThisT::handleEmitIndirectStubs);
>> > +    addHandler<EmitResolverBlock>(*this,
>> &ThisT::handleEmitResolverBlock);
>> > +    addHandler<EmitTrampolineBlock>(*this,
>> &ThisT::handleEmitTrampolineBlock);
>> > +    addHandler<GetSymbolAddress>(*this, &ThisT::handleGetSymbolAddress
>> );
>> > +    addHandler<GetRemoteInfo>(*this, &ThisT::handleGetRemoteInfo);
>> > +    addHandler<ReadMem>(*this, &ThisT::handleReadMem);
>> > +    addHandler<RegisterEHFrames>(*this, &ThisT::handleRegisterEHFrames
>> );
>> > +    addHandler<ReserveMem>(*this, &ThisT::handleReserveMem);
>> > +    addHandler<SetProtections>(*this, &ThisT::handleSetProtections);
>> > +    addHandler<TerminateSession>(*this, &ThisT::handleTerminateSession
>> );
>> > +    addHandler<WriteMem>(*this, &ThisT::handleWriteMem);
>> > +    addHandler<WritePtr>(*this, &ThisT::handleWritePtr);
>> > +  }
>> >
>> >   // FIXME: Remove move/copy ops once MSVC supports synthesizing move
>> ops.
>> >   OrcRemoteTargetServer(const OrcRemoteTargetServer &) = delete;
>> >   OrcRemoteTargetServer &operator=(const OrcRemoteTargetServer &) =
>> delete;
>> >
>> > -  OrcRemoteTargetServer(OrcRemoteTargetServer &&Other)
>> > -      : Channel(Other.Channel), SymbolLookup(std::move(Other.S
>> ymbolLookup)),
>> > -        EHFramesRegister(std::move(Other.EHFramesRegister)),
>> > -        EHFramesDeregister(std::move(Other.EHFramesDeregister)) {}
>> > -
>> > +  OrcRemoteTargetServer(OrcRemoteTargetServer &&Other) = default;
>> >   OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete;
>> >
>> > -  Error handleKnownFunction(JITFuncId Id) {
>> > -    typedef OrcRemoteTargetServer ThisT;
>> > -
>> > -    DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) <<
>> "\n");
>> > -
>> > -    switch (Id) {
>> > -    case CallIntVoidId:
>> > -      return handle<CallIntVoid>(Channel, *this,
>> &ThisT::handleCallIntVoid);
>> > -    case CallMainId:
>> > -      return handle<CallMain>(Channel, *this, &ThisT::handleCallMain);
>> > -    case CallVoidVoidId:
>> > -      return handle<CallVoidVoid>(Channel, *this,
>> &ThisT::handleCallVoidVoid);
>> > -    case CreateRemoteAllocatorId:
>> > -      return handle<CreateRemoteAllocator>(Channel, *this,
>> > -
>>  &ThisT::handleCreateRemoteAllocator);
>> > -    case CreateIndirectStubsOwnerId:
>> > -      return handle<CreateIndirectStubsOwner>(
>> > -          Channel, *this, &ThisT::handleCreateIndirectStubsOwner);
>> > -    case DeregisterEHFramesId:
>> > -      return handle<DeregisterEHFrames>(Channel, *this,
>> > -                                        &ThisT::handleDeregisterEHFram
>> es);
>> > -    case DestroyRemoteAllocatorId:
>> > -      return handle<DestroyRemoteAllocator>(
>> > -          Channel, *this, &ThisT::handleDestroyRemoteAllocator);
>> > -    case DestroyIndirectStubsOwnerId:
>> > -      return handle<DestroyIndirectStubsOwner>(
>> > -          Channel, *this, &ThisT::handleDestroyIndirectStubsOwner);
>> > -    case EmitIndirectStubsId:
>> > -      return handle<EmitIndirectStubs>(Channel, *this,
>> > -                                       &ThisT::handleEmitIndirectStu
>> bs);
>> > -    case EmitResolverBlockId:
>> > -      return handle<EmitResolverBlock>(Channel, *this,
>> > -                                       &ThisT::handleEmitResolverBlo
>> ck);
>> > -    case EmitTrampolineBlockId:
>> > -      return handle<EmitTrampolineBlock>(Channel, *this,
>> > -                                         &ThisT::handleEmitTrampolineB
>> lock);
>> > -    case GetSymbolAddressId:
>> > -      return handle<GetSymbolAddress>(Channel, *this,
>> > -                                      &ThisT::handleGetSymbolAddress);
>> > -    case GetRemoteInfoId:
>> > -      return handle<GetRemoteInfo>(Channel, *this,
>> &ThisT::handleGetRemoteInfo);
>> > -    case ReadMemId:
>> > -      return handle<ReadMem>(Channel, *this, &ThisT::handleReadMem);
>> > -    case RegisterEHFramesId:
>> > -      return handle<RegisterEHFrames>(Channel, *this,
>> > -                                      &ThisT::handleRegisterEHFrames);
>> > -    case ReserveMemId:
>> > -      return handle<ReserveMem>(Channel, *this,
>> &ThisT::handleReserveMem);
>> > -    case SetProtectionsId:
>> > -      return handle<SetProtections>(Channel, *this,
>> > -                                    &ThisT::handleSetProtections);
>> > -    case WriteMemId:
>> > -      return handle<WriteMem>(Channel, *this, &ThisT::handleWriteMem);
>> > -    case WritePtrId:
>> > -      return handle<WritePtr>(Channel, *this, &ThisT::handleWritePtr);
>> > -    default:
>> > -      return orcError(OrcErrorCode::UnexpectedRPCCall);
>> > -    }
>> > -
>> > -    llvm_unreachable("Unhandled JIT RPC procedure Id.");
>> > -  }
>> >
>> >   Expected<JITTargetAddress> requestCompile(JITTargetAddress
>> TrampolineAddr) {
>> > -    auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
>> > -      return handleKnownFunction(static_cast<JITFuncId>(Id));
>> > -    };
>> > -
>> > -    return callSTHandling<RequestCompile>(Channel, Listen,
>> TrampolineAddr);
>> > +    return callB<RequestCompile>(TrampolineAddr);
>> >   }
>> >
>> > -  Error handleTerminateSession() {
>> > -    return handle<TerminateSession>(Channel, []() { return
>> Error::success(); });
>> > -  }
>> > +  bool receivedTerminate() const { return TerminateFlag; }
>> >
>> > private:
>> >   struct Allocator {
>> > @@ -365,15 +322,16 @@ private:
>> >                            IndirectStubSize);
>> >   }
>> >
>> > -  Expected<std::vector<char>> handleReadMem(JITTargetAddress RSrc,
>> uint64_t Size) {
>> > -    char *Src = reinterpret_cast<char *>(static_cast<uintptr_t>(RSrc
>> ));
>> > +  Expected<std::vector<uint8_t>> handleReadMem(JITTargetAddress RSrc,
>> > +                                               uint64_t Size) {
>> > +    uint8_t *Src = reinterpret_cast<uint8_t*>(sta
>> tic_cast<uintptr_t>(RSrc));
>> >
>> >     DEBUG(dbgs() << "  Reading " << Size << " bytes from "
>> >                  << format("0x%016x", RSrc) << "\n");
>> >
>> > -    std::vector<char> Buffer;
>> > +    std::vector<uint8_t> Buffer;
>> >     Buffer.resize(Size);
>> > -    for (char *P = Src; Size != 0; --Size)
>> > +    for (uint8_t *P = Src; Size != 0; --Size)
>> >       Buffer.push_back(*P++);
>> >
>> >     return Buffer;
>> > @@ -421,6 +379,11 @@ private:
>> >     return Allocator.setProtections(LocalAddr, Flags);
>> >   }
>> >
>> > +  Error handleTerminateSession() {
>> > +    TerminateFlag = true;
>> > +    return Error::success();
>> > +  }
>> > +
>> >   Error handleWriteMem(DirectBufferWriter DBW) {
>> >     DEBUG(dbgs() << "  Writing " << DBW.getSize() << " bytes to "
>> >                  << format("0x%016x", DBW.getDst()) << "\n");
>> > @@ -436,7 +399,6 @@ private:
>> >     return Error::success();
>> >   }
>> >
>> > -  ChannelT &Channel;
>> >   SymbolLookupFtor SymbolLookup;
>> >   EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister;
>> >   std::map<ResourceIdMgr::ResourceId, Allocator> Allocators;
>> > @@ -444,6 +406,7 @@ private:
>> >   std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList>
>> IndirectStubsOwners;
>> >   sys::OwningMemoryBlock ResolverBlock;
>> >   std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
>> > +  bool TerminateFlag;
>> > };
>> >
>> > } // end namespace remote
>> >
>> > Removed: llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCByteChannel.h
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/
>> ExecutionEngine/Orc/RPCByteChannel.h?rev=286638&view=auto
>> > ============================================================
>> ==================
>> > --- llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCByteChannel.h
>> (original)
>> > +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCByteChannel.h
>> (removed)
>> > @@ -1,231 +0,0 @@
>> > -//===- llvm/ExecutionEngine/Orc/RPCByteChannel.h ----------------*-
>> C++ -*-===//
>> > -//
>> > -//                     The LLVM Compiler Infrastructure
>> > -//
>> > -// This file is distributed under the University of Illinois Open
>> Source
>> > -// License. See LICENSE.TXT for details.
>> > -//
>> > -//===------------------------------------------------------
>> ----------------===//
>> > -
>> > -#ifndef LLVM_EXECUTIONENGINE_ORC_RPCBYTECHANNEL_H
>> > -#define LLVM_EXECUTIONENGINE_ORC_RPCBYTECHANNEL_H
>> > -
>> > -#include "OrcError.h"
>> > -#include "RPCSerialization.h"
>> > -#include "llvm/ADT/ArrayRef.h"
>> > -#include "llvm/ADT/STLExtras.h"
>> > -#include "llvm/ADT/StringRef.h"
>> > -#include "llvm/Support/Endian.h"
>> > -#include "llvm/Support/Error.h"
>> > -#include <cstddef>
>> > -#include <cstdint>
>> > -#include <mutex>
>> > -#include <string>
>> > -#include <tuple>
>> > -#include <type_traits>
>> > -#include <vector>
>> > -
>> > -namespace llvm {
>> > -namespace orc {
>> > -namespace remote {
>> > -
>> > -/// Interface for byte-streams to be used with RPC.
>> > -class RPCByteChannel {
>> > -public:
>> > -  virtual ~RPCByteChannel() {}
>> > -
>> > -  /// Read Size bytes from the stream into *Dst.
>> > -  virtual Error readBytes(char *Dst, unsigned Size) = 0;
>> > -
>> > -  /// Read size bytes from *Src and append them to the stream.
>> > -  virtual Error appendBytes(const char *Src, unsigned Size) = 0;
>> > -
>> > -  /// Flush the stream if possible.
>> > -  virtual Error send() = 0;
>> > -
>> > -  /// Get the lock for stream reading.
>> > -  std::mutex &getReadLock() { return readLock; }
>> > -
>> > -  /// Get the lock for stream writing.
>> > -  std::mutex &getWriteLock() { return writeLock; }
>> > -
>> > -private:
>> > -  std::mutex readLock, writeLock;
>> > -};
>> > -
>> > -/// Notify the channel that we're starting a message send.
>> > -/// Locks the channel for writing.
>> > -inline Error startSendMessage(RPCByteChannel &C) {
>> > -  C.getWriteLock().lock();
>> > -  return Error::success();
>> > -}
>> > -
>> > -/// Notify the channel that we're ending a message send.
>> > -/// Unlocks the channel for writing.
>> > -inline Error endSendMessage(RPCByteChannel &C) {
>> > -  C.getWriteLock().unlock();
>> > -  return Error::success();
>> > -}
>> > -
>> > -/// Notify the channel that we're starting a message receive.
>> > -/// Locks the channel for reading.
>> > -inline Error startReceiveMessage(RPCByteChannel &C) {
>> > -  C.getReadLock().lock();
>> > -  return Error::success();
>> > -}
>> > -
>> > -/// Notify the channel that we're ending a message receive.
>> > -/// Unlocks the channel for reading.
>> > -inline Error endReceiveMessage(RPCByteChannel &C) {
>> > -  C.getReadLock().unlock();
>> > -  return Error::success();
>> > -}
>> > -
>> > -template <typename ChannelT, typename T,
>> > -          typename =
>> > -            typename std::enable_if<
>> > -                       std::is_base_of<RPCByteChannel,
>> ChannelT>::value>::
>> > -                         type>
>> > -class RPCByteChannelPrimitiveSerialization {
>> > -public:
>> > -  static Error serialize(ChannelT &C, T V) {
>> > -    support::endian::byte_swap<T, support::big>(V);
>> > -    return C.appendBytes(reinterpret_cast<const char *>(&V),
>> sizeof(T));
>> > -  };
>> > -
>> > -  static Error deserialize(ChannelT &C, T &V) {
>> > -    if (auto Err = C.readBytes(reinterpret_cast<char *>(&V),
>> sizeof(T)))
>> > -      return Err;
>> > -    support::endian::byte_swap<T, support::big>(V);
>> > -    return Error::success();
>> > -  };
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, uint64_t>
>> > -  : public RPCByteChannelPrimitiveSerialization<ChannelT, uint64_t> {
>> > -public:
>> > -  static const char* getName() { return "uint64_t"; }
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, int64_t>
>> > -  : public RPCByteChannelPrimitiveSerialization<ChannelT, int64_t> {
>> > -public:
>> > -  static const char* getName() { return "int64_t"; }
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, uint32_t>
>> > -  : public RPCByteChannelPrimitiveSerialization<ChannelT, uint32_t> {
>> > -public:
>> > -  static const char* getName() { return "uint32_t"; }
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, int32_t>
>> > -  : public RPCByteChannelPrimitiveSerialization<ChannelT, int32_t> {
>> > -public:
>> > -  static const char* getName() { return "int32_t"; }
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, uint16_t>
>> > -  : public RPCByteChannelPrimitiveSerialization<ChannelT, uint16_t> {
>> > -public:
>> > -  static const char* getName() { return "uint16_t"; }
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, int16_t>
>> > -  : public RPCByteChannelPrimitiveSerialization<ChannelT, int16_t> {
>> > -public:
>> > -  static const char* getName() { return "int16_t"; }
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, uint8_t>
>> > -  : public RPCByteChannelPrimitiveSerialization<ChannelT, uint8_t> {
>> > -public:
>> > -  static const char* getName() { return "uint8_t"; }
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, int8_t>
>> > -  : public RPCByteChannelPrimitiveSerialization<ChannelT, int8_t> {
>> > -public:
>> > -  static const char* getName() { return "int8_t"; }
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, char>
>> > -  : public RPCByteChannelPrimitiveSerialization<ChannelT, uint8_t> {
>> > -public:
>> > -  static const char* getName() { return "char"; }
>> > -
>> > -  static Error serialize(RPCByteChannel &C, char V) {
>> > -    return serializeSeq(C, static_cast<uint8_t>(V));
>> > -  };
>> > -
>> > -  static Error deserialize(RPCByteChannel &C, char &V) {
>> > -    uint8_t VV;
>> > -    if (auto Err = deserializeSeq(C, VV))
>> > -      return Err;
>> > -    V = static_cast<char>(V);
>> > -    return Error::success();
>> > -  };
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, bool,
>> > -                          typename std::enable_if<
>> > -                            std::is_base_of<RPCByteChannel,
>> ChannelT>::value>::
>> > -                              type> {
>> > -public:
>> > -  static const char* getName() { return "bool"; }
>> > -
>> > -  static Error serialize(ChannelT &C, bool V) {
>> > -    return C.appendBytes(reinterpret_cast<const char *>(&V), 1);
>> > -  }
>> > -
>> > -  static Error deserialize(ChannelT &C, bool &V) {
>> > -    return C.readBytes(reinterpret_cast<char *>(&V), 1);
>> > -  }
>> > -};
>> > -
>> > -template <typename ChannelT>
>> > -class SerializationTraits<ChannelT, std::string,
>> > -                          typename std::enable_if<
>> > -                            std::is_base_of<RPCByteChannel,
>> ChannelT>::value>::
>> > -                              type> {
>> > -public:
>> > -  static const char* getName() { return "std::string"; }
>> > -
>> > -  static Error serialize(RPCByteChannel &C, StringRef S) {
>> > -    if (auto Err = SerializationTraits<RPCByteChannel, uint64_t>::
>> > -                     serialize(C, static_cast<uint64_t>(S.size())))
>> > -      return Err;
>> > -    return C.appendBytes((const char *)S.bytes_begin(), S.size());
>> > -  }
>> > -
>> > -  /// RPC channel serialization for std::strings.
>> > -  static Error serialize(RPCByteChannel &C, const std::string &S) {
>> > -    return serialize(C, StringRef(S));
>> > -  }
>> > -
>> > -  /// RPC channel deserialization for std::strings.
>> > -  static Error deserialize(RPCByteChannel &C, std::string &S) {
>> > -    uint64_t Count = 0;
>> > -    if (auto Err = SerializationTraits<RPCByteChannel, uint64_t>::
>> > -                     deserialize(C, Count))
>> > -      return Err;
>> > -    S.resize(Count);
>> > -    return C.readBytes(&S[0], Count);
>> > -  }
>> > -};
>> > -
>> > -} // end namespace remote
>> > -} // end namespace orc
>> > -} // end namespace llvm
>> > -
>> > -#endif // LLVM_EXECUTIONENGINE_ORC_RPCBYTECHANNEL_H
>> >
>> > Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization
>> .h
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/
>> ExecutionEngine/Orc/RPCSerialization.h?rev=286639&r1=286638&
>> r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization.h
>> (original)
>> > +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCSerialization.h Fri
>> Nov 11 15:42:09 2016
>> > @@ -17,7 +17,164 @@
>> >
>> > namespace llvm {
>> > namespace orc {
>> > -namespace remote {
>> > +namespace rpc {
>> > +
>> > +template <typename T>
>> > +class RPCTypeName;
>> > +
>> > +/// TypeNameSequence is a utility for rendering sequences of types to
>> a string
>> > +/// by rendering each type, separated by ", ".
>> > +template <typename... ArgTs> class RPCTypeNameSequence {};
>> > +
>> > +/// Render an empty TypeNameSequence to an ostream.
>> > +template <typename OStream>
>> > +OStream &operator<<(OStream &OS, const RPCTypeNameSequence<> &V) {
>> > +  return OS;
>> > +}
>> > +
>> > +/// Render a TypeNameSequence of a single type to an ostream.
>> > +template <typename OStream, typename ArgT>
>> > +OStream &operator<<(OStream &OS, const RPCTypeNameSequence<ArgT> &V) {
>> > +  OS << RPCTypeName<ArgT>::getName();
>> > +  return OS;
>> > +}
>> > +
>> > +/// Render a TypeNameSequence of more than one type to an ostream.
>> > +template <typename OStream, typename ArgT1, typename ArgT2,
>> typename... ArgTs>
>> > +OStream&
>> > +operator<<(OStream &OS, const RPCTypeNameSequence<ArgT1, ArgT2,
>> ArgTs...> &V) {
>> > +  OS << RPCTypeName<ArgT1>::getName() << ", "
>> > +     << RPCTypeNameSequence<ArgT2, ArgTs...>();
>> > +  return OS;
>> > +}
>> > +
>> > +template <>
>> > +class RPCTypeName<void> {
>> > +public:
>> > +  static const char* getName() { return "void"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<int8_t> {
>> > +public:
>> > +  static const char* getName() { return "int8_t"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<uint8_t> {
>> > +public:
>> > +  static const char* getName() { return "uint8_t"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<int16_t> {
>> > +public:
>> > +  static const char* getName() { return "int16_t"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<uint16_t> {
>> > +public:
>> > +  static const char* getName() { return "uint16_t"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<int32_t> {
>> > +public:
>> > +  static const char* getName() { return "int32_t"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<uint32_t> {
>> > +public:
>> > +  static const char* getName() { return "uint32_t"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<int64_t> {
>> > +public:
>> > +  static const char* getName() { return "int64_t"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<uint64_t> {
>> > +public:
>> > +  static const char* getName() { return "uint64_t"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<bool> {
>> > +public:
>> > +  static const char* getName() { return "bool"; }
>> > +};
>> > +
>> > +template <>
>> > +class RPCTypeName<std::string> {
>> > +public:
>> > +  static const char* getName() { return "std::string"; }
>> > +};
>> > +
>> > +template <typename T1, typename T2>
>> > +class RPCTypeName<std::pair<T1, T2>> {
>> > +public:
>> > +  static const char* getName() {
>> > +    std::lock_guard<std::mutex> Lock(NameMutex);
>> > +    if (Name.empty())
>> > +      raw_string_ostream(Name) << "std::pair<" <<
>> RPCTypeNameSequence<T1, T2>()
>> > +                               << ">";
>> > +    return Name.data();
>> > +  }
>> > +private:
>> > +  static std::mutex NameMutex;
>> > +  static std::string Name;
>> > +};
>> > +
>> > +template <typename T1, typename T2>
>> > +std::mutex RPCTypeName<std::pair<T1, T2>>::NameMutex;
>> > +template <typename T1, typename T2>
>> > +std::string RPCTypeName<std::pair<T1, T2>>::Name;
>> > +
>> > +template <typename... ArgTs>
>> > +class RPCTypeName<std::tuple<ArgTs...>> {
>> > +public:
>> > +  static const char* getName() {
>> > +    std::lock_guard<std::mutex> Lock(NameMutex);
>> > +    if (Name.empty())
>> > +      raw_string_ostream(Name) << "std::tuple<"
>> > +                               << RPCTypeNameSequence<ArgTs...>() <<
>> ">";
>> > +    return Name.data();
>> > +  }
>> > +private:
>> > +  static std::mutex NameMutex;
>> > +  static std::string Name;
>> > +};
>> > +
>> > +template <typename... ArgTs>
>> > +std::mutex RPCTypeName<std::tuple<ArgTs...>>::NameMutex;
>> > +template <typename... ArgTs>
>> > +std::string RPCTypeName<std::tuple<ArgTs...>>::Name;
>> > +
>> > +template <typename T>
>> > +class RPCTypeName<std::vector<T>> {
>> > +public:
>> > +  static const char*getName() {
>> > +    std::lock_guard<std::mutex> Lock(NameMutex);
>> > +    if (Name.empty())
>> > +      raw_string_ostream(Name) << "std::vector<" <<
>> RPCTypeName<T>::getName()
>> > +                               << ">";
>> > +    return Name.data();
>> > +  }
>> > +
>> > +private:
>> > +  static std::mutex NameMutex;
>> > +  static std::string Name;
>> > +};
>> > +
>> > +template <typename T>
>> > +std::mutex RPCTypeName<std::vector<T>>::NameMutex;
>> > +template <typename T>
>> > +std::string RPCTypeName<std::vector<T>>::Name;
>> > +
>> >
>> > /// The SerializationTraits<ChannelT, T> class describes how to
>> serialize and
>> > /// deserialize an instance of type T to/from an abstract channel of
>> type
>> > @@ -51,71 +208,92 @@ namespace remote {
>> > ///   }
>> > ///
>> > ///   @endcode
>> > -template <typename ChannelT, typename T, typename = void>
>> > +template <typename ChannelT, typename WireType, typename From =
>> WireType,
>> > +          typename = void>
>> > class SerializationTraits {};
>> >
>> > -/// TypeNameSequence is a utility for rendering sequences of types to
>> a string
>> > -/// by rendering each type, separated by ", ".
>> > -template <typename ChannelT, typename... ArgTs> class TypeNameSequence
>> {};
>> > +template <typename ChannelT>
>> > +class SequenceTraits {
>> > +public:
>> > +  static Error emitSeparator(ChannelT &C) { return Error::success(); }
>> > +  static Error consumeSeparator(ChannelT &C) { return
>> Error::success(); }
>> > +};
>> >
>> > -/// Render a TypeNameSequence of a single type to an ostream.
>> > -template <typename OStream, typename ChannelT, typename ArgT>
>> > -OStream &operator<<(OStream &OS, const TypeNameSequence<ChannelT,
>> ArgT> &V) {
>> > -  OS << SerializationTraits<ChannelT, ArgT>::getName();
>> > -  return OS;
>> > -}
>> > +/// Utility class for serializing sequences of values of varying types.
>> > +/// Specializations of this class contain 'serialize' and
>> 'deserialize' methods
>> > +/// for the given channel. The ArgTs... list will determine the
>> "over-the-wire"
>> > +/// types to be serialized. The serialize and deserialize methods take
>> a list
>> > +/// CArgTs... ("caller arg types") which must be the same length as
>> ArgTs...,
>> > +/// but may be different types from ArgTs, provided that for each
>> CArgT there
>> > +/// is a SerializationTraits specialization
>> > +/// SerializeTraits<ChannelT, ArgT, CArgT> with methods that can
>> serialize the
>> > +/// caller argument to over-the-wire value.
>> > +template <typename ChannelT, typename... ArgTs>
>> > +class SequenceSerialization;
>> >
>> > -/// Render a TypeNameSequence of more than one type to an ostream.
>> > -template <typename OStream, typename ChannelT, typename ArgT1,
>> typename ArgT2,
>> > -          typename... ArgTs>
>> > -OStream &
>> > -operator<<(OStream &OS,
>> > -           const TypeNameSequence<ChannelT, ArgT1, ArgT2, ArgTs...>
>> &V) {
>> > -  OS << SerializationTraits<ChannelT, ArgT1>::getName() << ", "
>> > -     << TypeNameSequence<ChannelT, ArgT2, ArgTs...>();
>> > -  return OS;
>> > -}
>> > +template <typename ChannelT>
>> > +class SequenceSerialization<ChannelT> {
>> > +public:
>> > +  static Error serialize(ChannelT &C) { return Error::success(); }
>> > +  static Error deserialize(ChannelT &C) { return Error::success(); }
>> > +};
>> >
>> > -/// RPC channel serialization for a variadic list of arguments.
>> > -template <typename ChannelT, typename T, typename... Ts>
>> > -Error serializeSeq(ChannelT &C, const T &Arg, const Ts &... Args) {
>> > -  if (auto Err = SerializationTraits<ChannelT, T>::serialize(C, Arg))
>> > -    return Err;
>> > -  return serializeSeq(C, Args...);
>> > -}
>> > +template <typename ChannelT, typename ArgT>
>> > +class SequenceSerialization<ChannelT, ArgT> {
>> > +public:
>> >
>> > -/// RPC channel serialization for an (empty) variadic list of
>> arguments.
>> > -template <typename ChannelT> Error serializeSeq(ChannelT &C) {
>> > -  return Error::success();
>> > -}
>> > +  template <typename CArgT>
>> > +  static Error serialize(ChannelT &C, const CArgT &CArg) {
>> > +    return SerializationTraits<ChannelT, ArgT, CArgT>::serialize(C,
>> CArg);
>> > +  }
>> > +
>> > +  template <typename CArgT>
>> > +  static Error deserialize(ChannelT &C, CArgT &CArg) {
>> > +    return SerializationTraits<ChannelT, ArgT, CArgT>::deserialize(C,
>> CArg);
>> > +  }
>> > +};
>> > +
>> > +template <typename ChannelT, typename ArgT, typename... ArgTs>
>> > +class SequenceSerialization<ChannelT, ArgT, ArgTs...> {
>> > +public:
>> >
>> > -/// RPC channel deserialization for a variadic list of arguments.
>> > -template <typename ChannelT, typename T, typename... Ts>
>> > -Error deserializeSeq(ChannelT &C, T &Arg, Ts &... Args) {
>> > -  if (auto Err = SerializationTraits<ChannelT, T>::deserialize(C, Arg))
>> > -    return Err;
>> > -  return deserializeSeq(C, Args...);
>> > +  template <typename CArgT, typename... CArgTs>
>> > +  static Error serialize(ChannelT &C, const CArgT &CArg,
>> > +                         const CArgTs&... CArgs) {
>> > +    if (auto Err =
>> > +        SerializationTraits<ChannelT, ArgT, CArgT>::serialize(C, CArg))
>> > +      return Err;
>> > +    if (auto Err = SequenceTraits<ChannelT>::emitSeparator(C))
>> > +      return Err;
>> > +    return SequenceSerialization<ChannelT, ArgTs...>::serialize(C,
>> CArgs...);
>> > +  }
>> > +
>> > +  template <typename CArgT, typename... CArgTs>
>> > +  static Error deserialize(ChannelT &C, CArgT &CArg,
>> > +                           CArgTs&... CArgs) {
>> > +    if (auto Err =
>> > +        SerializationTraits<ChannelT, ArgT, CArgT>::deserialize(C,
>> CArg))
>> > +      return Err;
>> > +    if (auto Err = SequenceTraits<ChannelT>::consumeSeparator(C))
>> > +      return Err;
>> > +    return SequenceSerialization<ChannelT, ArgTs...>::deserialize(C,
>> CArgs...);
>> > +  }
>> > +};
>> > +
>> > +template <typename ChannelT, typename... ArgTs>
>> > +Error serializeSeq(ChannelT &C, const ArgTs &... Args) {
>> > +  return SequenceSerialization<ChannelT, ArgTs...>::serialize(C,
>> Args...);
>> > }
>> >
>> > -/// RPC channel serialization for an (empty) variadic list of
>> arguments.
>> > -template <typename ChannelT> Error deserializeSeq(ChannelT &C) {
>> > -  return Error::success();
>> > +template <typename ChannelT, typename... ArgTs>
>> > +Error deserializeSeq(ChannelT &C, ArgTs &... Args) {
>> > +  return SequenceSerialization<ChannelT, ArgTs...>::deserialize(C,
>> Args...);
>> > }
>> >
>> > /// SerializationTraits default specialization for std::pair.
>> > template <typename ChannelT, typename T1, typename T2>
>> > class SerializationTraits<ChannelT, std::pair<T1, T2>> {
>> > public:
>> > -  static const char *getName() {
>> > -    std::lock_guard<std::mutex> Lock(NameMutex);
>> > -    if (Name.empty())
>> > -      Name = (std::ostringstream()
>> > -              << "std::pair<" << TypeNameSequence<ChannelT, T1, T2>()
>> << ">")
>> > -                 .str();
>> > -
>> > -    return Name.data();
>> > -  }
>> > -
>> >   static Error serialize(ChannelT &C, const std::pair<T1, T2> &V) {
>> >     return serializeSeq(C, V.first, V.second);
>> >   }
>> > @@ -123,31 +301,12 @@ public:
>> >   static Error deserialize(ChannelT &C, std::pair<T1, T2> &V) {
>> >     return deserializeSeq(C, V.first, V.second);
>> >   }
>> > -
>> > -private:
>> > -  static std::mutex NameMutex;
>> > -  static std::string Name;
>> > };
>> >
>> > -template <typename ChannelT, typename T1, typename T2>
>> > -std::mutex SerializationTraits<ChannelT, std::pair<T1, T2>>::NameMutex;
>> > -
>> > -template <typename ChannelT, typename T1, typename T2>
>> > -std::string SerializationTraits<ChannelT, std::pair<T1, T2>>::Name;
>> > -
>> > /// SerializationTraits default specialization for std::tuple.
>> > template <typename ChannelT, typename... ArgTs>
>> > class SerializationTraits<ChannelT, std::tuple<ArgTs...>> {
>> > public:
>> > -  static const char *getName() {
>> > -    std::lock_guard<std::mutex> Lock(NameMutex);
>> > -    if (Name.empty())
>> > -      Name = (std::ostringstream()
>> > -              << "std::tuple<" << TypeNameSequence<ChannelT,
>> ArgTs...>() << ">")
>> > -                 .str();
>> > -
>> > -    return Name.data();
>> > -  }
>> >
>> >   /// RPC channel serialization for std::tuple.
>> >   static Error serialize(ChannelT &C, const std::tuple<ArgTs...> &V) {
>> > @@ -173,68 +332,41 @@ private:
>> >                                       llvm::index_sequence<Is...> _) {
>> >     return deserializeSeq(C, std::get<Is>(V)...);
>> >   }
>> > -
>> > -  static std::mutex NameMutex;
>> > -  static std::string Name;
>> > };
>> >
>> > -template <typename ChannelT, typename... ArgTs>
>> > -std::mutex SerializationTraits<ChannelT, std::tuple<ArgTs...>>::NameMut
>> ex;
>> > -
>> > -template <typename ChannelT, typename... ArgTs>
>> > -std::string SerializationTraits<ChannelT, std::tuple<ArgTs...>>::Name;
>> > -
>> > /// SerializationTraits default specialization for std::vector.
>> > template <typename ChannelT, typename T>
>> > class SerializationTraits<ChannelT, std::vector<T>> {
>> > public:
>> > -  static const char *getName() {
>> > -    std::lock_guard<std::mutex> Lock(NameMutex);
>> > -    if (Name.empty())
>> > -      Name = (std::ostringstream() << "std::vector<"
>> > -                                   << TypeNameSequence<ChannelT, T>()
>> << ">")
>> > -                 .str();
>> > -    return Name.data();
>> > -  }
>> >
>> > +  /// Serialize a std::vector<T> from std::vector<T>.
>> >   static Error serialize(ChannelT &C, const std::vector<T> &V) {
>> > -    if (auto Err = SerializationTraits<ChannelT, uint64_t>::serialize(
>> > -            C, static_cast<uint64_t>(V.size())))
>> > +    if (auto Err = serializeSeq(C, static_cast<uint64_t>(V.size())))
>> >       return Err;
>> >
>> >     for (const auto &E : V)
>> > -      if (auto Err = SerializationTraits<ChannelT, T>::serialize(C, E))
>> > +      if (auto Err = serializeSeq(C, E))
>> >         return Err;
>> >
>> >     return Error::success();
>> >   }
>> >
>> > +  /// Deserialize a std::vector<T> to a std::vector<T>.
>> >   static Error deserialize(ChannelT &C, std::vector<T> &V) {
>> >     uint64_t Count = 0;
>> > -    if (auto Err =
>> > -            SerializationTraits<ChannelT, uint64_t>::deserialize(C,
>> Count))
>> > +    if (auto Err = deserializeSeq(C, Count))
>> >       return Err;
>> >
>> >     V.resize(Count);
>> >     for (auto &E : V)
>> > -      if (auto Err = SerializationTraits<ChannelT, T>::deserialize(C,
>> E))
>> > +      if (auto Err = deserializeSeq(C, E))
>> >         return Err;
>> >
>> >     return Error::success();
>> >   }
>> > -
>> > -private:
>> > -  static std::mutex NameMutex;
>> > -  static std::string Name;
>> > };
>> >
>> > -template <typename ChannelT, typename T>
>> > -std::mutex SerializationTraits<ChannelT, std::vector<T>>::NameMutex;
>> > -
>> > -template <typename ChannelT, typename T>
>> > -std::string SerializationTraits<ChannelT, std::vector<T>>::Name;
>> > -
>> > -} // end namespace remote
>> > +} // end namespace rpc
>> > } // end namespace orc
>> > } // end namespace llvm
>> >
>> >
>> > Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/
>> ExecutionEngine/Orc/RPCUtils.h?rev=286639&r1=286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h (original)
>> > +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h Fri Nov 11
>> 15:42:09 2016
>> > @@ -1,4 +1,4 @@
>> > -//===----- RPCUTils.h - Basic tilities for building RPC APIs ----*-
>> C++ -*-===//
>> > +//===------- RPCUTils.h - Utilities for building RPC APIs -------*-
>> C++ -*-===//
>> > //
>> > //                     The LLVM Compiler Infrastructure
>> > //
>> > @@ -7,7 +7,11 @@
>> > //
>> > //===-------------------------------------------------------
>> ---------------===//
>> > //
>> > -// Basic utilities for building RPC APIs.
>> > +// Utilities to support construction of simple RPC APIs.
>> > +//
>> > +// The RPC utilities aim for ease of use (minimal conceptual overhead)
>> for C++
>> > +// programmers, high performance, low memory overhead, and efficient
>> use of the
>> > +// communications channel.
>> > //
>> > //===-------------------------------------------------------
>> ---------------===//
>> >
>> > @@ -15,10 +19,12 @@
>> > #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
>> >
>> > #include <map>
>> > +#include <thread>
>> > #include <vector>
>> >
>> > #include "llvm/ADT/STLExtras.h"
>> > #include "llvm/ExecutionEngine/Orc/OrcError.h"
>> > +#include "llvm/ExecutionEngine/Orc/RPCSerialization.h"
>> >
>> > #ifdef _MSC_VER
>> > // concrt.h depends on eh.h for __uncaught_exception declaration
>> > @@ -39,32 +45,92 @@
>> >
>> > namespace llvm {
>> > namespace orc {
>> > -namespace remote {
>> > +namespace rpc {
>> >
>> > -/// Describes reserved RPC Function Ids.
>> > -///
>> > -/// The default implementation will serve for integer and enum
>> function id
>> > -/// types. If you want to use a custom type as your FunctionId you can
>> > -/// specialize this class and provide unique values for InvalidId,
>> > -/// ResponseId and FirstValidId.
>> > +template <typename DerivedFunc, typename FnT>
>> > +class Function;
>> >
>> > -template <typename T> class RPCFunctionIdTraits {
>> > +// RPC Function class.
>> > +// DerivedFunc should be a user defined class with a static
>> 'getName()' method
>> > +// returning a const char* representing the function's name.
>> > +template <typename DerivedFunc, typename RetT, typename... ArgTs>
>> > +class Function<DerivedFunc, RetT(ArgTs...)> {
>> > public:
>> > -  static const T InvalidId = static_cast<T>(0);
>> > -  static const T ResponseId = static_cast<T>(1);
>> > -  static const T FirstValidId = static_cast<T>(2);
>> > +
>> > +  /// User defined function type.
>> > +  using Type = RetT(ArgTs...);
>> > +
>> > +  /// Return type.
>> > +  using ReturnType = RetT;
>> > +
>> > +  /// Returns the full function prototype as a string.
>> > +  static const char *getPrototype() {
>> > +    std::lock_guard<std::mutex> Lock(NameMutex);
>> > +    if (Name.empty())
>> > +      raw_string_ostream(Name)
>> > +          << RPCTypeName<RetT>::getName() << " " <<
>> DerivedFunc::getName()
>> > +          << "(" << llvm::orc::rpc::RPCTypeNameSequence<ArgTs...>()
>> << ")";
>> > +    return Name.data();
>> > +  }
>> > +private:
>> > +  static std::mutex NameMutex;
>> > +  static std::string Name;
>> > };
>> >
>> > -// Base class containing utilities that require partial specialization.
>> > -// These cannot be included in RPC, as template class members cannot be
>> > -// partially specialized.
>> > -class RPCBase {
>> > -protected:
>> >
>> > -  // FIXME: Remove MSVCPError/MSVCPExpected once MSVC's future
>> implementation
>> > -  //        supports classes without default constructors.
>> > +template <typename DerivedFunc, typename RetT, typename... ArgTs>
>> > +std::mutex Function<DerivedFunc, RetT(ArgTs...)>::NameMutex;
>> > +
>> > +template <typename DerivedFunc, typename RetT, typename... ArgTs>
>> > +std::string Function<DerivedFunc, RetT(ArgTs...)>::Name;
>> > +
>> > +/// Allocates RPC function ids during autonegotiation.
>> > +/// Specializations of this class must provide four members:
>> > +///
>> > +/// static T getInvalidId():
>> > +///   Should return a reserved id that will be used to represent
>> missing
>> > +/// functions during autonegotiation.
>> > +///
>> > +/// static T getResponseId():
>> > +///   Should return a reserved id that will be used to send function
>> responses
>> > +/// (return values).
>> > +///
>> > +/// static T getNegotiateId():
>> > +///   Should return a reserved id for the negotiate function, which
>> will be used
>> > +/// to negotiate ids for user defined functions.
>> > +///
>> > +/// template <typename Func> T allocate():
>> > +///   Allocate a unique id for function Func.
>> > +template <typename T, typename = void>
>> > +class RPCFunctionIdAllocator;
>> > +
>> > +/// This specialization of RPCFunctionIdAllocator provides a default
>> > +/// implementation for integral types.
>> > +template <typename T>
>> > +class RPCFunctionIdAllocator<T,
>> > +                             typename std::enable_if<
>> > +                               std::is_integral<T>::value
>> > +                             >::type> {
>> > +public:
>> > +
>> > +  static T getInvalidId() { return T(0); }
>> > +  static T getResponseId() { return T(1); }
>> > +  static T getNegotiateId() { return T(2); }
>> > +
>> > +  template <typename Func>
>> > +  T allocate(){ return NextId++; }
>> > +private:
>> > +  T NextId = 3;
>> > +};
>> > +
>> > +namespace detail {
>> > +
>> > +// FIXME: Remove MSVCPError/MSVCPExpected once MSVC's future
>> implementation
>> > +//        supports classes without default constructors.
>> > #ifdef _MSC_VER
>> >
>> > +namespace msvc_hacks {
>> > +
>> >   // Work around MSVC's future implementation's use of default
>> constructors:
>> >   // A default constructed value in the promise will be overwritten
>> when the
>> >   // real error is set - so the default constructed Error has to be
>> checked
>> > @@ -86,7 +152,7 @@ protected:
>> >     MSVCPError(Error Err) : Error(std::move(Err)) {}
>> >   };
>> >
>> > -  // Likewise for Expected:
>> > +  // Work around MSVC's future implementation, similar to MSVCPError.
>> >   template <typename T>
>> >   class MSVCPExpected : public Expected<T> {
>> >   public:
>> > @@ -123,488 +189,531 @@ protected:
>> >         nullptr) : Expected<T>(std::move(Other)) {}
>> >   };
>> >
>> > +} // end namespace msvc_hacks
>> > +
>> > #endif // _MSC_VER
>> >
>> > -  // RPC Function description type.
>> > -  //
>> > -  // This class provides the information and operations needed to
>> support the
>> > -  // RPC primitive operations (call, expect, etc) for a given
>> function. It
>> > -  // is specialized for void and non-void functions to deal with the
>> differences
>> > -  // betwen the two. Both specializations have the same interface:
>> > -  //
>> > -  // Id - The function's unique identifier.
>> > -  // ErrorReturn - The return type for blocking calls.
>> > -  // readResult - Deserialize a result from a channel.
>> > -  // abandon - Abandon a promised result.
>> > -  // respond - Retun a result on the channel.
>> > -  template <typename FunctionIdT, FunctionIdT FuncId, typename FnT>
>> > -  class FunctionHelper {};
>> > -
>> > -  // RPC Function description specialization for non-void functions.
>> > -  template <typename FunctionIdT, FunctionIdT FuncId, typename RetT,
>> > -            typename... ArgTs>
>> > -  class FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> {
>> > -  public:
>> > -    static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId
>> &&
>> > -                      FuncId != RPCFunctionIdTraits<FunctionId
>> T>::ResponseId,
>> > -                  "Cannot define custom function with InvalidId or
>> ResponseId. "
>> > -                  "Please use RPCFunctionTraits<FunctionIdT>
>> ::FirstValidId.");
>> > -
>> > -    static const FunctionIdT Id = FuncId;
>> > -
>> > -    typedef Expected<RetT> ErrorReturn;
>> > -
>> > -    // FIXME: Ditch PErrorReturn (replace it with plain ErrorReturn)
>> once MSVC's
>> > -    //        std::future implementation supports types without default
>> > -    //        constructors.
>> > -#ifdef _MSC_VER
>> > -    typedef MSVCPExpected<RetT> PErrorReturn;
>> > -#else
>> > -    typedef Expected<RetT> PErrorReturn;
>> > -#endif
>> > +// ResultTraits provides typedefs and utilities specific to the return
>> type
>> > +// of functions.
>> > +template <typename RetT>
>> > +class ResultTraits {
>> > +public:
>> >
>> > -    template <typename ChannelT>
>> > -    static Error readResult(ChannelT &C, std::promise<PErrorReturn>
>> &P) {
>> > -      RetT Val;
>> > -      auto Err = deserializeSeq(C, Val);
>> > -      auto Err2 = endReceiveMessage(C);
>> > -      Err = joinErrors(std::move(Err), std::move(Err2));
>> > -      if (Err)
>> > -        return Err;
>> > +  // The return type wrapped in llvm::Expected.
>> > +  using ErrorReturnType = Expected<RetT>;
>> >
>> > -      P.set_value(std::move(Val));
>> > -      return Error::success();
>> > -    }
>> > +#ifdef _MSC_VER
>> > +  // The ErrorReturnType wrapped in a std::promise.
>> > +  using ReturnPromiseType = std::promise<msvc_hacks::MSVCP
>> Expected<RetT>>;
>> >
>> > -    static void abandon(std::promise<PErrorReturn> &P) {
>> > -      P.set_value(
>> > -        make_error<StringError>("RPC function call failed to return",
>> > -                                inconvertibleErrorCode()));
>> > -    }
>> > +  // The ErrorReturnType wrapped in a std::future.
>> > +  using ReturnFutureType = std::future<msvc_hacks::MSVCPE
>> xpected<RetT>>;
>> > +#else
>> > +  // The ErrorReturnType wrapped in a std::promise.
>> > +  using ReturnPromiseType = std::promise<ErrorReturnType>;
>> >
>> > -    static void consumeAbandoned(std::future<PErrorReturn> &P) {
>> > -      consumeError(P.get().takeError());
>> > -    }
>> > +  // The ErrorReturnType wrapped in a std::future.
>> > +  using ReturnFutureType = std::future<ErrorReturnType>;
>> > +#endif
>> >
>> > -    template <typename ChannelT, typename SequenceNumberT>
>> > -    static Error respond(ChannelT &C, SequenceNumberT SeqNo,
>> > -                         ErrorReturn &Result) {
>> > -      FunctionIdT ResponseId = RPCFunctionIdTraits<FunctionId
>> T>::ResponseId;
>> > +  // Create a 'blank' value of the ErrorReturnType, ready and safe to
>> > +  // overwrite.
>> > +  static ErrorReturnType createBlankErrorReturnValue() {
>> > +    return ErrorReturnType(RetT());
>> > +  }
>> >
>> > -      // If the handler returned an error then bail out with that.
>> > -      if (!Result)
>> > -        return Result.takeError();
>> > +  // Consume an abandoned ErrorReturnType.
>> > +  static void consumeAbandoned(ErrorReturnType RetOrErr) {
>> > +    consumeError(RetOrErr.takeError());
>> > +  }
>> > +};
>> >
>> > -      // Otherwise open a new message on the channel and send the
>> result.
>> > -      if (auto Err = startSendMessage(C))
>> > -        return Err;
>> > -      if (auto Err = serializeSeq(C, ResponseId, SeqNo, *Result))
>> > -        return Err;
>> > -      return endSendMessage(C);
>> > -    }
>> > -  };
>> > +// ResultTraits specialization for void functions.
>> > +template <>
>> > +class ResultTraits<void> {
>> > +public:
>> > +
>> > +  // For void functions, ErrorReturnType is llvm::Error.
>> > +  using ErrorReturnType = Error;
>> >
>> > -  // RPC Function description specialization for void functions.
>> > -  template <typename FunctionIdT, FunctionIdT FuncId, typename...
>> ArgTs>
>> > -  class FunctionHelper<FunctionIdT, FuncId, void(ArgTs...)> {
>> > -  public:
>> > -    static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId
>> &&
>> > -                      FuncId != RPCFunctionIdTraits<FunctionId
>> T>::ResponseId,
>> > -                  "Cannot define custom function with InvalidId or
>> ResponseId. "
>> > -                  "Please use RPCFunctionTraits<FunctionIdT>
>> ::FirstValidId.");
>> > -
>> > -    static const FunctionIdT Id = FuncId;
>> > -
>> > -    typedef Error ErrorReturn;
>> > -
>> > -    // FIXME: Ditch PErrorReturn (replace it with plain ErrorReturn)
>> once MSVC's
>> > -    //        std::future implementation supports types without default
>> > -    //        constructors.
>> > #ifdef _MSC_VER
>> > -    typedef MSVCPError PErrorReturn;
>> > +  // The ErrorReturnType wrapped in a std::promise.
>> > +  using ReturnPromiseType = std::promise<msvc_hacks::MSVCPError>;
>> > +
>> > +  // The ErrorReturnType wrapped in a std::future.
>> > +  using ReturnFutureType = std::future<msvc_hacks::MSVCPError>;
>> > #else
>> > -    typedef Error PErrorReturn;
>> > +  // The ErrorReturnType wrapped in a std::promise.
>> > +  using ReturnPromiseType = std::promise<ErrorReturnType>;
>> > +
>> > +  // The ErrorReturnType wrapped in a std::future.
>> > +  using ReturnFutureType = std::future<ErrorReturnType>;
>> > #endif
>> >
>> > -    template <typename ChannelT>
>> > -    static Error readResult(ChannelT &C, std::promise<PErrorReturn>
>> &P) {
>> > -      // Void functions don't have anything to deserialize, so we're
>> good.
>> > -      P.set_value(Error::success());
>> > -      return endReceiveMessage(C);
>> > -    }
>> > +  // Create a 'blank' value of the ErrorReturnType, ready and safe to
>> > +  // overwrite.
>> > +  static ErrorReturnType createBlankErrorReturnValue() {
>> > +    return ErrorReturnType::success();
>> > +  }
>> >
>> > -    static void abandon(std::promise<PErrorReturn> &P) {
>> > -      P.set_value(
>> > -        make_error<StringError>("RPC function call failed to return",
>> > -                                inconvertibleErrorCode()));
>> > -    }
>> > +  // Consume an abandoned ErrorReturnType.
>> > +  static void consumeAbandoned(ErrorReturnType Err) {
>> > +    consumeError(std::move(Err));
>> > +  }
>> > +};
>> >
>> > -    static void consumeAbandoned(std::future<PErrorReturn> &P) {
>> > -      consumeError(P.get());
>> > -    }
>> > +// ResultTraits<Error> is equivalent to ResultTraits<void>. This allows
>> > +// handlers for void RPC functions to return either void (in which
>> case they
>> > +// implicitly succeed) or Error (in which case their error return is
>> > +// propagated). See usage in HandlerTraits::runHandlerHelper.
>> > +template <>
>> > +class ResultTraits<Error> : public ResultTraits<void> {};
>> > +
>> > +// ResultTraits<Expected<T>> is equivalent to ResultTraits<T>. This
>> allows
>> > +// handlers for RPC functions returning a T to return either a T (in
>> which
>> > +// case they implicitly succeed) or Expected<T> (in which case their
>> error
>> > +// return is propagated). See usage in HandlerTraits::runHandlerHelpe
>> r.
>> > +template <typename RetT>
>> > +class ResultTraits<Expected<RetT>> : public ResultTraits<RetT> {};
>> > +
>> > +// Send a response of the given wire return type (WireRetT) over the
>> > +// channel, with the given sequence number.
>> > +template <typename WireRetT, typename HandlerRetT, typename ChannelT,
>> > +          typename FunctionIdT, typename SequenceNumberT>
>> > +static Error respond(ChannelT &C, const FunctionIdT &ResponseId,
>> > +                     SequenceNumberT SeqNo, Expected<HandlerRetT>
>> ResultOrErr) {
>> > +  // If this was an error bail out.
>> > +  // FIXME: Send an "error" message to the client if this is not a
>> channel
>> > +  //        failure?
>> > +  if (auto Err = ResultOrErr.takeError())
>> > +    return Err;
>> > +
>> > +  // Open the response message.
>> > +  if (auto Err = C.startSendMessage(ResponseId, SeqNo))
>> > +    return Err;
>> > +
>> > +  // Serialize the result.
>> > +  if (auto Err = SerializationTraits<ChannelT, WireRetT, HandlerRetT>::
>> > +      serialize(C, *ResultOrErr))
>> > +    return Err;
>> > +
>> > +  // Close the response message.
>> > +  return C.endSendMessage();
>> > +}
>> > +
>> > +// Send an empty response message on the given channel to indicate that
>> > +// the handler ran.
>> > +template <typename WireRetT, typename ChannelT, typename FunctionIdT,
>> > +          typename SequenceNumberT>
>> > +static Error respond(ChannelT &C, const FunctionIdT &ResponseId,
>> > +                     SequenceNumberT SeqNo, Error Err) {
>> > +  if (Err)
>> > +    return Err;
>> > +  if (auto Err2 = C.startSendMessage(ResponseId, SeqNo))
>> > +    return Err2;
>> > +  return C.endSendMessage();
>> > +}
>> > +
>> > +// This template class provides utilities related to RPC function
>> handlers.
>> > +// The base case applies to non-function types (the template class is
>> > +// specialized for function types) and inherits from the appropriate
>> > +// speciilization for the given non-function type's call operator.
>> > +template <typename HandlerT>
>> > +class HandlerTraits
>> > +  : public HandlerTraits<decltype(
>> > +             &std::remove_reference<HandlerT>::type::operator())> {};
>> > +
>> > +// Traits for handlers with a given function type.
>> > +template <typename RetT, typename... ArgTs>
>> > +class HandlerTraits<RetT(ArgTs...)> {
>> > +public:
>> >
>> > -    template <typename ChannelT, typename SequenceNumberT>
>> > -    static Error respond(ChannelT &C, SequenceNumberT SeqNo,
>> > -                         ErrorReturn &Result) {
>> > -      const FunctionIdT ResponseId =
>> > -          RPCFunctionIdTraits<FunctionIdT>::ResponseId;
>> > +  // Function type of the handler.
>> > +  using Type = RetT(ArgTs...);
>> >
>> > -      // If the handler returned an error then bail out with that.
>> > -      if (Result)
>> > -        return std::move(Result);
>> > +  // Return type of the handler.
>> > +  using ReturnType = RetT;
>> >
>> > -      // Otherwise open a new message on the channel and send the
>> result.
>> > -      if (auto Err = startSendMessage(C))
>> > -        return Err;
>> > -      if (auto Err = serializeSeq(C, ResponseId, SeqNo))
>> > -        return Err;
>> > -      return endSendMessage(C);
>> > -    }
>> > -  };
>> > +  // A std::tuple wrapping the handler arguments.
>> > +  using ArgStorage =
>> > +    std::tuple<
>> > +      typename std::decay<
>> > +        typename std::remove_reference<ArgTs>::type>::type...>;
>> > +
>> > +  // Call the given handler with the given arguments.
>> > +  template <typename HandlerT>
>> > +  static typename ResultTraits<RetT>::ErrorReturnType
>> > +  runHandler(HandlerT &Handler, ArgStorage &Args) {
>> > +    return runHandlerHelper<RetT>(Handler, Args,
>> > +                                  llvm::index_sequence_for<ArgTs
>> ...>());
>> > +  }
>> >
>> > -  // Helper for the call primitive.
>> > -  template <typename ChannelT, typename SequenceNumberT, typename Func>
>> > -  class CallHelper;
>> > -
>> > -  template <typename ChannelT, typename SequenceNumberT, typename
>> FunctionIdT,
>> > -            FunctionIdT FuncId, typename RetT, typename... ArgTs>
>> > -  class CallHelper<ChannelT, SequenceNumberT,
>> > -                   FunctionHelper<FunctionIdT, FuncId,
>> RetT(ArgTs...)>> {
>> > -  public:
>> > -    static Error call(ChannelT &C, SequenceNumberT SeqNo,
>> > -                      const ArgTs &... Args) {
>> > -      if (auto Err = startSendMessage(C))
>> > -        return Err;
>> > -      if (auto Err = serializeSeq(C, FuncId, SeqNo, Args...))
>> > -        return Err;
>> > -      return endSendMessage(C);
>> > -    }
>> > -  };
>> > +  // Serialize arguments to the channel.
>> > +  template <typename ChannelT, typename... CArgTs>
>> > +  static Error serializeArgs(ChannelT &C, const CArgTs... CArgs) {
>> > +    return SequenceSerialization<ChannelT, ArgTs...>::serialize(C,
>> CArgs...);
>> > +  }
>> >
>> > -  // Helper for handle primitive.
>> > -  template <typename ChannelT, typename SequenceNumberT, typename Func>
>> > -  class HandlerHelper;
>> > -
>> > -  template <typename ChannelT, typename SequenceNumberT, typename
>> FunctionIdT,
>> > -            FunctionIdT FuncId, typename RetT, typename... ArgTs>
>> > -  class HandlerHelper<ChannelT, SequenceNumberT,
>> > -                      FunctionHelper<FunctionIdT, FuncId,
>> RetT(ArgTs...)>> {
>> > -  public:
>> > -    template <typename HandlerT>
>> > -    static Error handle(ChannelT &C, HandlerT Handler) {
>> > -      return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs
>> ...>());
>> > -    }
>> > -
>> > -  private:
>> > -    typedef FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> Func;
>> > -
>> > -    template <typename HandlerT, size_t... Is>
>> > -    static Error readAndHandle(ChannelT &C, HandlerT Handler,
>> > -                               llvm::index_sequence<Is...> _) {
>> > -      std::tuple<ArgTs...> RPCArgs;
>> > -      SequenceNumberT SeqNo;
>> > -      // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable
>> warning
>> > -      // for RPCArgs. Void cast RPCArgs to work around this for now.
>> > -      // FIXME: Remove this workaround once we can assume a working
>> GCC version.
>> > -      (void)RPCArgs;
>> > -      if (auto Err = deserializeSeq(C, SeqNo,
>> std::get<Is>(RPCArgs)...))
>> > -        return Err;
>> > +  // Deserialize arguments from the channel.
>> > +  template <typename ChannelT, typename... CArgTs>
>> > +  static Error deserializeArgs(ChannelT &C, std::tuple<CArgTs...>
>> &Args) {
>> > +    return deserializeArgsHelper(C, Args,
>> > +                                 llvm::index_sequence_for<CArg
>> Ts...>());
>> > +  }
>> >
>> > -      // We've deserialized the arguments, so unlock the channel for
>> reading
>> > -      // before we call the handler. This allows recursive RPC calls.
>> > -      if (auto Err = endReceiveMessage(C))
>> > -        return Err;
>> > +private:
>> >
>> > -      // Run the handler and get the result.
>> > -      auto Result = Handler(std::get<Is>(RPCArgs)...);
>> > +  // For non-void user handlers: unwrap the args tuple and call the
>> handler,
>> > +  // returning the result.
>> > +  template <typename RetTAlt, typename HandlerT, size_t... Indexes>
>> > +  static typename std::enable_if<
>> > +                    !std::is_void<RetTAlt>::value,
>> > +                    typename ResultTraits<RetT>::ErrorRetur
>> nType>::type
>> > +  runHandlerHelper(HandlerT &Handler, ArgStorage &Args,
>> > +                   llvm::index_sequence<Indexes...>) {
>> > +    return Handler(std::move(std::get<Indexes>(Args))...);
>> > +  }
>> >
>> > -      // Return the result to the client.
>> > -      return Func::template respond<ChannelT, SequenceNumberT>(C,
>> SeqNo,
>> > -                                                               Result);
>> > -    }
>> > -  };
>> > +  // For void user handlers: unwrap the args tuple and call the
>> handler, then
>> > +  // return Error::success().
>> > +  template <typename RetTAlt, typename HandlerT, size_t... Indexes>
>> > +  static typename std::enable_if<
>> > +                    std::is_void<RetTAlt>::value,
>> > +                    typename ResultTraits<RetT>::ErrorRetur
>> nType>::type
>> > +  runHandlerHelper(HandlerT &Handler, ArgStorage &Args,
>> > +                   llvm::index_sequence<Indexes...>) {
>> > +    Handler(std::move(std::get<Indexes>(Args))...);
>> > +    return ResultTraits<RetT>::ErrorReturnType::success();
>> > +  }
>> >
>> > -  // Helper for wrapping member functions up as functors.
>> > -  template <typename ClassT, typename RetT, typename... ArgTs>
>> > -  class MemberFnWrapper {
>> > -  public:
>> > -    typedef RetT (ClassT::*MethodT)(ArgTs...);
>> > -    MemberFnWrapper(ClassT &Instance, MethodT Method)
>> > -        : Instance(Instance), Method(Method) {}
>> > -    RetT operator()(ArgTs &... Args) { return
>> (Instance.*Method)(Args...); }
>> > -
>> > -  private:
>> > -    ClassT &Instance;
>> > -    MethodT Method;
>> > -  };
>> > +  template <typename ChannelT, typename... CArgTs, size_t... Indexes>
>> > +  static
>> > +  Error deserializeArgsHelper(ChannelT &C, std::tuple<CArgTs...> &Args,
>> > +                              llvm::index_sequence<Indexes...> _) {
>> > +    return SequenceSerialization<ChannelT, ArgTs...>::
>> > +      deserialize(C, std::get<Indexes>(Args)...);
>> > +  }
>> >
>> > -  // Helper that provides a Functor for deserializing arguments.
>> > -  template <typename... ArgTs> class ReadArgs {
>> > -  public:
>> > -    Error operator()() { return Error::success(); }
>> > -  };
>> > +};
>> >
>> > -  template <typename ArgT, typename... ArgTs>
>> > -  class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
>> > -  public:
>> > -    ReadArgs(ArgT &Arg, ArgTs &... Args)
>> > -        : ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
>> > +// Handler traits for class methods (especially call operators for
>> lambdas).
>> > +template <typename Class, typename RetT, typename... ArgTs>
>> > +class HandlerTraits<RetT (Class::*)(ArgTs...)>
>> > +  : public HandlerTraits<RetT(ArgTs...)> {};
>> > +
>> > +// Handler traits for const class methods (especially call operators
>> for
>> > +// lambdas).
>> > +template <typename Class, typename RetT, typename... ArgTs>
>> > +class HandlerTraits<RetT (Class::*)(ArgTs...) const>
>> > +  : public HandlerTraits<RetT(ArgTs...)> {};
>> > +
>> > +// Utility to peel the Expected wrapper off a response handler error
>> type.
>> > +template <typename HandlerT>
>> > +class UnwrapResponseHandlerArg;
>> >
>> > -    Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
>> > -      this->Arg = std::move(ArgVal);
>> > -      return ReadArgs<ArgTs...>::operator()(ArgVals...);
>> > -    }
>> > +template <typename ArgT>
>> > +class UnwrapResponseHandlerArg<Error(Expected<ArgT>)> {
>> > +public:
>> > +  using ArgType = ArgT;
>> > +};
>> >
>> > -  private:
>> > -    ArgT &Arg;
>> > -  };
>> > +template <typename ArgT>
>> > +class UnwrapResponseHandlerArg<ErrorSuccess(Expected<ArgT>)> {
>> > +public:
>> > +  using ArgType = ArgT;
>> > };
>> >
>> > -/// Contains primitive utilities for defining, calling and handling
>> calls to
>> > -/// remote procedures. ChannelT is a bidirectional stream conforming
>> to the
>> > -/// RPCChannel interface (see RPCChannel.h), and FunctionIdT is a
>> procedure
>> > -/// identifier type that must be serializable on ChannelT.
>> > -///
>> > -/// These utilities support the construction of very primitive RPC
>> utilities.
>> > -/// Their intent is to ensure correct serialization and
>> deserialization of
>> > -/// procedure arguments, and to keep the client and server's view of
>> the API in
>> > -/// sync.
>> > -///
>> > -/// These utilities do not support return values. These can be handled
>> by
>> > -/// declaring a corresponding '.*Response' procedure and expecting it
>> after a
>> > -/// call). They also do not support versioning: the client and server
>> *must* be
>> > -/// compiled with the same procedure definitions.
>> > -///
>> > -///
>> > -///
>> > -/// Overview (see comments individual types/methods for details):
>> > -///
>> > -/// Function<Id, Args...> :
>> > -///
>> > -///   associates a unique serializable id with an argument list.
>> > -///
>> > -///
>> > -/// call<Func>(Channel, Args...) :
>> > -///
>> > -///   Calls the remote procedure 'Func' by serializing Func's id
>> followed by its
>> > -/// arguments and sending the resulting bytes to 'Channel'.
>> > -///
>> > -///
>> > -/// handle<Func>(Channel, <functor matching Error(Args...)> :
>> > -///
>> > -///   Handles a call to 'Func' by deserializing its arguments and
>> calling the
>> > -/// given functor. This assumes that the id for 'Func' has already been
>> > -/// deserialized.
>> > -///
>> > -/// expect<Func>(Channel, <functor matching Error(Args...)> :
>> > -///
>> > -///   The same as 'handle', except that the procedure id should not
>> have been
>> > -/// read yet. Expect will deserialize the id and assert that it
>> matches Func's
>> > -/// id. If it does not, and unexpected RPC call error is returned.
>> > -template <typename ChannelT, typename FunctionIdT = uint32_t,
>> > -          typename SequenceNumberT = uint16_t>
>> > -class RPC : public RPCBase {
>> > -public:
>> > -  /// RPC default constructor.
>> > -  RPC() = default;
>> > -
>> > -  /// RPC instances cannot be copied.
>> > -  RPC(RPC &&) = default;
>> > -  RPC &operator=(RPC &&) = default;
>> >
>> > -  /// Utility class for defining/referring to RPC procedures.
>> > -  ///
>> > -  /// Typedefs of this utility are used when calling/handling remote
>> procedures.
>> > -  ///
>> > -  /// FuncId should be a unique value of FunctionIdT (i.e. not used
>> with any
>> > -  /// other Function typedef in the RPC API being defined.
>> > -  ///
>> > -  /// the template argument Ts... gives the argument list for the
>> remote
>> > -  /// procedure.
>> > -  ///
>> > -  /// E.g.
>> > -  ///
>> > -  ///   typedef Function<0, bool> Func1;
>> > -  ///   typedef Function<1, std::string, std::vector<int>> Func2;
>> > -  ///
>> > -  ///   if (auto Err = call<Func1>(Channel, true))
>> > -  ///     /* handle Err */;
>> > -  ///
>> > -  ///   if (auto Err = expect<Func2>(Channel,
>> > -  ///         [](std::string &S, std::vector<int> &V) {
>> > -  ///           // Stuff.
>> > -  ///           return Error::success();
>> > -  ///         })
>> > -  ///     /* handle Err */;
>> > -  ///
>> > -  template <FunctionIdT FuncId, typename FnT>
>> > -  using Function = FunctionHelper<FunctionIdT, FuncId, FnT>;
>> > +// ResponseHandler represents a handler for a not-yet-received
>> function call
>> > +// result.
>> > +template <typename ChannelT>
>> > +class ResponseHandler {
>> > +public:
>> > +  virtual ~ResponseHandler() {}
>> >
>> > -  /// Return type for non-blocking call primitives.
>> > -  template <typename Func>
>> > -  using NonBlockingCallResult = std::future<typename
>> Func::PErrorReturn>;
>> > +  // Reads the function result off the wire and acts on it. The
>> meaning of
>> > +  // "act" will depend on how this method is implemented in any given
>> > +  // ResponseHandler subclass but could, for example, mean running a
>> > +  // user-specified handler or setting a promise value.
>> > +  virtual Error handleResponse(ChannelT &C) = 0;
>> > +
>> > +  // Abandons this outstanding result.
>> > +  virtual void abandon() = 0;
>> > +
>> > +  // Create an error instance representing an abandoned response.
>> > +  static Error createAbandonedResponseError() {
>> > +    return make_error<StringError>("RPC function call failed to
>> return",
>> > +                                   inconvertibleErrorCode());
>> > +  }
>> > +};
>> >
>> > -  /// Return type for non-blocking call-with-seq primitives.
>> > -  template <typename Func>
>> > -  using NonBlockingCallWithSeqResult =
>> > -      std::pair<NonBlockingCallResult<Func>, SequenceNumberT>;
>> > +// ResponseHandler subclass for RPC functions with non-void returns.
>> > +template <typename ChannelT, typename FuncRetT, typename HandlerT>
>> > +class ResponseHandlerImpl : public ResponseHandler<ChannelT> {
>> > +public:
>> > +  ResponseHandlerImpl(HandlerT Handler)
>> > +      : Handler(std::move(Handler)) {}
>> >
>> > -  /// Call Func on Channel C. Does not block, does not call send.
>> Returns a pair
>> > -  /// of a future result and the sequence number assigned to the
>> result.
>> > -  ///
>> > -  /// This utility function is primarily used for single-threaded mode
>> support,
>> > -  /// where the sequence number can be used to wait for the
>> corresponding
>> > -  /// result. In multi-threaded mode the appendCallNB method, which
>> does not
>> > -  /// return the sequence numeber, should be preferred.
>> > -  template <typename Func, typename... ArgTs>
>> > -  Expected<NonBlockingCallWithSeqResult<Func>>
>> > -  appendCallNBWithSeq(ChannelT &C, const ArgTs &... Args) {
>> > -    auto SeqNo = SequenceNumberMgr.getSequenceNumber();
>> > -    std::promise<typename Func::PErrorReturn> Promise;
>> > -    auto Result = Promise.get_future();
>> > -    OutstandingResults[SeqNo] =
>> > -        createOutstandingResult<Func>(std::move(Promise));
>> > -
>> > -    if (auto Err = CallHelper<ChannelT, SequenceNumberT,
>> Func>::call(C, SeqNo,
>> > -
>>  Args...)) {
>> > -      abandonOutstandingResults();
>> > -      Func::consumeAbandoned(Result);
>> > -      return std::move(Err);
>> > -    } else
>> > -      return NonBlockingCallWithSeqResult<Func>(std::move(Result),
>> SeqNo);
>> > +  // Handle the result by deserializing it from the channel then
>> passing it
>> > +  // to the user defined handler.
>> > +  Error handleResponse(ChannelT &C) override {
>> > +    using ArgType = typename UnwrapResponseHandlerArg<
>> > +                      typename HandlerTraits<HandlerT>::Type>
>> ::ArgType;
>> > +    ArgType Result;
>> > +    if (auto Err = SerializationTraits<ChannelT, FuncRetT, ArgType>::
>> > +                     deserialize(C, Result))
>> > +      return Err;
>> > +    if (auto Err = C.endReceiveMessage())
>> > +      return Err;
>> > +    return Handler(Result);
>> >   }
>> >
>> > -  /// The same as appendCallNBWithSeq, except that it calls C.send() to
>> > -  /// flush the channel after serializing the call.
>> > -  template <typename Func, typename... ArgTs>
>> > -  Expected<NonBlockingCallWithSeqResult<Func>>
>> > -  callNBWithSeq(ChannelT &C, const ArgTs &... Args) {
>> > -    auto Result = appendCallNBWithSeq<Func>(C, Args...);
>> > -    if (!Result)
>> > -      return Result;
>> > -    if (auto Err = C.send()) {
>> > -      abandonOutstandingResults();
>> > -      Func::consumeAbandoned(Result->first);
>> > -      return std::move(Err);
>> > +  // Abandon this response by calling the handler with an 'abandoned
>> response'
>> > +  // error.
>> > +  void abandon() override {
>> > +    if (auto Err = Handler(this->createAbandonedResponseError())) {
>> > +      // Handlers should not fail when passed an abandoned response
>> error.
>> > +      report_fatal_error(std::move(Err));
>> >     }
>> > -    return Result;
>> >   }
>> >
>> > -  /// Serialize Args... to channel C, but do not call send.
>> > -  /// Returns an error if serialization fails, otherwise returns a
>> > -  /// std::future<Expected<T>> (or a future<Error> for void functions).
>> > -  template <typename Func, typename... ArgTs>
>> > -  Expected<NonBlockingCallResult<Func>> appendCallNB(ChannelT &C,
>> > -                                                     const ArgTs &...
>> Args) {
>> > -    auto FutureResAndSeqOrErr = appendCallNBWithSeq<Func>(C, Args...);
>> > -    if (FutureResAndSeqOrErr)
>> > -      return std::move(FutureResAndSeqOrErr->first);
>> > -    return FutureResAndSeqOrErr.takeError();
>> > -  }
>> > +private:
>> > +  HandlerT Handler;
>> > +};
>> >
>> > -  /// The same as appendCallNB, except that it calls C.send to flush
>> the
>> > -  /// channel after serializing the call.
>> > -  template <typename Func, typename... ArgTs>
>> > -  Expected<NonBlockingCallResult<Func>> callNB(ChannelT &C,
>> > -                                               const ArgTs &... Args) {
>> > -    auto FutureResAndSeqOrErr = callNBWithSeq<Func>(C, Args...);
>> > -    if (FutureResAndSeqOrErr)
>> > -      return std::move(FutureResAndSeqOrErr->first);
>> > -    return FutureResAndSeqOrErr.takeError();
>> > +// ResponseHandler subclass for RPC functions with void returns.
>> > +template <typename ChannelT, typename HandlerT>
>> > +class ResponseHandlerImpl<ChannelT, void, HandlerT>
>> > +  : public ResponseHandler<ChannelT> {
>> > +public:
>> > +  ResponseHandlerImpl(HandlerT Handler)
>> > +      : Handler(std::move(Handler)) {}
>> > +
>> > +  // Handle the result (no actual value, just a notification that the
>> function
>> > +  // has completed on the remote end) by calling the user-defined
>> handler with
>> > +  // Error::success().
>> > +  Error handleResponse(ChannelT &C) override {
>> > +    if (auto Err = C.endReceiveMessage())
>> > +      return Err;
>> > +    return Handler(Error::success());
>> >   }
>> >
>> > -  /// Call Func on Channel C. Blocks waiting for a result. Returns an
>> Error
>> > -  /// for void functions or an Expected<T> for functions returning a T.
>> > -  ///
>> > -  /// This function is for use in threaded code where another thread is
>> > -  /// handling responses and incoming calls.
>> > -  template <typename Func, typename... ArgTs>
>> > -  typename Func::ErrorReturn callB(ChannelT &C, const ArgTs &... Args)
>> {
>> > -    if (auto FutureResOrErr = callNBWithSeq<Func>(C, Args...)) {
>> > -      if (auto Err = C.send()) {
>> > -        abandonOutstandingResults();
>> > -        Func::consumeAbandoned(FutureResOrErr->first);
>> > -        return std::move(Err);
>> > -      }
>> > -      return FutureResOrErr->first.get();
>> > -    } else
>> > -      return FutureResOrErr.takeError();
>> > +  // Abandon this response by calling the handler with an 'abandoned
>> response'
>> > +  // error.
>> > +  void abandon() override {
>> > +    if (auto Err = Handler(this->createAbandonedResponseError())) {
>> > +      // Handlers should not fail when passed an abandoned response
>> error.
>> > +      report_fatal_error(std::move(Err));
>> > +    }
>> >   }
>> >
>> > -  /// Call Func on Channel C. Block waiting for a result. While
>> blocked, run
>> > -  /// HandleOther to handle incoming calls (Response calls will be
>> handled
>> > -  /// implicitly before calling HandleOther). Returns an Error for void
>> > -  /// functions or an Expected<T> for functions returning a T.
>> > -  ///
>> > -  /// This function is for use in single threaded mode when the
>> calling thread
>> > -  /// must act as both sender and receiver.
>> > -  template <typename Func, typename HandleFtor, typename... ArgTs>
>> > -  typename Func::ErrorReturn
>> > -  callSTHandling(ChannelT &C, HandleFtor &HandleOther, const ArgTs
>> &... Args) {
>> > -    if (auto ResultAndSeqNoOrErr = callNBWithSeq<Func>(C, Args...)) {
>> > -      auto &ResultAndSeqNo = *ResultAndSeqNoOrErr;
>> > -      if (auto Err = waitForResult(C, ResultAndSeqNo.second,
>> HandleOther))
>> > -        return std::move(Err);
>> > -      return ResultAndSeqNo.first.get();
>> > -    } else
>> > -      return ResultAndSeqNoOrErr.takeError();
>> > +private:
>> > +  HandlerT Handler;
>> > +};
>> > +
>> > +// Create a ResponseHandler from a given user handler.
>> > +template <typename ChannelT, typename FuncRetT, typename HandlerT>
>> > +std::unique_ptr<ResponseHandler<ChannelT>>
>> > +createResponseHandler(HandlerT H) {
>> > +  return llvm::make_unique<
>> > +           ResponseHandlerImpl<ChannelT, FuncRetT,
>> HandlerT>>(std::move(H));
>> > +}
>> > +
>> > +// Helper for wrapping member functions up as functors. This is useful
>> for
>> > +// installing methods as result handlers.
>> > +template <typename ClassT, typename RetT, typename... ArgTs>
>> > +class MemberFnWrapper {
>> > +public:
>> > +  using MethodT = RetT(ClassT::*)(ArgTs...);
>> > +  MemberFnWrapper(ClassT &Instance, MethodT Method)
>> > +      : Instance(Instance), Method(Method) {}
>> > +  RetT operator()(ArgTs &&... Args) {
>> > +    return (Instance.*Method)(std::move(Args)...);
>> >   }
>> > +private:
>> > +  ClassT &Instance;
>> > +  MethodT Method;
>> > +};
>> >
>> > -  /// Call Func on Channel C. Block waiting for a result. Returns an
>> Error for
>> > -  /// void functions or an Expected<T> for functions returning a T.
>> > -  template <typename Func, typename... ArgTs>
>> > -  typename Func::ErrorReturn callST(ChannelT &C, const ArgTs &...
>> Args) {
>> > -    return callSTHandling<Func>(C, handleNone, Args...);
>> > +// Helper that provides a Functor for deserializing arguments.
>> > +template <typename... ArgTs> class ReadArgs {
>> > +public:
>> > +  Error operator()() { return Error::success(); }
>> > +};
>> > +
>> > +template <typename ArgT, typename... ArgTs>
>> > +class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
>> > +public:
>> > +  ReadArgs(ArgT &Arg, ArgTs &... Args)
>> > +      : ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
>> > +
>> > +  Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
>> > +    this->Arg = std::move(ArgVal);
>> > +    return ReadArgs<ArgTs...>::operator()(ArgVals...);
>> >   }
>> > +private:
>> > +  ArgT &Arg;
>> > +};
>> >
>> > -  /// Start receiving a new function call.
>> > -  ///
>> > -  /// Calls startReceiveMessage on the channel, then deserializes a
>> FunctionId
>> > -  /// into Id.
>> > -  Error startReceivingFunction(ChannelT &C, FunctionIdT &Id) {
>> > -    if (auto Err = startReceiveMessage(C))
>> > -      return Err;
>> > +// Manage sequence numbers.
>> > +template <typename SequenceNumberT>
>> > +class SequenceNumberManager {
>> > +public:
>> > +  // Reset, making all sequence numbers available.
>> > +  void reset() {
>> > +    std::lock_guard<std::mutex> Lock(SeqNoLock);
>> > +    NextSequenceNumber = 0;
>> > +    FreeSequenceNumbers.clear();
>> > +  }
>> >
>> > -    return deserializeSeq(C, Id);
>> > +  // Get the next available sequence number. Will re-use numbers that
>> have
>> > +  // been released.
>> > +  SequenceNumberT getSequenceNumber() {
>> > +    std::lock_guard<std::mutex> Lock(SeqNoLock);
>> > +    if (FreeSequenceNumbers.empty())
>> > +      return NextSequenceNumber++;
>> > +    auto SequenceNumber = FreeSequenceNumbers.back();
>> > +    FreeSequenceNumbers.pop_back();
>> > +    return SequenceNumber;
>> >   }
>> >
>> > -  /// Deserialize args for Func from C and call Handler. The signature
>> of
>> > -  /// handler must conform to 'Error(Args...)' where Args... matches
>> > -  /// the arguments used in the Func typedef.
>> > -  template <typename Func, typename HandlerT>
>> > -  static Error handle(ChannelT &C, HandlerT Handler) {
>> > -    return HandlerHelper<ChannelT, SequenceNumberT, Func>::handle(C,
>> Handler);
>> > +  // Release a sequence number, making it available for re-use.
>> > +  void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
>> > +    std::lock_guard<std::mutex> Lock(SeqNoLock);
>> > +    FreeSequenceNumbers.push_back(SequenceNumber);
>> >   }
>> >
>> > -  /// Helper version of 'handle' for calling member functions.
>> > -  template <typename Func, typename ClassT, typename RetT, typename...
>> ArgTs>
>> > -  static Error handle(ChannelT &C, ClassT &Instance,
>> > -                      RetT (ClassT::*HandlerMethod)(ArgTs...)) {
>> > -    return handle<Func>(
>> > -        C, MemberFnWrapper<ClassT, RetT, ArgTs...>(Instance,
>> HandlerMethod));
>> > +private:
>> > +  std::mutex SeqNoLock;
>> > +  SequenceNumberT NextSequenceNumber = 0;
>> > +  std::vector<SequenceNumberT> FreeSequenceNumbers;
>> > +};
>> > +
>> > +/// Contains primitive utilities for defining, calling and handling
>> calls to
>> > +/// remote procedures. ChannelT is a bidirectional stream conforming
>> to the
>> > +/// RPCChannel interface (see RPCChannel.h), FunctionIdT is a procedure
>> > +/// identifier type that must be serializable on ChannelT, and
>> SequenceNumberT
>> > +/// is an integral type that will be used to number in-flight function
>> calls.
>> > +///
>> > +/// These utilities support the construction of very primitive RPC
>> utilities.
>> > +/// Their intent is to ensure correct serialization and
>> deserialization of
>> > +/// procedure arguments, and to keep the client and server's view of
>> the API in
>> > +/// sync.
>> > +template <typename ImplT, typename ChannelT, typename FunctionIdT,
>> > +          typename SequenceNumberT>
>> > +class RPCBase {
>> > +protected:
>> > +
>> > +  class OrcRPCInvalid : public Function<OrcRPCInvalid, void()> {
>> > +  public:
>> > +    static const char *getName() { return "__orc_rpc$invalid"; }
>> > +  };
>> > +
>> > +  class OrcRPCResponse : public Function<OrcRPCResponse, void()> {
>> > +  public:
>> > +    static const char *getName() { return "__orc_rpc$response"; }
>> > +  };
>> > +
>> > +  class OrcRPCNegotiate
>> > +    : public Function<OrcRPCNegotiate, FunctionIdT(std::string)> {
>> > +  public:
>> > +    static const char *getName() { return "__orc_rpc$negotiate"; }
>> > +  };
>> > +
>> > +public:
>> > +
>> > +  /// Construct an RPC instance on a channel.
>> > +  RPCBase(ChannelT &C, bool LazyAutoNegotiation)
>> > +      : C(C), LazyAutoNegotiation(LazyAutoNegotiation) {
>> > +    // Hold ResponseId in a special variable, since we expect Response
>> to be
>> > +    // called relatively frequently, and want to avoid the map lookup.
>> > +    ResponseId = FnIdAllocator.getResponseId();
>> > +    RemoteFunctionIds[OrcRPCResponse::getPrototype()] = ResponseId;
>> > +
>> > +    // Register the negotiate function id and handler.
>> > +    auto NegotiateId = FnIdAllocator.getNegotiateId();
>> > +    RemoteFunctionIds[OrcRPCNegotiate::getPrototype()] = NegotiateId;
>> > +    Handlers[NegotiateId] =
>> > +      wrapHandler<OrcRPCNegotiate>([this](const std::string &Name) {
>> > +                                     return handleNegotiate(Name);
>> > +                                   }, LaunchPolicy());
>> >   }
>> >
>> > -  /// Deserialize a FunctionIdT from C and verify it matches the id
>> for Func.
>> > -  /// If the id does match, deserialize the arguments and call the
>> handler
>> > -  /// (similarly to handle).
>> > -  /// If the id does not match, return an unexpect RPC call error and
>> do not
>> > -  /// deserialize any further bytes.
>> > -  template <typename Func, typename HandlerT>
>> > -  Error expect(ChannelT &C, HandlerT Handler) {
>> > -    FunctionIdT FuncId;
>> > -    if (auto Err = startReceivingFunction(C, FuncId))
>> > +  /// Append a call Func, does not call send on the channel.
>> > +  /// The first argument specifies a user-defined handler to be run
>> when the
>> > +  /// function returns. The handler should take an
>> Expected<Func::ReturnType>,
>> > +  /// or an Error (if Func::ReturnType is void). The handler will be
>> called
>> > +  /// with an error if the return value is abandoned due to a channel
>> error.
>> > +  template <typename Func, typename HandlerT, typename... ArgTs>
>> > +  Error appendCallAsync(HandlerT Handler, const ArgTs &... Args) {
>> > +    // Look up the function ID.
>> > +    FunctionIdT FnId;
>> > +    if (auto FnIdOrErr = getRemoteFunctionId<Func>())
>> > +      FnId = *FnIdOrErr;
>> > +    else {
>> > +      // This isn't a channel error so we don't want to abandon other
>> pending
>> > +      // responses, but we still need to run the user handler with an
>> error to
>> > +      // let them know the call failed.
>> > +      if (auto Err = Handler(orcError(OrcErrorCode:
>> :UnknownRPCFunction)))
>> > +        report_fatal_error(std::move(Err));
>> > +      return FnIdOrErr.takeError();
>> > +    }
>> > +
>> > +    // Allocate a sequence number.
>> > +    auto SeqNo = SequenceNumberMgr.getSequenceNumber();
>> > +    assert(!PendingResponses.count(SeqNo) &&
>> > +           "Sequence number already allocated");
>> > +
>> > +    // Install the user handler.
>> > +    PendingResponses[SeqNo] =
>> > +      detail::createResponseHandler<ChannelT, typename
>> Func::ReturnType>(
>> > +                std::move(Handler));
>> > +
>> > +    // Open the function call message.
>> > +    if (auto Err = C.startSendMessage(FnId, SeqNo)) {
>> > +      abandonPendingResponses();
>> > +      return joinErrors(std::move(Err), C.endSendMessage());
>> > +    }
>> > +
>> > +    // Serialize the call arguments.
>> > +    if (auto Err =
>> > +          detail::HandlerTraits<typename Func::Type>::
>> > +            serializeArgs(C, Args...)) {
>> > +      abandonPendingResponses();
>> > +      return joinErrors(std::move(Err), C.endSendMessage());
>> > +    }
>> > +
>> > +    // Close the function call messagee.
>> > +    if (auto Err = C.endSendMessage()) {
>> > +      abandonPendingResponses();
>> >       return std::move(Err);
>> > -    if (FuncId != Func::Id)
>> > -      return orcError(OrcErrorCode::UnexpectedRPCCall);
>> > -    return handle<Func>(C, Handler);
>> > +    }
>> > +
>> > +    return Error::success();
>> >   }
>> >
>> > -  /// Helper version of expect for calling member functions.
>> > -  template <typename Func, typename ClassT, typename... ArgTs>
>> > -  static Error expect(ChannelT &C, ClassT &Instance,
>> > -                      Error (ClassT::*HandlerMethod)(ArgTs...)) {
>> > -    return expect<Func>(
>> > -        C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));
>> > +
>> > +  template <typename Func, typename HandlerT, typename... ArgTs>
>> > +  Error callAsync(HandlerT Handler, const ArgTs &... Args) {
>> > +    if (auto Err = appendCallAsync<Func>(std::move(Handler), Args...))
>> > +      return Err;
>> > +    return C.send();
>> > +  }
>> > +
>> > +  /// Handle one incoming call.
>> > +  Error handleOne() {
>> > +    FunctionIdT FnId;
>> > +    SequenceNumberT SeqNo;
>> > +    if (auto Err = C.startReceiveMessage(FnId, SeqNo))
>> > +      return Err;
>> > +    if (FnId == ResponseId)
>> > +      return handleResponse(SeqNo);
>> > +    auto I = Handlers.find(FnId);
>> > +    if (I != Handlers.end())
>> > +      return I->second(C, SeqNo);
>> > +
>> > +    // else: No handler found. Report error to client?
>> > +    return orcError(OrcErrorCode::UnexpectedRPCCall);
>> >   }
>> >
>> >   /// Helper for handling setter procedures - this method returns a
>> functor that
>> > @@ -621,160 +730,417 @@ public:
>> >   ///     /* Handle Args */ ;
>> >   ///
>> >   template <typename... ArgTs>
>> > -  static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
>> > -    return ReadArgs<ArgTs...>(Args...);
>> > +  static detail::ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
>> > +    return detail::ReadArgs<ArgTs...>(Args...);
>> >   }
>> >
>> > -  /// Read a response from Channel.
>> > -  /// This should be called from the receive loop to retrieve results.
>> > -  Error handleResponse(ChannelT &C, SequenceNumberT *SeqNoRet =
>> nullptr) {
>> > -    SequenceNumberT SeqNo;
>> > -    if (auto Err = deserializeSeq(C, SeqNo)) {
>> > -      abandonOutstandingResults();
>> > -      return Err;
>> > -    }
>> > +protected:
>> > +  // The LaunchPolicy type allows a launch policy to be specified when
>> adding
>> > +  // a function handler. See addHandlerImpl.
>> > +  using LaunchPolicy = std::function<Error(std::function<Error()>)>;
>> > +
>> > +  /// Add the given handler to the handler map and make it available
>> for
>> > +  /// autonegotiation and execution.
>> > +  template <typename Func, typename HandlerT>
>> > +  void addHandlerImpl(HandlerT Handler, LaunchPolicy Launch) {
>> > +    FunctionIdT NewFnId = FnIdAllocator.template allocate<Func>();
>> > +    LocalFunctionIds[Func::getPrototype()] = NewFnId;
>> > +    Handlers[NewFnId] = wrapHandler<Func>(std::move(Handler),
>> > +                                          std::move(Launch));
>> > +  }
>> >
>> > -    if (SeqNoRet)
>> > -      *SeqNoRet = SeqNo;
>> > +  // Abandon all outstanding results.
>> > +  void abandonPendingResponses() {
>> > +    for (auto &KV : PendingResponses)
>> > +      KV.second->abandon();
>> > +    PendingResponses.clear();
>> > +    SequenceNumberMgr.reset();
>> > +  }
>> >
>> > -    auto I = OutstandingResults.find(SeqNo);
>> > -    if (I == OutstandingResults.end()) {
>> > -      abandonOutstandingResults();
>> > +  Error handleResponse(SequenceNumberT SeqNo) {
>> > +    auto I = PendingResponses.find(SeqNo);
>> > +    if (I == PendingResponses.end()) {
>> > +      abandonPendingResponses();
>> >       return orcError(OrcErrorCode::UnexpectedRPCResponse);
>> >     }
>> >
>> > -    if (auto Err = I->second->readResult(C)) {
>> > -      abandonOutstandingResults();
>> > -      // FIXME: Release sequence numbers?
>> > +    auto PRHandler = std::move(I->second);
>> > +    PendingResponses.erase(I);
>> > +    SequenceNumberMgr.releaseSequenceNumber(SeqNo);
>> > +
>> > +    if (auto Err = PRHandler->handleResponse(C)) {
>> > +      abandonPendingResponses();
>> > +      SequenceNumberMgr.reset();
>> >       return Err;
>> >     }
>> >
>> > -    OutstandingResults.erase(I);
>> > -    SequenceNumberMgr.releaseSequenceNumber(SeqNo);
>> > -
>> >     return Error::success();
>> >   }
>> >
>> > -  // Loop waiting for a result with the given sequence number.
>> > -  // This can be used as a receive loop if the user doesn't have a
>> default.
>> > -  template <typename HandleOtherFtor>
>> > -  Error waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo,
>> > -                      HandleOtherFtor &HandleOther = handleNone) {
>> > -    bool GotTgtResult = false;
>> > -
>> > -    while (!GotTgtResult) {
>> > -      FunctionIdT Id = RPCFunctionIdTraits<FunctionIdT>::InvalidId;
>> > -      if (auto Err = startReceivingFunction(C, Id))
>> > -        return Err;
>> > -      if (Id == RPCFunctionIdTraits<FunctionIdT>::ResponseId) {
>> > -        SequenceNumberT SeqNo;
>> > -        if (auto Err = handleResponse(C, &SeqNo))
>> > +  FunctionIdT handleNegotiate(const std::string &Name) {
>> > +    auto I = LocalFunctionIds.find(Name);
>> > +    if (I == LocalFunctionIds.end())
>> > +      return FnIdAllocator.getInvalidId();
>> > +    return I->second;
>> > +  }
>> > +
>> > +  // Find the remote FunctionId for the given function, which must be
>> in the
>> > +  // RemoteFunctionIds map.
>> > +  template <typename Func>
>> > +  Expected<FunctionIdT> getRemoteFunctionId() {
>> > +    // Try to find the id for the given function.
>> > +    auto I = RemoteFunctionIds.find(Func::getPrototype());
>> > +
>> > +    // If we have it in the map, return it.
>> > +    if (I != RemoteFunctionIds.end())
>> > +      return I->second;
>> > +
>> > +    // Otherwise, if we have auto-negotiation enabled, try to
>> negotiate it.
>> > +    if (LazyAutoNegotiation) {
>> > +      auto &Impl = static_cast<ImplT&>(*this);
>> > +      if (auto RemoteIdOrErr =
>> > +          Impl.template callB<OrcRPCNegotiate>(Func::getPrototype()))
>> {
>> > +        auto &RemoteId = *RemoteIdOrErr;
>> > +
>> > +        // If autonegotiation indicates that the remote end doesn't
>> support this
>> > +        // function, return an unknown function error.
>> > +        if (RemoteId == FnIdAllocator.getInvalidId())
>> > +          return orcError(OrcErrorCode::UnknownRPCFunction);
>> > +
>> > +        // Autonegotiation succeeded and returned a valid id. Update
>> the map and
>> > +        // return the id.
>> > +        RemoteFunctionIds[Func::getPrototype()] = RemoteId;
>> > +        return RemoteId;
>> > +      } else {
>> > +        // Autonegotiation failed. Return the error.
>> > +        return RemoteIdOrErr.takeError();
>> > +      }
>> > +    }
>> > +
>> > +    // No key was available in the map and autonegotiation wasn't
>> enabled.
>> > +    // Return an unknown function error.
>> > +    return orcError(OrcErrorCode::UnknownRPCFunction);
>> > +  }
>> > +
>> > +  using WrappedHandlerFn = std::function<Error(ChannelT&,
>> SequenceNumberT)>;
>> > +
>> > +  // Wrap the given user handler in the necessary
>> argument-deserialization code,
>> > +  // result-serialization code, and call to the launch policy (if
>> present).
>> > +  template <typename Func, typename HandlerT>
>> > +  WrappedHandlerFn wrapHandler(HandlerT Handler, LaunchPolicy Launch) {
>> > +    return
>> > +      [this, Handler, Launch](ChannelT &Channel, SequenceNumberT
>> SeqNo) -> Error {
>> > +        // Start by deserializing the arguments.
>> > +        auto Args =
>> > +          std::make_shared<typename detail::HandlerTraits<HandlerT
>> >::ArgStorage>();
>> > +        if (auto Err = detail::HandlerTraits<typename Func::Type>::
>> > +                         deserializeArgs(Channel, *Args))
>> >           return Err;
>> > -        GotTgtResult = (SeqNo == TgtSeqNo);
>> > -      } else if (auto Err = HandleOther(C, Id))
>> > -        return Err;
>> > +
>> > +        // GCC 4.7 and 4.8 incorrectly issue a
>> -Wunused-but-set-variable warning
>> > +        // for RPCArgs. Void cast RPCArgs to work around this for now.
>> > +        // FIXME: Remove this workaround once we can assume a working
>> GCC version.
>> > +        (void)Args;
>> > +
>> > +        // End receieve message, unlocking the channel for reading.
>> > +        if (auto Err = Channel.endReceiveMessage())
>> > +          return Err;
>> > +
>> > +        // Build the handler/responder.
>> > +        auto Responder =
>> > +          [this, Handler, Args, &Channel, SeqNo]() mutable -> Error {
>> > +            using HTraits = detail::HandlerTraits<HandlerT>;
>> > +            using FuncReturn = typename Func::ReturnType;
>> > +            return detail::respond<FuncReturn>(Channel, ResponseId,
>> SeqNo,
>> > +
>>  HTraits::runHandler(Handler,
>> > +
>>  *Args));
>> > +          };
>> > +
>> > +        // If there is an explicit launch policy then use it to launch
>> the
>> > +        // handler.
>> > +        if (Launch)
>> > +          return Launch(std::move(Responder));
>> > +
>> > +        // Otherwise run the handler on the listener thread.
>> > +        return Responder();
>> > +      };
>> > +  }
>> > +
>> > +  ChannelT &C;
>> > +
>> > +  bool LazyAutoNegotiation;
>> > +
>> > +  RPCFunctionIdAllocator<FunctionIdT> FnIdAllocator;
>> > +
>> > +  FunctionIdT ResponseId;
>> > +  std::map<std::string, FunctionIdT> LocalFunctionIds;
>> > +  std::map<const char*, FunctionIdT> RemoteFunctionIds;
>> > +
>> > +  std::map<FunctionIdT, WrappedHandlerFn> Handlers;
>> > +
>> > +  detail::SequenceNumberManager<SequenceNumberT> SequenceNumberMgr;
>> > +  std::map<SequenceNumberT, std::unique_ptr<detail::Respon
>> seHandler<ChannelT>>>
>> > +    PendingResponses;
>> > +};
>> > +
>> > +} // end namespace detail
>> > +
>> > +
>> > +template <typename ChannelT,
>> > +          typename FunctionIdT = uint32_t,
>> > +          typename SequenceNumberT = uint32_t>
>> > +class MultiThreadedRPC
>> > +  : public detail::RPCBase<MultiThreadedRPC<ChannelT, FunctionIdT,
>> > +                                            SequenceNumberT>,
>> > +                           ChannelT, FunctionIdT, SequenceNumberT> {
>> > +private:
>> > +  using BaseClass =
>> > +    detail::RPCBase<MultiThreadedRPC<ChannelT, FunctionIdT,
>> SequenceNumberT>,
>> > +                    ChannelT, FunctionIdT, SequenceNumberT>;
>> > +
>> > +public:
>> > +
>> > +  MultiThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
>> > +      : BaseClass(C, LazyAutoNegotiation) {}
>> > +
>> > +  /// The LaunchPolicy type allows a launch policy to be specified
>> when adding
>> > +  /// a function handler. See addHandler.
>> > +  using LaunchPolicy = typename BaseClass::LaunchPolicy;
>> > +
>> > +  /// Add a handler for the given RPC function.
>> > +  /// This installs the given handler functor for the given RPC
>> Function, and
>> > +  /// makes the RPC function available for negotiation/calling from
>> the remote.
>> > +  ///
>> > +  /// The optional LaunchPolicy argument can be used to control how
>> the handler
>> > +  /// is run when called:
>> > +  ///
>> > +  /// * If no LaunchPolicy is given, the handler code will be run on
>> the RPC
>> > +  ///   handler thread that is reading from the channel. This handler
>> cannot
>> > +  ///   make blocking RPC calls (since it would be blocking the thread
>> used to
>> > +  ///   get the result), but can make non-blocking calls.
>> > +  ///
>> > +  /// * If a LaunchPolicy is given, the user's handler will be wrapped
>> in a
>> > +  ///   call to serialize and send the result, and the resulting
>> functor (with
>> > +  ///   type 'Error()' will be passed to the LaunchPolicy. The user
>> can then
>> > +  ///   choose to add the wrapped handler to a work queue, spawn a new
>> thread,
>> > +  ///   or anything else.
>> > +  template <typename Func, typename HandlerT>
>> > +  void addHandler(HandlerT Handler, LaunchPolicy Launch =
>> LaunchPolicy()) {
>> > +    return this->template addHandlerImpl<Func>(std::move(Handler),
>> > +                                               std::move(Launch));
>> > +  }
>> > +
>> > +  /// Negotiate a function id for Func with the other end of the
>> channel.
>> > +  template <typename Func>
>> > +  Error negotiateFunction() {
>> > +    using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
>> > +
>> > +    if (auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype()))
>> {
>> > +      this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
>> > +      return Error::success();
>> > +    } else
>> > +      return RemoteIdOrErr.takeError();
>> > +  }
>> > +
>> > +  /// Convenience method for negotiating multiple functions at once.
>> > +  template <typename Func>
>> > +  Error negotiateFunctions() {
>> > +    return negotiateFunction<Func>();
>> > +  }
>> > +
>> > +  /// Convenience method for negotiating multiple functions at once.
>> > +  template <typename Func1, typename Func2, typename... Funcs>
>> > +  Error negotiateFunctions() {
>> > +    if (auto Err = negotiateFunction<Func1>())
>> > +      return Err;
>> > +    return negotiateFunctions<Func2, Funcs...>();
>> > +  }
>> > +
>> > +  /// Return type for non-blocking call primitives.
>> > +  template <typename Func>
>> > +  using NonBlockingCallResult =
>> > +    typename detail::ResultTraits<typename
>> Func::ReturnType>::ReturnFutureType;
>> > +
>> > +  /// Call Func on Channel C. Does not block, does not call send.
>> Returns a pair
>> > +  /// of a future result and the sequence number assigned to the
>> result.
>> > +  ///
>> > +  /// This utility function is primarily used for single-threaded mode
>> support,
>> > +  /// where the sequence number can be used to wait for the
>> corresponding
>> > +  /// result. In multi-threaded mode the appendCallNB method, which
>> does not
>> > +  /// return the sequence numeber, should be preferred.
>> > +  template <typename Func, typename... ArgTs>
>> > +  Expected<NonBlockingCallResult<Func>>
>> > +  appendCallNB(const ArgTs &... Args) {
>> > +    using RTraits = detail::ResultTraits<typename Func::ReturnType>;
>> > +    using ErrorReturn = typename RTraits::ErrorReturnType;
>> > +    using ErrorReturnPromise = typename RTraits::ReturnPromiseType;
>> > +
>> > +    // FIXME: Stack allocate and move this into the handler once LLVM
>> builds
>> > +    //        with C++14.
>> > +    auto Promise = std::make_shared<ErrorReturnPromise>();
>> > +    auto FutureResult = Promise->get_future();
>> > +
>> > +    if (auto Err = this->template appendCallAsync<Func>(
>> > +            [Promise](ErrorReturn RetOrErr) {
>> > +              Promise->set_value(std::move(RetOrErr));
>> > +              return Error::success();
>> > +            }, Args...)) {
>> > +      this->abandonPendingResponses();
>> > +      RTraits::consumeAbandoned(FutureResult.get());
>> > +      return std::move(Err);
>> >     }
>> > +    return std::move(FutureResult);
>> > +  }
>> >
>> > +  /// The same as appendCallNBWithSeq, except that it calls C.send() to
>> > +  /// flush the channel after serializing the call.
>> > +  template <typename Func, typename... ArgTs>
>> > +  Expected<NonBlockingCallResult<Func>>
>> > +  callNB(const ArgTs &... Args) {
>> > +    auto Result = appendCallNB<Func>(Args...);
>> > +    if (!Result)
>> > +      return Result;
>> > +    if (auto Err = this->C.send()) {
>> > +      this->abandonPendingResponses();
>> > +      detail::ResultTraits<typename Func::ReturnType>::
>> > +        consumeAbandoned(std::move(Result->get()));
>> > +      return std::move(Err);
>> > +    }
>> > +    return Result;
>> > +  }
>> > +
>> > +  /// Call Func on Channel C. Blocks waiting for a result. Returns an
>> Error
>> > +  /// for void functions or an Expected<T> for functions returning a T.
>> > +  ///
>> > +  /// This function is for use in threaded code where another thread is
>> > +  /// handling responses and incoming calls.
>> > +  template <typename Func, typename... ArgTs,
>> > +            typename AltRetT = typename Func::ReturnType>
>> > +  typename detail::ResultTraits<AltRetT>::ErrorReturnType
>> > +  callB(const ArgTs &... Args) {
>> > +    if (auto FutureResOrErr = callNB<Func>(Args...)) {
>> > +      if (auto Err = this->C.send()) {
>> > +        this->abandonPendingResponses();
>> > +        detail::ResultTraits<typename Func::ReturnType>::
>> > +          consumeAbandoned(std::move(FutureResOrErr->get()));
>> > +        return std::move(Err);
>> > +      }
>> > +      return FutureResOrErr->get();
>> > +    } else
>> > +      return FutureResOrErr.takeError();
>> > +  }
>> > +
>> > +  /// Handle incoming RPC calls.
>> > +  Error handlerLoop() {
>> > +    while (true)
>> > +      if (auto Err = this->handleOne())
>> > +        return Err;
>> >     return Error::success();
>> >   }
>> >
>> > -  // Default handler for 'other' (non-response) functions when waiting
>> for a
>> > -  // result from the channel.
>> > -  static Error handleNone(ChannelT &, FunctionIdT) {
>> > -    return orcError(OrcErrorCode::UnexpectedRPCCall);
>> > -  };
>> > +};
>> >
>> > +template <typename ChannelT,
>> > +          typename FunctionIdT = uint32_t,
>> > +          typename SequenceNumberT = uint32_t>
>> > +class SingleThreadedRPC
>> > +  : public detail::RPCBase<SingleThreadedRPC<ChannelT, FunctionIdT,
>> > +                                             SequenceNumberT>,
>> > +                           ChannelT, FunctionIdT,
>> > +                           SequenceNumberT> {
>> > private:
>> > -  // Manage sequence numbers.
>> > -  class SequenceNumberManager {
>> > -  public:
>> > -    SequenceNumberManager() = default;
>> >
>> > -    SequenceNumberManager(const SequenceNumberManager &) = delete;
>> > -    SequenceNumberManager &operator=(const SequenceNumberManager &) =
>> delete;
>> > +  using BaseClass = detail::RPCBase<SingleThreadedRPC<ChannelT,
>> FunctionIdT,
>> > +                                                      SequenceNumberT>,
>> > +                                    ChannelT, FunctionIdT,
>> SequenceNumberT>;
>> >
>> > -    SequenceNumberManager(SequenceNumberManager &&Other)
>> > -        : NextSequenceNumber(std::move(Other.NextSequenceNumber)),
>> > -          FreeSequenceNumbers(std::move(Other.FreeSequenceNumbers)) {}
>> > -
>> > -    SequenceNumberManager &operator=(SequenceNumberManager &&Other) {
>> > -      NextSequenceNumber = std::move(Other.NextSequenceNumber);
>> > -      FreeSequenceNumbers = std::move(Other.FreeSequenceNumbers);
>> > -      return *this;
>> > -    }
>> > +  using LaunchPolicy = typename BaseClass::LaunchPolicy;
>> >
>> > -    void reset() {
>> > -      std::lock_guard<std::mutex> Lock(SeqNoLock);
>> > -      NextSequenceNumber = 0;
>> > -      FreeSequenceNumbers.clear();
>> > -    }
>> > -
>> > -    SequenceNumberT getSequenceNumber() {
>> > -      std::lock_guard<std::mutex> Lock(SeqNoLock);
>> > -      if (FreeSequenceNumbers.empty())
>> > -        return NextSequenceNumber++;
>> > -      auto SequenceNumber = FreeSequenceNumbers.back();
>> > -      FreeSequenceNumbers.pop_back();
>> > -      return SequenceNumber;
>> > -    }
>> > -
>> > -    void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
>> > -      std::lock_guard<std::mutex> Lock(SeqNoLock);
>> > -      FreeSequenceNumbers.push_back(SequenceNumber);
>> > -    }
>> > -
>> > -  private:
>> > -    std::mutex SeqNoLock;
>> > -    SequenceNumberT NextSequenceNumber = 0;
>> > -    std::vector<SequenceNumberT> FreeSequenceNumbers;
>> > -  };
>> > +public:
>> >
>> > -  // Base class for results that haven't been returned from the other
>> end of the
>> > -  // RPC connection yet.
>> > -  class OutstandingResult {
>> > -  public:
>> > -    virtual ~OutstandingResult() {}
>> > -    virtual Error readResult(ChannelT &C) = 0;
>> > -    virtual void abandon() = 0;
>> > -  };
>> > +  SingleThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
>> > +      : BaseClass(C, LazyAutoNegotiation) {}
>> >
>> > -  // Outstanding results for a specific function.
>> > -  template <typename Func>
>> > -  class OutstandingResultImpl : public OutstandingResult {
>> > -  private:
>> > -  public:
>> > -    OutstandingResultImpl(std::promise<typename Func::PErrorReturn>
>> &&P)
>> > -        : P(std::move(P)) {}
>> > +  template <typename Func, typename HandlerT>
>> > +  void addHandler(HandlerT Handler) {
>> > +    return this->template addHandlerImpl<Func>(std::move(Handler),
>> > +                                               LaunchPolicy());
>> > +  }
>> >
>> > -    Error readResult(ChannelT &C) override { return
>> Func::readResult(C, P); }
>> > +  template <typename Func, typename ClassT, typename RetT, typename...
>> ArgTs>
>> > +  void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
>> > +    addHandler<Func>(
>> > +        detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object,
>> Method));
>> > +  }
>> >
>> > -    void abandon() override { Func::abandon(P); }
>> > +  /// Negotiate a function id for Func with the other end of the
>> channel.
>> > +  template <typename Func>
>> > +  Error negotiateFunction() {
>> > +    using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
>> >
>> > -  private:
>> > -    std::promise<typename Func::PErrorReturn> P;
>> > -  };
>> > +    if (auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype()))
>> {
>> > +      this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
>> > +      return Error::success();
>> > +    } else
>> > +      return RemoteIdOrErr.takeError();
>> > +  }
>> >
>> > -  // Create an outstanding result for the given function.
>> > +  /// Convenience method for negotiating multiple functions at once.
>> >   template <typename Func>
>> > -  std::unique_ptr<OutstandingResult>
>> > -  createOutstandingResult(std::promise<typename Func::PErrorReturn>
>> &&P) {
>> > -    return llvm::make_unique<OutstandingR
>> esultImpl<Func>>(std::move(P));
>> > +  Error negotiateFunctions() {
>> > +    return negotiateFunction<Func>();
>> >   }
>> >
>> > -  // Abandon all outstanding results.
>> > -  void abandonOutstandingResults() {
>> > -    for (auto &KV : OutstandingResults)
>> > -      KV.second->abandon();
>> > -    OutstandingResults.clear();
>> > -    SequenceNumberMgr.reset();
>> > +  /// Convenience method for negotiating multiple functions at once.
>> > +  template <typename Func1, typename Func2, typename... Funcs>
>> > +  Error negotiateFunctions() {
>> > +    if (auto Err = negotiateFunction<Func1>())
>> > +      return Err;
>> > +    return negotiateFunctions<Func2, Funcs...>();
>> >   }
>> >
>> > -  SequenceNumberManager SequenceNumberMgr;
>> > -  std::map<SequenceNumberT, std::unique_ptr<OutstandingResult>>
>> > -      OutstandingResults;
>> > +  template <typename Func, typename... ArgTs,
>> > +            typename AltRetT = typename Func::ReturnType>
>> > +  typename detail::ResultTraits<AltRetT>::ErrorReturnType
>> > +  callB(const ArgTs &... Args) {
>> > +    bool ReceivedResponse = false;
>> > +    using ResultType =
>> > +      typename detail::ResultTraits<AltRetT>::ErrorReturnType;
>> > +    auto Result = detail::ResultTraits<AltRetT>:
>> :createBlankErrorReturnValue();
>> > +
>> > +    // We have to 'Check' result (which we know is in a success state
>> at this
>> > +    // point) so that it can be overwritten in the async handler.
>> > +    (void)!!Result;
>> > +
>> > +    if (auto Err = this->template appendCallAsync<Func>(
>> > +           [&](ResultType R) {
>> > +             Result = std::move(R);
>> > +             ReceivedResponse = true;
>> > +             return Error::success();
>> > +           }, Args...)) {
>> > +      this->abandonPendingResponses();
>> > +      detail::ResultTraits<typename Func::ReturnType>::
>> > +        consumeAbandoned(std::move(Result));
>> > +      return std::move(Err);
>> > +    }
>> > +
>> > +    while (!ReceivedResponse) {
>> > +      if (auto Err = this->handleOne()) {
>> > +        this->abandonPendingResponses();
>> > +        detail::ResultTraits<typename Func::ReturnType>::
>> > +          consumeAbandoned(std::move(Result));
>> > +        return std::move(Err);
>> > +      }
>> > +    }
>> > +
>> > +    return Result;
>> > +  }
>> > +
>> > +  //using detail::RPCBase<ChannelT, FunctionIdT,
>> SequenceNumberT>::handleOne;
>> > +
>> > };
>> >
>> > -} // end namespace remote
>> > +} // end namespace rpc
>> > } // end namespace orc
>> > } // end namespace llvm
>> >
>> >
>> > Modified: llvm/trunk/lib/ExecutionEngine/Orc/CMakeLists.txt
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Execution
>> Engine/Orc/CMakeLists.txt?rev=286639&r1=286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/lib/ExecutionEngine/Orc/CMakeLists.txt (original)
>> > +++ llvm/trunk/lib/ExecutionEngine/Orc/CMakeLists.txt Fri Nov 11
>> 15:42:09 2016
>> > @@ -6,7 +6,6 @@ add_llvm_library(LLVMOrcJIT
>> >   OrcCBindings.cpp
>> >   OrcError.cpp
>> >   OrcMCJITReplacement.cpp
>> > -  OrcRemoteTargetRPCAPI.cpp
>> >
>> >   ADDITIONAL_HEADER_DIRS
>> >   ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
>> >
>> > Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Execution
>> Engine/Orc/OrcError.cpp?rev=286639&r1=286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp (original)
>> > +++ llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp Fri Nov 11
>> 15:42:09 2016
>> > @@ -43,6 +43,8 @@ public:
>> >       return "Unexpected RPC call";
>> >     case OrcErrorCode::UnexpectedRPCResponse:
>> >       return "Unexpected RPC response";
>> > +    case OrcErrorCode::UnknownRPCFunction:
>> > +      return "Unknown RPC function";
>> >     }
>> >     llvm_unreachable("Unhandled error code");
>> >   }
>> >
>> > Removed: llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Execution
>> Engine/Orc/OrcRemoteTargetRPCAPI.cpp?rev=286638&view=auto
>> > ============================================================
>> ==================
>> > --- llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp
>> (original)
>> > +++ llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp
>> (removed)
>> > @@ -1,53 +0,0 @@
>> > -//===------- OrcRemoteTargetRPCAPI.cpp - ORC Remote API utilities
>> ---------===//
>> > -//
>> > -//                     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/OrcRemoteTargetRPCAPI.h"
>> > -
>> > -namespace llvm {
>> > -namespace orc {
>> > -namespace remote {
>> > -
>> > -#define FUNCNAME(X) \
>> > -  case X ## Id: \
>> > -  return #X
>> > -
>> > -const char *OrcRemoteTargetRPCAPI::getJITFuncIdName(JITFuncId Id) {
>> > -  switch (Id) {
>> > -  case InvalidId:
>> > -    return "*** Invalid JITFuncId ***";
>> > -  FUNCNAME(CallIntVoid);
>> > -  FUNCNAME(CallMain);
>> > -  FUNCNAME(CallVoidVoid);
>> > -  FUNCNAME(CreateRemoteAllocator);
>> > -  FUNCNAME(CreateIndirectStubsOwner);
>> > -  FUNCNAME(DeregisterEHFrames);
>> > -  FUNCNAME(DestroyRemoteAllocator);
>> > -  FUNCNAME(DestroyIndirectStubsOwner);
>> > -  FUNCNAME(EmitIndirectStubs);
>> > -  FUNCNAME(EmitResolverBlock);
>> > -  FUNCNAME(EmitTrampolineBlock);
>> > -  FUNCNAME(GetSymbolAddress);
>> > -  FUNCNAME(GetRemoteInfo);
>> > -  FUNCNAME(ReadMem);
>> > -  FUNCNAME(RegisterEHFrames);
>> > -  FUNCNAME(ReserveMem);
>> > -  FUNCNAME(RequestCompile);
>> > -  FUNCNAME(SetProtections);
>> > -  FUNCNAME(TerminateSession);
>> > -  FUNCNAME(WriteMem);
>> > -  FUNCNAME(WritePtr);
>> > -  };
>> > -  return nullptr;
>> > -}
>> > -
>> > -#undef FUNCNAME
>> > -
>> > -} // end namespace remote
>> > -} // end namespace orc
>> > -} // end namespace llvm
>> >
>> > Modified: llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/Chi
>> ldTarget/ChildTarget.cpp?rev=286639&r1=286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp (original)
>> > +++ llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp Fri Nov 11
>> 15:42:09 2016
>> > @@ -53,23 +53,12 @@ int main(int argc, char *argv[]) {
>> >     RTDyldMemoryManager::deregisterEHFramesInProcess(Addr, Size);
>> >   };
>> >
>> > -  FDRPCChannel Channel(InFD, OutFD);
>> > -  typedef remote::OrcRemoteTargetServer<FDRPCChannel, HostOrcArch>
>> JITServer;
>> > +  FDRawChannel Channel(InFD, OutFD);
>> > +  typedef remote::OrcRemoteTargetServer<FDRawChannel, HostOrcArch>
>> JITServer;
>> >   JITServer Server(Channel, SymbolLookup, RegisterEHFrames,
>> DeregisterEHFrames);
>> >
>> > -  while (1) {
>> > -    uint32_t RawId;
>> > -    ExitOnErr(Server.startReceivingFunction(Channel, RawId));
>> > -    auto Id = static_cast<JITServer::JITFuncId>(RawId);
>> > -    switch (Id) {
>> > -    case JITServer::TerminateSessionId:
>> > -      ExitOnErr(Server.handleTerminateSession());
>> > -      return 0;
>> > -    default:
>> > -      ExitOnErr(Server.handleKnownFunction(Id));
>> > -      break;
>> > -    }
>> > -  }
>> > +  while (!Server.receivedTerminate())
>> > +    ExitOnErr(Server.handleOne());
>> >
>> >   close(InFD);
>> >   close(OutFD);
>> >
>> > Modified: llvm/trunk/tools/lli/RemoteJITUtils.h
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/Rem
>> oteJITUtils.h?rev=286639&r1=286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/tools/lli/RemoteJITUtils.h (original)
>> > +++ llvm/trunk/tools/lli/RemoteJITUtils.h Fri Nov 11 15:42:09 2016
>> > @@ -14,7 +14,7 @@
>> > #ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H
>> > #define LLVM_TOOLS_LLI_REMOTEJITUTILS_H
>> >
>> > -#include "llvm/ExecutionEngine/Orc/RPCByteChannel.h"
>> > +#include "llvm/ExecutionEngine/Orc/RawByteChannel.h"
>> > #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
>> > #include <mutex>
>> >
>> > @@ -25,9 +25,9 @@
>> > #endif
>> >
>> > /// RPC channel that reads from and writes from file descriptors.
>> > -class FDRPCChannel final : public llvm::orc::remote::RPCByteChannel {
>> > +class FDRawChannel final : public llvm::orc::rpc::RawByteChannel {
>> > public:
>> > -  FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
>> > +  FDRawChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
>> >
>> >   llvm::Error readBytes(char *Dst, unsigned Size) override {
>> >     assert(Dst && "Attempt to read into null.");
>> > @@ -72,11 +72,12 @@ private:
>> > };
>> >
>> > // launch the remote process (see lli.cpp) and return a channel to it.
>> > -std::unique_ptr<FDRPCChannel> launchRemote();
>> > +std::unique_ptr<FDRawChannel> launchRemote();
>> >
>> > namespace llvm {
>> >
>> > -// ForwardingMM - Adapter to connect MCJIT to Orc's Remote memory
>> manager.
>> > +// ForwardingMM - Adapter to connect MCJIT to Orc's Remote8
>> > +// memory manager.
>> > class ForwardingMemoryManager : public llvm::RTDyldMemoryManager {
>> > public:
>> >   void setMemMgr(std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr) {
>> >
>> > Modified: llvm/trunk/tools/lli/lli.cpp
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/lli
>> .cpp?rev=286639&r1=286638&r2=286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/tools/lli/lli.cpp (original)
>> > +++ llvm/trunk/tools/lli/lli.cpp Fri Nov 11 15:42:09 2016
>> > @@ -654,20 +654,20 @@ int main(int argc, char **argv, char * c
>> >     // MCJIT itself. FIXME.
>> >
>> >     // Lanch the remote process and get a channel to it.
>> > -    std::unique_ptr<FDRPCChannel> C = launchRemote();
>> > +    std::unique_ptr<FDRawChannel> C = launchRemote();
>> >     if (!C) {
>> >       errs() << "Failed to launch remote JIT.\n";
>> >       exit(1);
>> >     }
>> >
>> >     // Create a remote target client running over the channel.
>> > -    typedef orc::remote::OrcRemoteTargetClient<orc::remote::
>> RPCByteChannel>
>> > +    typedef orc::remote::OrcRemoteTargetCl
>> ient<orc::rpc::RawByteChannel>
>> >       MyRemote;
>> > -    MyRemote R = ExitOnErr(MyRemote::Create(*C));
>> > +    auto R = ExitOnErr(MyRemote::Create(*C));
>> >
>> >     // Create a remote memory manager.
>> >     std::unique_ptr<MyRemote::RCMemoryManager> RemoteMM;
>> > -    ExitOnErr(R.createRemoteMemoryManager(RemoteMM));
>> > +    ExitOnErr(R->createRemoteMemoryManager(RemoteMM));
>> >
>> >     // Forward MCJIT's memory manager calls to the remote memory
>> manager.
>> >     static_cast<ForwardingMemoryManager*>(RTDyldMM)->setMemMgr(
>> > @@ -678,7 +678,7 @@ int main(int argc, char **argv, char * c
>> >       orc::createLambdaResolver(
>> >         [](const std::string &Name) { return nullptr; },
>> >         [&](const std::string &Name) {
>> > -          if (auto Addr = ExitOnErr(R.getSymbolAddress(Name)))
>> > +          if (auto Addr = ExitOnErr(R->getSymbolAddress(Name)))
>> >           return JITSymbol(Addr, JITSymbolFlags::Exported);
>> >           return JITSymbol(nullptr);
>> >         }
>> > @@ -691,7 +691,7 @@ int main(int argc, char **argv, char * c
>> >     EE->finalizeObject();
>> >     DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x"
>> >                  << format("%llx", Entry) << "\n");
>> > -    Result = ExitOnErr(R.callIntVoid(Entry));
>> > +    Result = ExitOnErr(R->callIntVoid(Entry));
>> >
>> >     // Like static constructors, the remote target MCJIT support
>> doesn't handle
>> >     // this yet. It could. FIXME.
>> > @@ -702,13 +702,13 @@ int main(int argc, char **argv, char * c
>> >     EE.reset();
>> >
>> >     // Signal the remote target that we're done JITing.
>> > -    ExitOnErr(R.terminateSession());
>> > +    ExitOnErr(R->terminateSession());
>> >   }
>> >
>> >   return Result;
>> > }
>> >
>> > -std::unique_ptr<FDRPCChannel> launchRemote() {
>> > +std::unique_ptr<FDRawChannel> launchRemote() {
>> > #ifndef LLVM_ON_UNIX
>> >   llvm_unreachable("launchRemote not supported on non-Unix platforms");
>> > #else
>> > @@ -758,6 +758,6 @@ std::unique_ptr<FDRPCChannel> launchRemo
>> >   close(PipeFD[1][1]);
>> >
>> >   // Return an RPC channel connected to our end of the pipes.
>> > -  return llvm::make_unique<FDRPCChannel>(PipeFD[1][0], PipeFD[0][1]);
>> > +  return llvm::make_unique<FDRawChannel>(PipeFD[1][0], PipeFD[0][1]);
>> > #endif
>> > }
>> >
>> > Modified: llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
>> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Exe
>> cutionEngine/Orc/RPCUtilsTest.cpp?rev=286639&r1=286638&r2=
>> 286639&view=diff
>> > ============================================================
>> ==================
>> > --- llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
>> (original)
>> > +++ llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp Fri Nov
>> 11 15:42:09 2016
>> > @@ -7,7 +7,7 @@
>> > //
>> > //===-------------------------------------------------------
>> ---------------===//
>> >
>> > -#include "llvm/ExecutionEngine/Orc/RPCByteChannel.h"
>> > +#include "llvm/ExecutionEngine/Orc/RawByteChannel.h"
>> > #include "llvm/ExecutionEngine/Orc/RPCUtils.h"
>> > #include "gtest/gtest.h"
>> >
>> > @@ -15,7 +15,7 @@
>> >
>> > using namespace llvm;
>> > using namespace llvm::orc;
>> > -using namespace llvm::orc::remote;
>> > +using namespace llvm::orc::rpc;
>> >
>> > class Queue : public std::queue<char> {
>> > public:
>> > @@ -25,7 +25,7 @@ private:
>> >   std::mutex Lock;
>> > };
>> >
>> > -class QueueChannel : public RPCByteChannel {
>> > +class QueueChannel : public RawByteChannel {
>> > public:
>> >   QueueChannel(Queue &InQueue, Queue &OutQueue)
>> >       : InQueue(InQueue), OutQueue(OutQueue) {}
>> > @@ -61,126 +61,190 @@ private:
>> >   Queue &OutQueue;
>> > };
>> >
>> > -class DummyRPC : public testing::Test, public RPC<QueueChannel> {
>> > +class DummyRPCAPI {
>> > public:
>> > -  enum FuncId : uint32_t {
>> > -    VoidBoolId = RPCFunctionIdTraits<FuncId>::FirstValidId,
>> > -    IntIntId,
>> > -    AllTheTypesId
>> > +
>> > +  class VoidBool : public Function<VoidBool, void(bool)> {
>> > +  public:
>> > +    static const char* getName() { return "VoidBool"; }
>> > +  };
>> > +
>> > +  class IntInt : public Function<IntInt, int32_t(int32_t)> {
>> > +  public:
>> > +    static const char* getName() { return "IntInt"; }
>> >   };
>> >
>> > -  typedef Function<VoidBoolId, void(bool)> VoidBool;
>> > -  typedef Function<IntIntId, int32_t(int32_t)> IntInt;
>> > -  typedef Function<AllTheTypesId,
>> > -                   void(int8_t, uint8_t, int16_t, uint16_t, int32_t,
>> uint32_t,
>> > -                        int64_t, uint64_t, bool, std::string,
>> std::vector<int>)>
>> > -      AllTheTypes;
>> > +  class AllTheTypes
>> > +    : public Function<AllTheTypes,
>> > +                      void(int8_t, uint8_t, int16_t, uint16_t, int32_t,
>> > +                           uint32_t, int64_t, uint64_t, bool,
>> std::string,
>> > +                           std::vector<int>)> {
>> > +  public:
>> > +    static const char* getName() { return "AllTheTypes"; }
>> > +  };
>> > +};
>> > +
>> > +class DummyRPCEndpoint : public DummyRPCAPI,
>> > +                         public SingleThreadedRPC<QueueChannel> {
>> > +public:
>> > +  DummyRPCEndpoint(Queue &Q1, Queue &Q2)
>> > +      : SingleThreadedRPC(C, true), C(Q1, Q2) {}
>> > +private:
>> > +  QueueChannel C;
>> > };
>> >
>> > -TEST_F(DummyRPC, TestAsyncVoidBool) {
>> > +TEST(DummyRPC, TestAsyncVoidBool) {
>> >   Queue Q1, Q2;
>> > -  QueueChannel C1(Q1, Q2);
>> > -  QueueChannel C2(Q2, Q1);
>> > +  DummyRPCEndpoint Client(Q1, Q2);
>> > +  DummyRPCEndpoint Server(Q2, Q1);
>> > +
>> > +  std::thread ServerThread([&]() {
>> > +      Server.addHandler<DummyRPCAPI::VoidBool>(
>> > +          [](bool B) {
>> > +            EXPECT_EQ(B, true)
>> > +              << "Server void(bool) received unexpected result";
>> > +          });
>> > +
>> > +      {
>> > +        // Poke the server to handle the negotiate call.
>> > +        auto Err = Server.handleOne();
>> > +        EXPECT_FALSE(!!Err) << "Server failed to handle call to
>> negotiate";
>> > +      }
>> >
>> > -  // Make an async call.
>> > -  auto ResOrErr = callNBWithSeq<VoidBool>(C1, true);
>> > -  EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
>> > +      {
>> > +        // Poke the server to handle the VoidBool call.
>> > +        auto Err = Server.handleOne();
>> > +        EXPECT_FALSE(!!Err) << "Server failed to handle call to
>> void(bool)";
>> > +      }
>> > +  });
>> >
>> >   {
>> > -    // Expect a call to Proc1.
>> > -    auto EC = expect<VoidBool>(C2, [&](bool &B) {
>> > -      EXPECT_EQ(B, true) << "Bool serialization broken";
>> > -      return Error::success();
>> > -    });
>> > -    EXPECT_FALSE(EC) << "Simple expect over queue failed";
>> > +    // Make an async call.
>> > +    auto Err = Client.callAsync<DummyRPCAPI::VoidBool>(
>> > +        [](Error Err) {
>> > +          EXPECT_FALSE(!!Err) << "Async void(bool) response handler
>> failed";
>> > +          return Error::success();
>> > +        }, true);
>> > +    EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)";
>> >   }
>> >
>> >   {
>> > -    // Wait for the result.
>> > -    auto EC = waitForResult(C1, ResOrErr->second, handleNone);
>> > -    EXPECT_FALSE(EC) << "Could not read result.";
>> > +    // Poke the client to process the result of the void(bool) call.
>> > +    auto Err = Client.handleOne();
>> > +    EXPECT_FALSE(!!Err) << "Client failed to handle response from
>> void(bool)";
>> >   }
>> >
>> > -  // Verify that the function returned ok.
>> > -  auto Err = ResOrErr->first.get();
>> > -  EXPECT_FALSE(!!Err) << "Remote void function failed to execute.";
>> > +  ServerThread.join();
>> > }
>> >
>> > -TEST_F(DummyRPC, TestAsyncIntInt) {
>> > +TEST(DummyRPC, TestAsyncIntInt) {
>> >   Queue Q1, Q2;
>> > -  QueueChannel C1(Q1, Q2);
>> > -  QueueChannel C2(Q2, Q1);
>> > +  DummyRPCEndpoint Client(Q1, Q2);
>> > +  DummyRPCEndpoint Server(Q2, Q1);
>> >
>> > -  // Make an async call.
>> > -  auto ResOrErr = callNBWithSeq<IntInt>(C1, 21);
>> > -  EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
>> > +  std::thread ServerThread([&]() {
>> > +      Server.addHandler<DummyRPCAPI::IntInt>(
>> > +          [](int X) -> int {
>> > +            EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected
>> result";
>> > +            return 2 * X;
>> > +          });
>> > +
>> > +      {
>> > +        // Poke the server to handle the negotiate call.
>> > +        auto Err = Server.handleOne();
>> > +        EXPECT_FALSE(!!Err) << "Server failed to handle call to
>> negotiate";
>> > +      }
>> >
>> > -  {
>> > -    // Expect a call to Proc1.
>> > -    auto EC = expect<IntInt>(C2, [&](int32_t I) -> Expected<int32_t> {
>> > -      EXPECT_EQ(I, 21) << "Bool serialization broken";
>> > -      return 2 * I;
>> > +      {
>> > +        // Poke the server to handle the int(int) call.
>> > +        auto Err = Server.handleOne();
>> > +        EXPECT_FALSE(!!Err) << "Server failed to handle call to
>> int(int)";
>> > +      }
>> >     });
>> > -    EXPECT_FALSE(EC) << "Simple expect over queue failed";
>> > +
>> > +  {
>> > +    auto Err = Client.callAsync<DummyRPCAPI::IntInt>(
>> > +        [](Expected<int> Result) {
>> > +          EXPECT_TRUE(!!Result) << "Async int(int) response handler
>> failed";
>> > +          EXPECT_EQ(*Result, 42)
>> > +            << "Async int(int) response handler received incorrect
>> result";
>> > +          return Error::success();
>> > +        }, 21);
>> > +    EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)";
>> >   }
>> >
>> >   {
>> > -    // Wait for the result.
>> > -    auto EC = waitForResult(C1, ResOrErr->second, handleNone);
>> > -    EXPECT_FALSE(EC) << "Could not read result.";
>> > +    // Poke the client to process the result.
>> > +    auto Err = Client.handleOne();
>> > +    EXPECT_FALSE(!!Err) << "Client failed to handle response from
>> void(bool)";
>> >   }
>> >
>> > -  // Verify that the function returned ok.
>> > -  auto Val = ResOrErr->first.get();
>> > -  EXPECT_TRUE(!!Val) << "Remote int function failed to execute.";
>> > -  EXPECT_EQ(*Val, 42) << "Remote int function return wrong value.";
>> > +  ServerThread.join();
>> > }
>> >
>> > -TEST_F(DummyRPC, TestSerialization) {
>> > +TEST(DummyRPC, TestSerialization) {
>> >   Queue Q1, Q2;
>> > -  QueueChannel C1(Q1, Q2);
>> > -  QueueChannel C2(Q2, Q1);
>> > +  DummyRPCEndpoint Client(Q1, Q2);
>> > +  DummyRPCEndpoint Server(Q2, Q1);
>> >
>> > -  // Make a call to Proc1.
>> > -  std::vector<int> v({42, 7});
>> > -  auto ResOrErr = callNBWithSeq<AllTheTypes>(
>> > -      C1, -101, 250, -10000, 10000, -1000000000, 1000000000,
>> -10000000000,
>> > -      10000000000, true, "foo", v);
>> > -  EXPECT_TRUE(!!ResOrErr) << "Big (serialization test) call over queue
>> failed";
>> > -
>> > -  {
>> > -    // Expect a call to Proc1.
>> > -    auto EC = expect<AllTheTypes>(
>> > -        C2, [&](int8_t &s8, uint8_t &u8, int16_t &s16, uint16_t &u16,
>> > -                int32_t &s32, uint32_t &u32, int64_t &s64, uint64_t
>> &u64,
>> > -                bool &b, std::string &s, std::vector<int> &v) {
>> > -
>> > -          EXPECT_EQ(s8, -101) << "int8_t serialization broken";
>> > -          EXPECT_EQ(u8, 250) << "uint8_t serialization broken";
>> > -          EXPECT_EQ(s16, -10000) << "int16_t serialization broken";
>> > -          EXPECT_EQ(u16, 10000) << "uint16_t serialization broken";
>> > -          EXPECT_EQ(s32, -1000000000) << "int32_t serialization
>> broken";
>> > -          EXPECT_EQ(u32, 1000000000ULL) << "uint32_t serialization
>> broken";
>> > -          EXPECT_EQ(s64, -10000000000) << "int64_t serialization
>> broken";
>> > -          EXPECT_EQ(u64, 10000000000ULL) << "uint64_t serialization
>> broken";
>> > -          EXPECT_EQ(b, true) << "bool serialization broken";
>> > -          EXPECT_EQ(s, "foo") << "std::string serialization broken";
>> > -          EXPECT_EQ(v, std::vector<int>({42, 7}))
>> > +  std::thread ServerThread([&]() {
>> > +      Server.addHandler<DummyRPCAPI::AllTheTypes>(
>> > +          [&](int8_t S8, uint8_t U8, int16_t S16, uint16_t U16,
>> > +              int32_t S32, uint32_t U32, int64_t S64, uint64_t U64,
>> > +              bool B, std::string S, std::vector<int> V) {
>> > +
>> > +            EXPECT_EQ(S8, -101) << "int8_t serialization broken";
>> > +            EXPECT_EQ(U8, 250) << "uint8_t serialization broken";
>> > +            EXPECT_EQ(S16, -10000) << "int16_t serialization broken";
>> > +            EXPECT_EQ(U16, 10000) << "uint16_t serialization broken";
>> > +            EXPECT_EQ(S32, -1000000000) << "int32_t serialization
>> broken";
>> > +            EXPECT_EQ(U32, 1000000000ULL) << "uint32_t serialization
>> broken";
>> > +            EXPECT_EQ(S64, -10000000000) << "int64_t serialization
>> broken";
>> > +            EXPECT_EQ(U64, 10000000000ULL) << "uint64_t serialization
>> broken";
>> > +            EXPECT_EQ(B, true) << "bool serialization broken";
>> > +            EXPECT_EQ(S, "foo") << "std::string serialization broken";
>> > +            EXPECT_EQ(V, std::vector<int>({42, 7}))
>> >               << "std::vector serialization broken";
>> > +            return Error::success();
>> > +          });
>> > +
>> > +      {
>> > +        // Poke the server to handle the negotiate call.
>> > +        auto Err = Server.handleOne();
>> > +        EXPECT_FALSE(!!Err) << "Server failed to handle call to
>> negotiate";
>> > +      }
>> > +
>> > +      {
>> > +        // Poke the server to handle the AllTheTypes call.
>> > +        auto Err = Server.handleOne();
>> > +        EXPECT_FALSE(!!Err) << "Server failed to handle call to
>> void(bool)";
>> > +      }
>> > +    });
>> > +
>> > +
>> > +  {
>> > +    // Make an async call.
>> > +    std::vector<int> v({42, 7});
>> > +    auto Err = Client.callAsync<DummyRPCAPI::AllTheTypes>(
>> > +        [](Error Err) {
>> > +          EXPECT_FALSE(!!Err) << "Async AllTheTypes response handler
>> failed";
>> >           return Error::success();
>> > -        });
>> > -    EXPECT_FALSE(EC) << "Big (serialization test) call over queue
>> failed";
>> > +        },
>> > +        static_cast<int8_t>(-101), static_cast<uint8_t>(250),
>> > +        static_cast<int16_t>(-10000), static_cast<uint16_t>(10000),
>> > +        static_cast<int32_t>(-1000000000),
>> static_cast<uint32_t>(1000000000),
>> > +        static_cast<int64_t>(-10000000000),
>> static_cast<uint64_t>(10000000000),
>> > +        true, std::string("foo"), v);
>> > +    EXPECT_FALSE(!!Err) << "Client.callAsync failed for AllTheTypes";
>> >   }
>> >
>> >   {
>> > -    // Wait for the result.
>> > -    auto EC = waitForResult(C1, ResOrErr->second, handleNone);
>> > -    EXPECT_FALSE(EC) << "Could not read result.";
>> > +    // Poke the client to process the result of the AllTheTypes call.
>> > +    auto Err = Client.handleOne();
>> > +    EXPECT_FALSE(!!Err) << "Client failed to handle response from
>> AllTheTypes";
>> >   }
>> >
>> > -  // Verify that the function returned ok.
>> > -  auto Err = ResOrErr->first.get();
>> > -  EXPECT_FALSE(!!Err) << "Remote void function failed to execute.";
>> > +  ServerThread.join();
>> > }
>> >
>> > // Test the synchronous call API.
>> >
>> >
>> > _______________________________________________
>> > llvm-commits mailing list
>> > llvm-commits at lists.llvm.org
>> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20161114/8120dbad/attachment-0001.html>


More information about the llvm-commits mailing list