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