<div dir="ltr">Hi Dave,<div><br></div><div>Thanks for spotting that. I meant to clang-format this whole thing before I committed but forgot. Nico has reverted it to deal with MSVC breakage - I'll format before re-committing.<div><br></div><div>- Lang.</div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Apr 18, 2016 at 9:13 AM, David Blaikie <span dir="ltr"><<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Apr 17, 2016 at 6:06 PM, Lang Hames via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: lhames<br>
Date: Sun Apr 17 20:06:49 2016<br>
New Revision: 266581<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=266581&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=266581&view=rev</a><br>
Log:<br>
[ORC] Generalize the ORC RPC utils to support RPC function return values and<br>
asynchronous call/handle. Also updates the ORC remote JIT API to use the new<br>
scheme.<br>
<br>
The previous version of the RPC tools only supported void functions, and<br>
required the user to manually call a paired function to return results. This<br>
patch replaces the Procedure typedef (which only supported void functions) with<br>
the Function typedef which supports return values, e.g.:<br>
<br>
  Function<FooId, int32_t(std::string)> Foo;<br>
<br>
The RPC primitives and channel operations are also expanded. RPC channels must<br>
support four new operations: startSendMessage, endSendMessage,<br>
startRecieveMessage and endRecieveMessage, to handle channel locking. In<br>
addition, serialization support for tuples to RPCChannels is added to enable<br>
multiple return values.<br>
<br>
The RPC primitives are expanded from callAppend, call, expect and handle, to:<br>
<br>
appendCallAsync - Make an asynchronous call to the given function.<br>
<br>
callAsync - The same as appendCallAsync, but calls send on the channel when<br>
            done.<br>
<br>
callSTHandling - Blocking call for single-threaded code. Wraps a call to<br>
                 callAsync then waits on the result, using a user-supplied<br>
                 handler to handle any callbacks from the remote.<br>
<br>
callST - The same as callSTHandling, except that it doesn't handle<br>
         callbacks - it expects the result to be the first return.<br>
<br>
expect and handle - as before.<br>
<br>
handleResponse - Handle a response from the remote.<br>
<br>
waitForResult - Wait for the response with the given sequence number to arrive.<br>
<br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCChannel.h<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h<br>
    llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp<br>
    llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp<br>
    llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp<br>
    llvm/trunk/tools/lli/RemoteJITUtils.h<br>
    llvm/trunk/tools/lli/lli.cpp<br>
    llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcError.h Sun Apr 17 20:06:49 2016<br>
@@ -26,7 +26,8 @@ enum class OrcErrorCode : int {<br>
   RemoteMProtectAddrUnrecognized,<br>
   RemoteIndirectStubsOwnerDoesNotExist,<br>
   RemoteIndirectStubsOwnerIdAlreadyInUse,<br>
-  UnexpectedRPCCall<br>
+  UnexpectedRPCCall,<br>
+  UnexpectedRPCResponse,<br>
 };<br>
<br>
 std::error_code orcError(OrcErrorCode ErrCode);<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h Sun Apr 17 20:06:49 2016<br>
@@ -36,6 +36,7 @@ namespace remote {<br>
 template <typename ChannelT><br>
 class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {<br>
 public:<br>
+<br>
   /// Remote memory manager.<br>
   class RCMemoryManager : public RuntimeDyld::MemoryManager {<br>
   public:<br>
@@ -105,11 +106,13 @@ public:<br>
       DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");<br>
<br>
       if (CodeSize != 0) {<br>
-        std::error_code EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr,<br>
-                                               Id, CodeSize, CodeAlign);<br>
-        // FIXME; Add error to poll.<br>
-        assert(!EC && "Failed reserving remote memory.");<br>
-        (void)EC;<br>
+       if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign))<br>
+         Unmapped.back().RemoteCodeAddr = *AddrOrErr;<br>
+       else {<br>
+         // FIXME; Add error to poll.<br>
+         assert(!AddrOrErr.getError() && "Failed reserving remote memory.");<br>
+       }<br>
+<br>
         DEBUG(dbgs() << "  code: "<br>
                      << format("0x%016x", Unmapped.back().RemoteCodeAddr)<br>
                      << " (" << CodeSize << " bytes, alignment " << CodeAlign<br>
@@ -117,11 +120,13 @@ public:<br>
       }<br>
<br>
       if (RODataSize != 0) {<br>
-        std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr,<br>
-                                               Id, RODataSize, RODataAlign);<br>
-        // FIXME; Add error to poll.<br>
-        assert(!EC && "Failed reserving remote memory.");<br>
-        (void)EC;<br>
+        if (auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign))<br>
+         Unmapped.back().RemoteRODataAddr = *AddrOrErr;<br>
+       else {<br>
+         // FIXME; Add error to poll.<br>
+         assert(!AddrOrErr.getError() && "Failed reserving remote memory.");<br>
+       }<br>
+<br>
         DEBUG(dbgs() << "  ro-data: "<br>
                      << format("0x%016x", Unmapped.back().RemoteRODataAddr)<br>
                      << " (" << RODataSize << " bytes, alignment "<br>
@@ -129,11 +134,13 @@ public:<br>
       }<br>
<br>
       if (RWDataSize != 0) {<br>
-        std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr,<br>
-                                               Id, RWDataSize, RWDataAlign);<br>
-        // FIXME; Add error to poll.<br>
-        assert(!EC && "Failed reserving remote memory.");<br>
-        (void)EC;<br>
+        if (auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign))<br>
+         Unmapped.back().RemoteRWDataAddr = *AddrOrErr;<br>
+       else {<br>
+         // FIXME; Add error to poll.<br>
+         assert(!AddrOrErr.getError() && "Failed reserving remote memory.");<br>
+        }<br>
+<br>
         DEBUG(dbgs() << "  rw-data: "<br>
                      << format("0x%016x", Unmapped.back().RemoteRWDataAddr)<br>
                      << " (" << RWDataSize << " bytes, alignment "<br>
@@ -431,8 +438,10 @@ public:<br>
       TargetAddress PtrBase;<br>
       unsigned NumStubsEmitted;<br>
<br>
-      Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id,<br>
-                               NewStubsRequired);<br>
+      if (auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired))<br>
+       std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;<br>
+      else<br>
+       return StubInfoOrErr.getError();<br>
<br>
       unsigned NewBlockId = RemoteIndirectStubsInfos.size();<br>
       RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});<br>
@@ -484,8 +493,12 @@ public:<br>
     void grow() override {<br>
       TargetAddress BlockAddr = 0;<br>
       uint32_t NumTrampolines = 0;<br>
-      auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines);<br>
-      assert(!EC && "Failed to create trampolines");<br>
+      if (auto TrampolineInfoOrErr = Remote.emitTrampolineBlock())<br>
+       std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;<br>
+      else {<br>
+       // FIXME: Return error.<br>
+       llvm_unreachable("Failed to create trampolines");<br>
+      }<br>
<br>
       uint32_t TrampolineSize = Remote.getTrampolineSize();<br>
       for (unsigned I = 0; I < NumTrampolines; ++I)<br>
@@ -503,53 +516,33 @@ public:<br>
     OrcRemoteTargetClient H(Channel, EC);<br>
     if (EC)<br>
       return EC;<br>
-    return H;<br>
+    return ErrorOr<OrcRemoteTargetClient>(std::move(H));<br>
   }<br>
<br>
   /// Call the int(void) function at the given address in the target and return<br>
   /// its result.<br>
-  std::error_code callIntVoid(int &Result, TargetAddress Addr) {<br>
+  ErrorOr<int> callIntVoid(TargetAddress Addr) {<br>
     DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");<br>
<br>
-    if (auto EC = call<CallIntVoid>(Channel, Addr))<br>
-      return EC;<br>
-<br>
-    unsigned NextProcId;<br>
-    if (auto EC = listenForCompileRequests(NextProcId))<br>
-      return EC;<br>
-<br>
-    if (NextProcId != CallIntVoidResponseId)<br>
-      return orcError(OrcErrorCode::UnexpectedRPCCall);<br>
-<br>
-    return handle<CallIntVoidResponse>(Channel, [&](int R) {<br>
-      Result = R;<br>
-      DEBUG(dbgs() << "Result: " << R << "\n");<br>
-      return std::error_code();<br>
-    });<br>
+    auto Listen =<br>
+      [&](RPCChannel &C, uint32_t Id) {<br>
+        return listenForCompileRequests(C, Id);<br>
+      };<br>
+    return callSTHandling<CallIntVoid>(Channel, Listen, Addr);<br>
   }<br>
<br>
   /// Call the int(int, char*[]) function at the given address in the target and<br>
   /// return its result.<br>
-  std::error_code callMain(int &Result, TargetAddress Addr,<br>
-                           const std::vector<std::string> &Args) {<br>
+  ErrorOr<int> callMain(TargetAddress Addr,<br>
+                       const std::vector<std::string> &Args) {<br>
     DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)<br>
                  << "\n");<br>
<br>
-    if (auto EC = call<CallMain>(Channel, Addr, Args))<br>
-      return EC;<br>
-<br>
-    unsigned NextProcId;<br>
-    if (auto EC = listenForCompileRequests(NextProcId))<br>
-      return EC;<br>
-<br>
-    if (NextProcId != CallMainResponseId)<br>
-      return orcError(OrcErrorCode::UnexpectedRPCCall);<br>
-<br>
-    return handle<CallMainResponse>(Channel, [&](int R) {<br>
-      Result = R;<br>
-      DEBUG(dbgs() << "Result: " << R << "\n");<br>
-      return std::error_code();<br>
-    });<br>
+    auto Listen =<br>
+      [&](RPCChannel &C, uint32_t Id) {<br>
+        return listenForCompileRequests(C, Id);<br>
+      };<br>
+    return callSTHandling<CallMain>(Channel, Listen, Addr, Args);<br>
   }<br>
<br>
   /// Call the void() function at the given address in the target and wait for<br>
@@ -558,17 +551,11 @@ public:<br>
     DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)<br>
                  << "\n");<br>
<br>
-    if (auto EC = call<CallVoidVoid>(Channel, Addr))<br>
-      return EC;<br>
-<br>
-    unsigned NextProcId;<br>
-    if (auto EC = listenForCompileRequests(NextProcId))<br>
-      return EC;<br>
-<br>
-    if (NextProcId != CallVoidVoidResponseId)<br>
-      return orcError(OrcErrorCode::UnexpectedRPCCall);<br>
-<br>
-    return handle<CallVoidVoidResponse>(Channel, doNothing);<br>
+    auto Listen =<br>
+      [&](RPCChannel &C, JITFuncId Id) {<br>
+        return listenForCompileRequests(C, Id);<br>
+      };<br>
+    return callSTHandling<CallVoidVoid>(Channel, Listen, Addr);<br>
   }<br>
<br>
   /// Create an RCMemoryManager which will allocate its memory on the remote<br>
@@ -578,7 +565,7 @@ public:<br>
     assert(!MM && "MemoryManager should be null before creation.");<br>
<br>
     auto Id = AllocatorIds.getNext();<br>
-    if (auto EC = call<CreateRemoteAllocator>(Channel, Id))<br>
+    if (auto EC = callST<CreateRemoteAllocator>(Channel, Id))<br>
       return EC;<br>
     MM = llvm::make_unique<RCMemoryManager>(*this, Id);<br>
     return std::error_code();<br>
@@ -590,7 +577,7 @@ public:<br>
   createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {<br>
     assert(!I && "Indirect stubs manager should be null before creation.");<br>
     auto Id = IndirectStubOwnerIds.getNext();<br>
-    if (auto EC = call<CreateIndirectStubsOwner>(Channel, Id))<br>
+    if (auto EC = callST<CreateIndirectStubsOwner>(Channel, Id))<br>
       return EC;<br>
     I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);<br>
     return std::error_code();<br>
@@ -599,45 +586,39 @@ public:<br>
   /// Search for symbols in the remote process. Note: This should be used by<br>
   /// symbol resolvers *after* they've searched the local symbol table in the<br>
   /// JIT stack.<br>
-  std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) {<br>
+  ErrorOr<TargetAddress> getSymbolAddress(StringRef Name) {<br>
     // Check for an 'out-of-band' error, e.g. from an MM destructor.<br>
     if (ExistingError)<br>
       return ExistingError;<br>
<br>
-    // Request remote symbol address.<br>
-    if (auto EC = call<GetSymbolAddress>(Channel, Name))<br>
-      return EC;<br>
-<br>
-    return expect<GetSymbolAddressResponse>(Channel, [&](TargetAddress &A) {<br>
-      Addr = A;<br>
-      DEBUG(dbgs() << "Remote address lookup " << Name << " = "<br>
-                   << format("0x%016x", Addr) << "\n");<br>
-      return std::error_code();<br>
-    });<br>
+    return callST<GetSymbolAddress>(Channel, Name);<br>
   }<br>
<br>
   /// Get the triple for the remote target.<br>
   const std::string &getTargetTriple() const { return RemoteTargetTriple; }<br>
<br>
-  std::error_code terminateSession() { return call<TerminateSession>(Channel); }<br>
+  std::error_code terminateSession() {<br>
+    return callST<TerminateSession>(Channel);<br>
+  }<br>
<br>
 private:<br>
   OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC)<br>
       : Channel(Channel) {<br>
-    if ((EC = call<GetRemoteInfo>(Channel)))<br>
-      return;<br>
-<br>
-    EC = expect<GetRemoteInfoResponse>(<br>
-        Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize,<br>
-                          RemoteTrampolineSize, RemoteIndirectStubSize));<br>
+    if (auto RIOrErr = callST<GetRemoteInfo>(Channel)) {<br>
+      std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,<br>
+              RemoteTrampolineSize, RemoteIndirectStubSize) =<br>
+       *RIOrErr;<br>
+      EC = std::error_code();<br>
+    } else<br>
+      EC = RIOrErr.getError();<br>
   }<br>
<br>
   std::error_code deregisterEHFrames(TargetAddress Addr, uint32_t Size) {<br>
-    return call<RegisterEHFrames>(Channel, Addr, Size);<br>
+    return callST<RegisterEHFrames>(Channel, Addr, Size);<br>
   }<br>
<br>
   void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {<br>
-    if (auto EC = call<DestroyRemoteAllocator>(Channel, Id)) {<br>
+    if (auto EC = callST<DestroyRemoteAllocator>(Channel, 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>
@@ -647,19 +628,13 @@ private:<br>
<br>
   std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {<br>
     IndirectStubOwnerIds.release(Id);<br>
-    return call<DestroyIndirectStubsOwner>(Channel, Id);<br>
+    return callST<DestroyIndirectStubsOwner>(Channel, Id);<br>
   }<br>
<br>
-  std::error_code emitIndirectStubs(TargetAddress &StubBase,<br>
-                                    TargetAddress &PtrBase,<br>
-                                    uint32_t &NumStubsEmitted,<br>
-                                    ResourceIdMgr::ResourceId Id,<br>
-                                    uint32_t NumStubsRequired) {<br>
-    if (auto EC = call<EmitIndirectStubs>(Channel, Id, NumStubsRequired))<br>
-      return EC;<br>
-<br>
-    return expect<EmitIndirectStubsResponse>(<br>
-        Channel, readArgs(StubBase, PtrBase, NumStubsEmitted));<br>
+  ErrorOr<std::tuple<TargetAddress, TargetAddress, uint32_t>><br>
+  emitIndirectStubs(ResourceIdMgr::ResourceId Id,<br>
+                   uint32_t NumStubsRequired) {<br>
+    return callST<EmitIndirectStubs>(Channel, Id, NumStubsRequired);<br>
   }<br>
<br>
   std::error_code emitResolverBlock() {<br>
@@ -667,24 +642,16 @@ private:<br>
     if (ExistingError)<br>
       return ExistingError;<br>
<br>
-    return call<EmitResolverBlock>(Channel);<br>
+    return callST<EmitResolverBlock>(Channel);<br>
   }<br>
<br>
-  std::error_code emitTrampolineBlock(TargetAddress &BlockAddr,<br>
-                                      uint32_t &NumTrampolines) {<br>
+  ErrorOr<std::tuple<TargetAddress, uint32_t>><br>
+  emitTrampolineBlock() {<br>
     // Check for an 'out-of-band' error, e.g. from an MM destructor.<br>
     if (ExistingError)<br>
       return ExistingError;<br>
<br>
-    if (auto EC = call<EmitTrampolineBlock>(Channel))<br>
-      return EC;<br>
-<br>
-    return expect<EmitTrampolineBlockResponse>(<br>
-        Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) {<br>
-          BlockAddr = BAddr;<br>
-          NumTrampolines = NTrampolines;<br>
-          return std::error_code();<br>
-        });<br>
+    return callST<EmitTrampolineBlock>(Channel);<br>
   }<br>
<br>
   uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }<br>
@@ -693,67 +660,46 @@ private:<br>
<br>
   uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }<br>
<br>
-  std::error_code listenForCompileRequests(uint32_t &NextId) {<br>
+  std::error_code listenForCompileRequests(RPCChannel &C, uint32_t &Id) {<br>
     // Check for an 'out-of-band' error, e.g. from an MM destructor.<br>
     if (ExistingError)<br>
       return ExistingError;<br>
<br>
-    if (auto EC = getNextProcId(Channel, NextId))<br>
-      return EC;<br>
-<br>
-    while (NextId == RequestCompileId) {<br>
-      TargetAddress TrampolineAddr = 0;<br>
-      if (auto EC = handle<RequestCompile>(Channel, readArgs(TrampolineAddr)))<br>
-        return EC;<br>
-<br>
-      TargetAddress ImplAddr = CompileCallback(TrampolineAddr);<br>
-      if (auto EC = call<RequestCompileResponse>(Channel, ImplAddr))<br>
-        return EC;<br>
-<br>
-      if (auto EC = getNextProcId(Channel, NextId))<br>
+    if (Id == RequestCompileId) {<br>
+      if (auto EC = handle<RequestCompile>(C, CompileCallback))<br>
         return EC;<br>
+      return std::error_code();<br>
     }<br>
-<br>
-    return std::error_code();<br>
+    // else<br>
+    return orcError(OrcErrorCode::UnexpectedRPCCall);<br>
   }<br>
<br>
-  std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) {<br>
+  ErrorOr<std::vector<char>> readMem(char *Dst, TargetAddress Src, uint64_t Size) {<br>
     // Check for an 'out-of-band' error, e.g. from an MM destructor.<br>
     if (ExistingError)<br>
       return ExistingError;<br>
<br>
-    if (auto EC = call<ReadMem>(Channel, Src, Size))<br>
-      return EC;<br>
-<br>
-    if (auto EC = expect<ReadMemResponse>(<br>
-            Channel, [&]() { return Channel.readBytes(Dst, Size); }))<br>
-      return EC;<br>
-<br>
-    return std::error_code();<br>
+    return callST<ReadMem>(Channel, Src, Size);<br>
   }<br>
<br>
   std::error_code registerEHFrames(TargetAddress &RAddr, uint32_t Size) {<br>
-    return call<RegisterEHFrames>(Channel, RAddr, Size);<br>
+    return callST<RegisterEHFrames>(Channel, RAddr, Size);<br>
   }<br>
<br>
-  std::error_code reserveMem(TargetAddress &RemoteAddr,<br>
-                             ResourceIdMgr::ResourceId Id, uint64_t Size,<br>
-                             uint32_t Align) {<br>
+  ErrorOr<TargetAddress> reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,<br>
+                                   uint32_t Align) {<br>
<br>
     // Check for an 'out-of-band' error, e.g. from an MM destructor.<br>
     if (ExistingError)<br>
       return ExistingError;<br>
<br>
-    if (std::error_code EC = call<ReserveMem>(Channel, Id, Size, Align))<br>
-      return EC;<br>
-<br>
-    return expect<ReserveMemResponse>(Channel, readArgs(RemoteAddr));<br>
+    return callST<ReserveMem>(Channel, Id, Size, Align);<br>
   }<br>
<br>
   std::error_code setProtections(ResourceIdMgr::ResourceId Id,<br>
                                  TargetAddress RemoteSegAddr,<br>
                                  unsigned ProtFlags) {<br>
-    return call<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);<br>
+    return callST<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);<br>
   }<br>
<br>
   std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {<br>
@@ -761,15 +707,7 @@ private:<br>
     if (ExistingError)<br>
       return ExistingError;<br>
<br>
-    // Make the send call.<br>
-    if (auto EC = call<WriteMem>(Channel, Addr, Size))<br>
-      return EC;<br>
-<br>
-    // Follow this up with the section contents.<br>
-    if (auto EC = Channel.appendBytes(Src, Size))<br>
-      return EC;<br>
-<br>
-    return Channel.send();<br>
+    return callST<WriteMem>(Channel, DirectBufferWriter(Src, Addr, Size));<br>
   }<br>
<br>
   std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) {<br>
@@ -777,7 +715,7 @@ private:<br>
     if (ExistingError)<br>
       return ExistingError;<br>
<br>
-    return call<WritePtr>(Channel, Addr, PtrVal);<br>
+    return callST<WritePtr>(Channel, Addr, PtrVal);<br>
   }<br>
<br>
   static std::error_code doNothing() { return std::error_code(); }<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h Sun Apr 17 20:06:49 2016<br>
@@ -24,8 +24,48 @@ namespace llvm {<br>
 namespace orc {<br>
 namespace remote {<br>
<br>
+class DirectBufferWriter {<br>
+public:<br>
+  DirectBufferWriter() = default;<br>
+  DirectBufferWriter(const char *Src, TargetAddress Dst, uint64_t Size)<br>
+    : Src(Src), Dst(Dst), Size(Size) {}<br>
+<br>
+  const char *getSrc() const { return Src; }<br>
+  TargetAddress getDst() const { return Dst; }<br>
+  uint64_t getSize() const { return Size; }<br>
+private:<br>
+  const char *Src;<br>
+  TargetAddress Dst;<br>
+  uint64_t Size;<br>
+};<br>
+<br>
+inline std::error_code serialize(RPCChannel &C,<br>
+                                const DirectBufferWriter &DBW) {<br>
+  if (auto EC = serialize(C, DBW.getDst()))<br>
+    return EC;<br>
+  if (auto EC = serialize(C, DBW.getSize()))<br>
+    return EC;<br>
+  return C.appendBytes(DBW.getSrc(), DBW.getSize());<br>
+}<br>
+<br>
+inline std::error_code deserialize(RPCChannel &C,<br>
+                                  DirectBufferWriter &DBW) {<br>
+  TargetAddress Dst;<br>
+  if (auto EC = deserialize(C, Dst))<br>
+    return EC;<br>
+  uint64_t Size;<br>
+  if (auto EC = deserialize(C, Size))<br>
+    return EC;<br>
+  char *Addr = reinterpret_cast<char*>(static_cast<uintptr_t>(Dst));<br>
+<br>
+  DBW = DirectBufferWriter(0, Dst, Size);<br>
+<br>
+  return C.readBytes(Addr, Size);<br>
+}<br>
+<br>
 class OrcRemoteTargetRPCAPI : public RPC<RPCChannel> {<br>
 protected:<br>
+<br>
   class ResourceIdMgr {<br>
   public:<br>
     typedef uint64_t ResourceId;<br>
@@ -45,146 +85,111 @@ protected:<br>
   };<br>
<br>
 public:<br>
-  enum JITProcId : uint32_t {<br>
-    InvalidId = 0,<br>
-    CallIntVoidId,<br>
-    CallIntVoidResponseId,<br>
+  enum JITFuncId : uint32_t {<br>
+    InvalidId = RPCFunctionIdTraits<JITFuncId>::InvalidId,<br>
+    CallIntVoidId = RPCFunctionIdTraits<JITFuncId>::FirstValidId,<br>
     CallMainId,<br>
-    CallMainResponseId,<br>
     CallVoidVoidId,<br>
-    CallVoidVoidResponseId,<br>
     CreateRemoteAllocatorId,<br>
     CreateIndirectStubsOwnerId,<br>
     DeregisterEHFramesId,<br>
     DestroyRemoteAllocatorId,<br>
     DestroyIndirectStubsOwnerId,<br>
     EmitIndirectStubsId,<br>
-    EmitIndirectStubsResponseId,<br>
     EmitResolverBlockId,<br>
     EmitTrampolineBlockId,<br>
-    EmitTrampolineBlockResponseId,<br>
     GetSymbolAddressId,<br>
-    GetSymbolAddressResponseId,<br>
     GetRemoteInfoId,<br>
-    GetRemoteInfoResponseId,<br>
     ReadMemId,<br>
-    ReadMemResponseId,<br>
     RegisterEHFramesId,<br>
     ReserveMemId,<br>
-    ReserveMemResponseId,<br>
     RequestCompileId,<br>
-    RequestCompileResponseId,<br>
     SetProtectionsId,<br>
     TerminateSessionId,<br>
     WriteMemId,<br>
     WritePtrId<br>
   };<br>
<br>
-  static const char *getJITProcIdName(JITProcId Id);<br>
-<br>
-  typedef Procedure<CallIntVoidId, void(TargetAddress Addr)> CallIntVoid;<br>
+  static const char *getJITFuncIdName(JITFuncId Id);<br>
<br>
-  typedef Procedure<CallIntVoidResponseId, void(int Result)><br>
-    CallIntVoidResponse;<br>
+  typedef Function<CallIntVoidId, int32_t(TargetAddress Addr)> CallIntVoid;<br>
<br>
-  typedef Procedure<CallMainId, void(TargetAddress Addr,<br>
-                                     std::vector<std::string> Args)><br>
+  typedef Function<CallMainId, int32_t(TargetAddress Addr,<br>
+                                      std::vector<std::string> Args)><br>
       CallMain;<br>
<br>
-  typedef Procedure<CallMainResponseId, void(int Result)> CallMainResponse;<br>
-<br>
-  typedef Procedure<CallVoidVoidId, void(TargetAddress FnAddr)> CallVoidVoid;<br>
-<br>
-  typedef Procedure<CallVoidVoidResponseId, void()> CallVoidVoidResponse;<br>
+  typedef Function<CallVoidVoidId, void(TargetAddress FnAddr)> CallVoidVoid;<br>
<br>
-  typedef Procedure<CreateRemoteAllocatorId,<br>
-                    void(ResourceIdMgr::ResourceId AllocatorID)><br>
+  typedef Function<CreateRemoteAllocatorId,<br>
+                  void(ResourceIdMgr::ResourceId AllocatorID)><br>
       CreateRemoteAllocator;<br>
<br>
-  typedef Procedure<CreateIndirectStubsOwnerId,<br>
-                    void(ResourceIdMgr::ResourceId StubOwnerID)><br>
+  typedef Function<CreateIndirectStubsOwnerId,<br>
+                  void(ResourceIdMgr::ResourceId StubOwnerID)><br>
     CreateIndirectStubsOwner;<br>
<br>
-  typedef Procedure<DeregisterEHFramesId,<br>
-                    void(TargetAddress Addr, uint32_t Size)><br>
+  typedef Function<DeregisterEHFramesId,<br>
+                  void(TargetAddress Addr, uint32_t Size)><br>
       DeregisterEHFrames;<br>
<br>
-  typedef Procedure<DestroyRemoteAllocatorId,<br>
-                    void(ResourceIdMgr::ResourceId AllocatorID)><br>
+  typedef Function<DestroyRemoteAllocatorId,<br>
+                  void(ResourceIdMgr::ResourceId AllocatorID)><br>
       DestroyRemoteAllocator;<br>
<br>
-  typedef Procedure<DestroyIndirectStubsOwnerId,<br>
-                    void(ResourceIdMgr::ResourceId StubsOwnerID)><br>
+  typedef Function<DestroyIndirectStubsOwnerId,<br>
+                  void(ResourceIdMgr::ResourceId StubsOwnerID)><br>
       DestroyIndirectStubsOwner;<br>
<br>
-  typedef Procedure<EmitIndirectStubsId,<br>
-                    void(ResourceIdMgr::ResourceId StubsOwnerID,<br>
-                         uint32_t NumStubsRequired)><br>
+  /// EmitIndirectStubs result is (StubsBase, PtrsBase, NumStubsEmitted).<br>
+  typedef Function<EmitIndirectStubsId,<br>
+                  std::tuple<TargetAddress, TargetAddress, uint32_t>(<br>
+                        ResourceIdMgr::ResourceId StubsOwnerID,<br>
+                       uint32_t NumStubsRequired)><br>
       EmitIndirectStubs;<br>
<br>
-  typedef Procedure<EmitIndirectStubsResponseId,<br>
-                    void(TargetAddress StubsBaseAddr,<br>
-                         TargetAddress PtrsBaseAddr,<br>
-                         uint32_t NumStubsEmitted)><br>
-      EmitIndirectStubsResponse;<br>
+  typedef Function<EmitResolverBlockId, void()> EmitResolverBlock;<br>
<br>
-  typedef Procedure<EmitResolverBlockId, void()> EmitResolverBlock;<br>
+  /// EmitTrampolineBlock result is (BlockAddr, NumTrampolines).<br>
+  typedef Function<EmitTrampolineBlockId,<br>
+                  std::tuple<TargetAddress, uint32_t>()> EmitTrampolineBlock;<br>
<br>
-  typedef Procedure<EmitTrampolineBlockId, void()> EmitTrampolineBlock;<br>
-<br>
-  typedef Procedure<EmitTrampolineBlockResponseId,<br>
-                    void(TargetAddress BlockAddr, uint32_t NumTrampolines)><br>
-      EmitTrampolineBlockResponse;<br>
-<br>
-  typedef Procedure<GetSymbolAddressId, void(std::string SymbolName)><br>
+  typedef Function<GetSymbolAddressId, TargetAddress(std::string SymbolName)><br>
       GetSymbolAddress;<br>
<br>
-  typedef Procedure<GetSymbolAddressResponseId, void(uint64_t SymbolAddr)><br>
-      GetSymbolAddressResponse;<br>
-<br>
-  typedef Procedure<GetRemoteInfoId, void()> GetRemoteInfo;<br>
-<br>
-  typedef Procedure<GetRemoteInfoResponseId,<br>
-                    void(std::string Triple, uint32_t PointerSize,<br>
-                         uint32_t PageSize, uint32_t TrampolineSize,<br>
-                         uint32_t IndirectStubSize)><br>
-      GetRemoteInfoResponse;<br>
+  /// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize,<br>
+  ///                          IndirectStubsSize).<br>
+  typedef Function<GetRemoteInfoId,<br>
+                  std::tuple<std::string, uint32_t, uint32_t, uint32_t,<br>
+                             uint32_t>()> GetRemoteInfo;<br>
<br>
-  typedef Procedure<ReadMemId, void(TargetAddress Src, uint64_t Size)><br>
+  typedef Function<ReadMemId,<br>
+                  std::vector<char>(TargetAddress Src, uint64_t Size)><br>
       ReadMem;<br>
<br>
-  typedef Procedure<ReadMemResponseId, void()> ReadMemResponse;<br>
-<br>
-  typedef Procedure<RegisterEHFramesId,<br>
-                    void(TargetAddress Addr, uint32_t Size)><br>
+  typedef Function<RegisterEHFramesId,<br>
+                  void(TargetAddress Addr, uint32_t Size)><br>
       RegisterEHFrames;<br>
<br>
-  typedef Procedure<ReserveMemId,<br>
-                    void(ResourceIdMgr::ResourceId AllocID, uint64_t Size,<br>
-                         uint32_t Align)><br>
+  typedef Function<ReserveMemId,<br>
+                  TargetAddress(ResourceIdMgr::ResourceId AllocID,<br>
+                                uint64_t Size, uint32_t Align)><br>
       ReserveMem;<br>
<br>
-  typedef Procedure<ReserveMemResponseId, void(TargetAddress Addr)><br>
-      ReserveMemResponse;<br>
-<br>
-  typedef Procedure<RequestCompileId, void(TargetAddress TrampolineAddr)><br>
+  typedef Function<RequestCompileId,<br>
+                  TargetAddress(TargetAddress TrampolineAddr)><br>
       RequestCompile;<br>
<br>
-  typedef Procedure<RequestCompileResponseId, void(TargetAddress ImplAddr)><br>
-      RequestCompileResponse;<br>
-<br>
-  typedef Procedure<SetProtectionsId,<br>
-                    void(ResourceIdMgr::ResourceId AllocID, TargetAddress Dst,<br>
-                         uint32_t ProtFlags)><br>
+  typedef Function<SetProtectionsId,<br>
+                  void(ResourceIdMgr::ResourceId AllocID, TargetAddress Dst,<br>
+                       uint32_t ProtFlags)><br>
       SetProtections;<br>
<br>
-  typedef Procedure<TerminateSessionId, void()> TerminateSession;<br>
+  typedef Function<TerminateSessionId, void()> TerminateSession;<br>
<br>
-  typedef Procedure<WriteMemId,<br>
-                    void(TargetAddress Dst, uint64_t Size /* Data to follow */)><br>
+  typedef Function<WriteMemId, void(DirectBufferWriter DB)><br>
       WriteMem;<br>
<br>
-  typedef Procedure<WritePtrId, void(TargetAddress Dst, TargetAddress Val)><br>
+  typedef Function<WritePtrId, void(TargetAddress Dst, TargetAddress Val)><br>
       WritePtr;<br>
 };<br>
<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h Sun Apr 17 20:06:49 2016<br>
@@ -45,14 +45,14 @@ public:<br>
         EHFramesRegister(std::move(EHFramesRegister)),<br>
         EHFramesDeregister(std::move(EHFramesDeregister)) {}<br>
<br>
-  std::error_code getNextProcId(JITProcId &Id) {<br>
+  std::error_code getNextFuncId(JITFuncId &Id) {<br>
     return deserialize(Channel, Id);<br>
   }<br>
<br>
-  std::error_code handleKnownProcedure(JITProcId Id) {<br>
+  std::error_code handleKnownFunction(JITFuncId Id) {<br>
     typedef OrcRemoteTargetServer ThisT;<br>
<br>
-    DEBUG(dbgs() << "Handling known proc: " << getJITProcIdName(Id) << "\n");<br>
+    DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) << "\n");<br>
<br>
     switch (Id) {<br>
     case CallIntVoidId:<br>
@@ -111,27 +111,17 @@ public:<br>
     llvm_unreachable("Unhandled JIT RPC procedure Id.");<br>
   }<br>
<br>
-  std::error_code requestCompile(TargetAddress &CompiledFnAddr,<br>
-                                 TargetAddress TrampolineAddr) {<br>
-    if (auto EC = call<RequestCompile>(Channel, TrampolineAddr))<br>
-      return EC;<br>
-<br>
-    while (1) {<br>
-      JITProcId Id = InvalidId;<br>
-      if (auto EC = getNextProcId(Id))<br>
-        return EC;<br>
+  ErrorOr<TargetAddress> requestCompile(TargetAddress TrampolineAddr) {<br>
+    auto Listen =<br>
+      [&](RPCChannel &C, uint32_t Id) {<br>
+        return handleKnownFunction(static_cast<JITFuncId>(Id));<br>
+      };<br>
<br>
-      switch (Id) {<br>
-      case RequestCompileResponseId:<br>
-        return handle<RequestCompileResponse>(Channel,<br>
-                                              readArgs(CompiledFnAddr));<br>
-      default:<br>
-        if (auto EC = handleKnownProcedure(Id))<br>
-          return EC;<br>
-      }<br>
-    }<br>
+    return callSTHandling<RequestCompile>(Channel, Listen, TrampolineAddr);<br>
+  }<br>
<br>
-    llvm_unreachable("Fell through request-compile command loop.");<br>
+  void handleTerminateSession() {<br>
+    handle<TerminateSession>(Channel, [](){ return std::error_code(); });<br>
   }<br>
<br>
 private:<br>
@@ -175,18 +165,16 @@ private:<br>
   static std::error_code doNothing() { return std::error_code(); }<br>
<br>
   static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {<br>
-    TargetAddress CompiledFnAddr = 0;<br>
-<br>
     auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr);<br>
-    auto EC = T->requestCompile(<br>
-        CompiledFnAddr, static_cast<TargetAddress>(<br>
-                            reinterpret_cast<uintptr_t>(TrampolineAddr)));<br>
-    assert(!EC && "Compile request failed");<br>
-    (void)EC;<br>
-    return CompiledFnAddr;<br>
+    auto AddrOrErr = T->requestCompile(<br>
+                      static_cast<TargetAddress>(<br>
+                        reinterpret_cast<uintptr_t>(TrampolineAddr)));<br>
+    // FIXME: Allow customizable failure substitution functions.<br>
+    assert(AddrOrErr && "Compile request failed");<br>
+    return *AddrOrErr;<br>
   }<br>
<br>
-  std::error_code handleCallIntVoid(TargetAddress Addr) {<br>
+  ErrorOr<int32_t> handleCallIntVoid(TargetAddress Addr) {<br>
     typedef int (*IntVoidFnTy)();<br>
     IntVoidFnTy Fn =<br>
         reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr));<br>
@@ -195,11 +183,11 @@ private:<br>
     int Result = Fn();<br>
     DEBUG(dbgs() << "  Result = " << Result << "\n");<br>
<br>
-    return call<CallIntVoidResponse>(Channel, Result);<br>
+    return Result;<br>
   }<br>
<br>
-  std::error_code handleCallMain(TargetAddress Addr,<br>
-                                 std::vector<std::string> Args) {<br>
+  ErrorOr<int32_t> handleCallMain(TargetAddress Addr,<br>
+                                 std::vector<std::string> Args) {<br>
     typedef int (*MainFnTy)(int, const char *[]);<br>
<br>
     MainFnTy Fn = reinterpret_cast<MainFnTy>(static_cast<uintptr_t>(Addr));<br>
@@ -214,7 +202,7 @@ private:<br>
     int Result = Fn(ArgC, ArgV.get());<br>
     DEBUG(dbgs() << "  Result = " << Result << "\n");<br>
<br>
-    return call<CallMainResponse>(Channel, Result);<br>
+    return Result;<br>
   }<br>
<br>
   std::error_code handleCallVoidVoid(TargetAddress Addr) {<br>
@@ -226,7 +214,7 @@ private:<br>
     Fn();<br>
     DEBUG(dbgs() << "  Complete.\n");<br>
<br>
-    return call<CallVoidVoidResponse>(Channel);<br>
+    return std::error_code();<br>
   }<br>
<br>
   std::error_code handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {<br>
@@ -273,8 +261,9 @@ private:<br>
     return std::error_code();<br>
   }<br>
<br>
-  std::error_code handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,<br>
-                                          uint32_t NumStubsRequired) {<br>
+  ErrorOr<std::tuple<TargetAddress, TargetAddress, uint32_t>><br>
+  handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,<br>
+                         uint32_t NumStubsRequired) {<br>
     DEBUG(dbgs() << "  ISMgr " << Id << " request " << NumStubsRequired<br>
                  << " stubs.\n");<br>
<br>
@@ -296,8 +285,7 @@ private:<br>
     auto &BlockList = StubOwnerItr->second;<br>
     BlockList.push_back(std::move(IS));<br>
<br>
-    return call<EmitIndirectStubsResponse>(Channel, StubsBase, PtrsBase,<br>
-                                           NumStubsEmitted);<br>
+    return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted);<br>
   }<br>
<br>
   std::error_code handleEmitResolverBlock() {<br>
@@ -316,7 +304,8 @@ private:<br>
                                                 sys::Memory::MF_EXEC);<br>
   }<br>
<br>
-  std::error_code handleEmitTrampolineBlock() {<br>
+  ErrorOr<std::tuple<TargetAddress, uint32_t>><br>
+  handleEmitTrampolineBlock() {<br>
     std::error_code EC;<br>
     auto TrampolineBlock =<br>
         sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(<br>
@@ -325,7 +314,7 @@ private:<br>
     if (EC)<br>
       return EC;<br>
<br>
-    unsigned NumTrampolines =<br>
+    uint32_t NumTrampolines =<br>
         (sys::Process::getPageSize() - TargetT::PointerSize) /<br>
         TargetT::TrampolineSize;<br>
<br>
@@ -339,20 +328,21 @@ private:<br>
<br>
     TrampolineBlocks.push_back(std::move(TrampolineBlock));<br>
<br>
-    return call<EmitTrampolineBlockResponse>(<br>
-        Channel,<br>
-        static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem)),<br>
-        NumTrampolines);<br>
+    auto TrampolineBaseAddr =<br>
+      static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem));<br>
+<br>
+    return std::make_tuple(TrampolineBaseAddr, NumTrampolines);<br>
   }<br>
<br>
-  std::error_code handleGetSymbolAddress(const std::string &Name) {<br>
+  ErrorOr<TargetAddress> handleGetSymbolAddress(const std::string &Name) {<br>
     TargetAddress Addr = SymbolLookup(Name);<br>
     DEBUG(dbgs() << "  Symbol '" << Name << "' =  " << format("0x%016x", Addr)<br>
                  << "\n");<br>
-    return call<GetSymbolAddressResponse>(Channel, Addr);<br>
+    return Addr;<br>
   }<br>
<br>
-  std::error_code handleGetRemoteInfo() {<br>
+  ErrorOr<std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>><br>
+  handleGetRemoteInfo() {<br>
     std::string ProcessTriple = sys::getProcessTriple();<br>
     uint32_t PointerSize = TargetT::PointerSize;<br>
     uint32_t PageSize = sys::Process::getPageSize();<br>
@@ -364,24 +354,23 @@ private:<br>
                  << "    page size          = " << PageSize << "\n"<br>
                  << "    trampoline size    = " << TrampolineSize << "\n"<br>
                  << "    indirect stub size = " << IndirectStubSize << "\n");<br>
-    return call<GetRemoteInfoResponse>(Channel, ProcessTriple, PointerSize,<br>
-                                       PageSize, TrampolineSize,<br>
-                                       IndirectStubSize);<br>
+    return std::make_tuple(ProcessTriple, PointerSize, PageSize ,TrampolineSize,<br>
+                          IndirectStubSize);<br>
   }<br>
<br>
-  std::error_code handleReadMem(TargetAddress RSrc, uint64_t Size) {<br>
+  ErrorOr<std::vector<char>><br>
+  handleReadMem(TargetAddress RSrc, uint64_t Size) {<br>
     char *Src = reinterpret_cast<char *>(static_cast<uintptr_t>(RSrc));<br>
<br>
     DEBUG(dbgs() << "  Reading " << Size << " bytes from "<br>
                  << format("0x%016x", RSrc) << "\n");<br>
<br>
-    if (auto EC = call<ReadMemResponse>(Channel))<br>
-      return EC;<br>
-<br>
-    if (auto EC = Channel.appendBytes(Src, Size))<br>
-      return EC;<br>
+    std::vector<char> Buffer;<br>
+    Buffer.resize(Size);<br>
+    for (char *P = Src; Size != 0; --Size)<br>
+      Buffer.push_back(*P++);<br>
<br>
-    return Channel.send();<br>
+    return Buffer;<br>
   }<br>
<br>
   std::error_code handleRegisterEHFrames(TargetAddress TAddr, uint32_t Size) {<br>
@@ -392,8 +381,9 @@ private:<br>
     return std::error_code();<br>
   }<br>
<br>
-  std::error_code handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,<br>
-                                   uint32_t Align) {<br>
+  ErrorOr<TargetAddress><br>
+  handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,<br>
+                  uint32_t Align) {<br>
     auto I = Allocators.find(Id);<br>
     if (I == Allocators.end())<br>
       return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);<br>
@@ -408,7 +398,7 @@ private:<br>
     TargetAddress AllocAddr =<br>
         static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(LocalAllocAddr));<br>
<br>
-    return call<ReserveMemResponse>(Channel, AllocAddr);<br>
+    return AllocAddr;<br>
   }<br>
<br>
   std::error_code handleSetProtections(ResourceIdMgr::ResourceId Id,<br>
@@ -425,11 +415,10 @@ private:<br>
     return Allocator.setProtections(LocalAddr, Flags);<br>
   }<br>
<br>
-  std::error_code handleWriteMem(TargetAddress RDst, uint64_t Size) {<br>
-    char *Dst = reinterpret_cast<char *>(static_cast<uintptr_t>(RDst));<br>
-    DEBUG(dbgs() << "  Writing " << Size << " bytes to "<br>
-                 << format("0x%016x", RDst) << "\n");<br>
-    return Channel.readBytes(Dst, Size);<br>
+  std::error_code handleWriteMem(DirectBufferWriter DBW) {<br>
+    DEBUG(dbgs() << "  Writing " << DBW.getSize() << " bytes to "<br>
+                << format("0x%016x", DBW.getDst()) << "\n");<br>
+    return std::error_code();<br>
   }<br>
<br>
   std::error_code handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) {<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCChannel.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCChannel.h?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCChannel.h?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCChannel.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCChannel.h Sun Apr 17 20:06:49 2016<br>
@@ -5,8 +5,10 @@<br>
<br>
 #include "OrcError.h"<br>
 #include "llvm/ADT/ArrayRef.h"<br>
+#include "llvm/ADT/STLExtras.h"<br>
 #include "llvm/Support/Endian.h"<br>
<br>
+#include <mutex><br>
 #include <system_error><br>
<br>
 namespace llvm {<br>
@@ -26,31 +28,68 @@ public:<br>
<br>
   /// Flush the stream if possible.<br>
   virtual std::error_code 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 std::error_code startSendMessage(RPCChannel &C) {<br>
+  C.getWriteLock().lock();<br>
+  return std::error_code();<br>
+}<br>
+<br>
+/// Notify the channel that we're ending a message send.<br>
+/// Unlocks the channel for writing.<br>
+inline std::error_code endSendMessage(RPCChannel &C) {<br>
+  C.getWriteLock().unlock();<br>
+  return std::error_code();<br>
+}<br>
+<br>
+/// Notify the channel that we're starting a message receive.<br>
+/// Locks the channel for reading.<br>
+inline std::error_code startReceiveMessage(RPCChannel &C) {<br>
+  C.getReadLock().lock();<br>
+  return std::error_code();<br>
+}<br>
+<br>
+/// Notify the channel that we're ending a message receive.<br>
+/// Unlocks the channel for reading.<br>
+inline std::error_code endReceiveMessage(RPCChannel &C) {<br>
+  C.getReadLock().unlock();<br>
+  return std::error_code();<br>
+}<br>
+<br>
 /// RPC channel serialization for a variadic list of arguments.<br>
 template <typename T, typename... Ts><br>
-std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) {<br>
+std::error_code serializeSeq(RPCChannel &C, const T &Arg, const Ts &... Args) {<br>
   if (auto EC = serialize(C, Arg))<br>
     return EC;<br>
-  return serialize_seq(C, Args...);<br>
+  return serializeSeq(C, Args...);<br>
 }<br>
<br>
 /// RPC channel serialization for an (empty) variadic list of arguments.<br>
-inline std::error_code serialize_seq(RPCChannel &C) {<br>
+inline std::error_code serializeSeq(RPCChannel &C) {<br>
   return std::error_code();<br>
 }<br>
<br>
 /// RPC channel deserialization for a variadic list of arguments.<br>
 template <typename T, typename... Ts><br>
-std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) {<br>
+std::error_code deserializeSeq(RPCChannel &C, T &Arg, Ts &... Args) {<br>
   if (auto EC = deserialize(C, Arg))<br>
     return EC;<br>
-  return deserialize_seq(C, Args...);<br>
+  return deserializeSeq(C, Args...);<br>
 }<br>
<br>
 /// RPC channel serialization for an (empty) variadic list of arguments.<br>
-inline std::error_code deserialize_seq(RPCChannel &C) {<br>
+inline std::error_code deserializeSeq(RPCChannel &C) {<br>
   return std::error_code();<br>
 }<br>
<br>
@@ -138,6 +177,34 @@ inline std::error_code deserialize(RPCCh<br>
   return C.readBytes(&S[0], Count);<br>
 }<br>
<br>
+// Serialization helper for std::tuple.<br>
+template <typename TupleT, size_t... Is><br>
+inline std::error_code serializeTupleHelper(RPCChannel &C,<br>
+                                           const TupleT &V,<br>
+                                           llvm::index_sequence<Is...> _) {<br>
+  return serializeSeq(C, std::get<Is>(V)...);<br>
+}<br>
+<br>
+/// RPC channel serialization for std::tuple.<br>
+template <typename... ArgTs><br>
+inline std::error_code serialize(RPCChannel &C, const std::tuple<ArgTs...> &V) {<br>
+  return serializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>());<br>
+}<br>
+<br>
+// Serialization helper for std::tuple.<br>
+template <typename TupleT, size_t... Is><br>
+inline std::error_code deserializeTupleHelper(RPCChannel &C,<br>
+                                             TupleT &V,<br>
+                                             llvm::index_sequence<Is...> _) {<br>
+  return deserializeSeq(C, std::get<Is>(V)...);<br>
+}<br>
+<br>
+/// RPC channel deserialization for std::tuple.<br>
+template <typename... ArgTs><br>
+inline std::error_code deserialize(RPCChannel &C, std::tuple<ArgTs...> &V) {<br>
+  return deserializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>());<br>
+}<br>
+<br>
 /// RPC channel serialization for ArrayRef<T>.<br>
 template <typename T><br>
 std::error_code serialize(RPCChannel &C, const ArrayRef<T> &A) {<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/RPCUtils.h Sun Apr 17 20:06:49 2016<br>
@@ -14,46 +14,197 @@<br>
 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H<br>
 #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H<br>
<br>
+#include "llvm/ADT/Optional.h"<br>
 #include "llvm/ADT/STLExtras.h"<br>
 #include "llvm/ExecutionEngine/Orc/OrcError.h"<br>
+#include "llvm/Support/ErrorOr.h"<br>
+#include <future><br>
+#include <map><br>
<br>
 namespace llvm {<br>
 namespace orc {<br>
 namespace remote {<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>
+<br>
+template <typename T><br>
+class RPCFunctionIdTraits {<br>
+public:<br>
+  constexpr static const T InvalidId = static_cast<T>(0);<br>
+  constexpr static const T ResponseId = static_cast<T>(1);<br>
+  constexpr static const T FirstValidId = static_cast<T>(2);<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>
-  template <typename ProcedureIdT, ProcedureIdT ProcId, typename FnT><br>
-  class ProcedureHelper {<br>
-  public:<br>
-    static const ProcedureIdT Id = ProcId;<br>
-  };<br>
<br>
-  template <typename ChannelT, typename Proc> class CallHelper;<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>
+  // OptionalReturn - The return type for asyncronous calls.<br>
+  // ErrorReturn - The return type for synchronous calls.<br>
+  // optionalToErrorReturn - Conversion from a valid OptionalReturn to an<br>
+  //                         ErrorReturn.<br>
+  // readResult - Deserialize a result from a channel.<br>
+  // abandon - Abandon a promised (asynchronous) result.<br>
+  // respond - Retun a result on the channel.<br>
+  template <typename FunctionIdT, FunctionIdT FuncId, typename FnT><br>
+  class FunctionHelper {};<br>
<br>
-  template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId,<br>
+  // RPC Function description specialization for non-void functions.<br>
+  template <typename FunctionIdT, FunctionIdT FuncId, typename RetT,<br>
             typename... ArgTs><br>
-  class CallHelper<ChannelT,<br>
-                   ProcedureHelper<ProcedureIdT, ProcId, void(ArgTs...)>> {<br>
+  class FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> {<br>
   public:<br>
-    static std::error_code call(ChannelT &C, const ArgTs &... Args) {<br>
-      if (auto EC = serialize(C, ProcId))<br>
+<br>
+    static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId &&<br>
+                  FuncId != RPCFunctionIdTraits<FunctionIdT>::ResponseId,<br>
+                  "Cannot define custom function with InvalidId or ResponseId. "<br>
+                  "Please use RPCFunctionTraits<FunctionIdT>::FirstValidId.");<br>
+<br>
+    static const FunctionIdT Id = FuncId;<br>
+<br>
+    typedef Optional<RetT> OptionalReturn;<br>
+<br>
+    typedef ErrorOr<RetT> ErrorReturn;<br>
+<br>
+    static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) {<br>
+      assert(V && "Return value not available");<br>
+      return std::move(*V);<br>
+    }<br>
+<br>
+    template <typename ChannelT><br>
+    static std::error_code readResult(ChannelT &C,<br>
+                                      std::promise<OptionalReturn> &P) {<br>
+      RetT Val;<br>
+      auto EC = deserialize(C, Val);<br>
+      // FIXME: Join error EC2 from endReceiveMessage with the deserialize<br>
+      //        error once we switch to using Error.<br>
+      auto EC2 = endReceiveMessage(C);<br>
+      (void)EC2;<br>
+<br>
+      if (EC) {<br>
+        P.set_value(OptionalReturn());<br>
         return EC;<br>
-      // If you see a compile-error on this line you're probably calling a<br>
-      // function with the wrong signature.<br>
-      return serialize_seq(C, Args...);<br>
+      }<br>
+      P.set_value(std::move(Val));<br>
+      return std::error_code();<br>
+    }<br>
+<br>
+    static void abandon(std::promise<OptionalReturn> &P) {<br>
+      P.set_value(OptionalReturn());<br>
+    }<br>
+<br>
+    template <typename ChannelT, typename SequenceNumberT><br>
+    static std::error_code respond(ChannelT &C, SequenceNumberT SeqNo,<br>
+                                   const ErrorReturn &Result) {<br>
+      FunctionIdT ResponseId =<br>
+        RPCFunctionIdTraits<FunctionIdT>::ResponseId;<br>
+<br>
+      // If the handler returned an error then bail out with that.<br>
+      if (!Result)<br>
+        return Result.getError();<br>
+<br>
+      // Otherwise open a new message on the channel and send the result.<br>
+      if (auto EC = startSendMessage(C))<br>
+        return EC;<br>
+      if (auto EC = serializeSeq(C, ResponseId, SeqNo, *Result))<br>
+        return EC;<br>
+      return endSendMessage(C);<br>
     }<br>
   };<br>
<br>
-  template <typename ChannelT, typename Proc> class HandlerHelper;<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>
<br>
-  template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId,<br>
-            typename... ArgTs><br>
-  class HandlerHelper<ChannelT,<br>
-                      ProcedureHelper<ProcedureIdT, ProcId, void(ArgTs...)>> {<br>
+    static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId &&<br>
+                  FuncId != RPCFunctionIdTraits<FunctionIdT>::ResponseId,<br>
+                  "Cannot define custom function with InvalidId or ResponseId. "<br>
+                  "Please use RPCFunctionTraits<FunctionIdT>::FirstValidId.");<br>
+<br>
+    static const FunctionIdT Id = FuncId;<br>
+<br>
+    typedef bool OptionalReturn;<br>
+    typedef std::error_code ErrorReturn;<br>
+<br>
+    static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) {<br>
+      assert(V && "Return value not available");<br>
+      return std::error_code();<br>
+    }<br>
+<br>
+    template <typename ChannelT><br>
+    static std::error_code readResult(ChannelT &C,<br>
+                                      std::promise<OptionalReturn> &P) {<br>
+      // Void functions don't have anything to deserialize, so we're good.<br>
+      P.set_value(true);<br>
+      return endReceiveMessage(C);<br>
+    }<br>
+<br>
+    static void abandon(std::promise<OptionalReturn> &P) {<br>
+      P.set_value(false);<br>
+    }<br>
+<br>
+    template <typename ChannelT, typename SequenceNumberT><br>
+    static std::error_code respond(ChannelT &C, SequenceNumberT SeqNo,<br>
+                                  const ErrorReturn &Result) {<br>
+      const FunctionIdT ResponseId =<br>
+       RPCFunctionIdTraits<FunctionIdT>::ResponseId;<br>
+<br>
+      // If the handler returned an error then bail out with that.<br>
+      if (Result)<br>
+        return Result;<br>
+<br>
+      // Otherwise open a new message on the channel and send the result.<br>
+      if (auto EC = startSendMessage(C))<br>
+        return EC;<br>
+      if (auto EC = serializeSeq(C, ResponseId, SeqNo))<br>
+        return EC;<br>
+      return endSendMessage(C);<br>
+    }<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 std::error_code call(ChannelT &C, SequenceNumberT SeqNo,<br>
+                               const ArgTs &... Args) {<br>
+      if (auto EC = startSendMessage(C))<br>
+        return EC;<br>
+      if (auto EC = serializeSeq(C, FuncId, SeqNo, Args...))<br>
+        return EC;<br>
+      return endSendMessage(C);<br>
+    }<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 std::error_code handle(ChannelT &C, HandlerT Handler) {<br>
@@ -61,34 +212,46 @@ protected:<br>
     }<br>
<br>
   private:<br>
+<br>
+    typedef FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> Func;<br>
+<br>
     template <typename HandlerT, size_t... Is><br>
     static std::error_code 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 EC = deserialize_seq(C, std::get<Is>(RPCArgs)...))<br>
+      if (auto EC = deserializeSeq(C, SeqNo, std::get<Is>(RPCArgs)...))<br>
         return EC;<br>
-      return Handler(std::get<Is>(RPCArgs)...);<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 EC = endReceiveMessage(C))<br>
+        return EC;<br>
+<br>
+      return Func::template respond<ChannelT, SequenceNumberT>(<br>
+                     C, SeqNo, Handler(std::get<Is>(RPCArgs)...));<br>
     }<br>
+<br>
   };<br>
<br>
-  template <typename ClassT, typename... ArgTs> class MemberFnWrapper {<br>
+  // Helper for wrapping member functions up as functors.<br>
+  template <typename ClassT, typename RetT, typename... ArgTs><br>
+  class MemberFnWrapper {<br>
   public:<br>
-    typedef std::error_code (ClassT::*MethodT)(ArgTs...);<br>
+    typedef RetT(ClassT::*MethodT)(ArgTs...);<br>
     MemberFnWrapper(ClassT &Instance, MethodT Method)<br>
         : Instance(Instance), Method(Method) {}<br>
-    std::error_code operator()(ArgTs &... Args) {<br>
-      return (Instance.*Method)(Args...);<br>
-    }<br>
-<br>
+    RetT operator()(ArgTs &... Args) { return (Instance.*Method)(Args...); }<br>
   private:<br>
     ClassT &Instance;<br>
     MethodT Method;<br>
   };<br>
<br>
+  // Helper that provides a Functor for deserializing arguments.<br>
   template <typename... ArgTs> class ReadArgs {<br>
   public:<br>
     std::error_code operator()() { return std::error_code(); }<br>
@@ -112,7 +275,7 @@ protected:<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 ProcedureIdT is a procedure<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>
@@ -129,120 +292,184 @@ protected:<br>
 ///<br>
 /// Overview (see comments individual types/methods for details):<br>
 ///<br>
-/// Procedure<Id, Args...> :<br>
+/// Function<Id, Args...> :<br>
 ///<br>
 ///   associates a unique serializable id with an argument list.<br>
 ///<br>
 ///<br>
-/// call<Proc>(Channel, Args...) :<br>
+/// call<Func>(Channel, Args...) :<br>
 ///<br>
-///   Calls the remote procedure 'Proc' by serializing Proc's id followed by its<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<Proc>(Channel, <functor matching std::error_code(Args...)> :<br>
+/// handle<Func>(Channel, <functor matching std::error_code(Args...)> :<br>
 ///<br>
-///   Handles a call to 'Proc' by deserializing its arguments and calling the<br>
-/// given functor. This assumes that the id for 'Proc' has already been<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<Proc>(Channel, <functor matching std::error_code(Args...)> :<br>
+/// expect<Func>(Channel, <functor matching std::error_code(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 Proc's<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>
-<br>
-template <typename ChannelT, typename ProcedureIdT = uint32_t><br>
+template <typename ChannelT, typename FunctionIdT = uint32_t,<br>
+          typename SequenceNumberT = uint16_t><br>
 class RPC : public RPCBase {<br>
 public:<br>
+<br>
+  RPC() = default;<br>
+  RPC(const RPC&) = delete;<br>
+  RPC& operator=(const RPC&) = delete;<br>
+  RPC(RPC &&Other) : SequenceNumberMgr(std::move(Other.SequenceNumberMgr)), OutstandingResults(std::move(Other.OutstandingResults)) {}<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>
-  /// ProcId should be a unique value of ProcedureIdT (i.e. not used with any<br>
-  /// other Procedure typedef in the RPC API being defined.<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 Procedure<0, bool> Proc1;<br>
-  ///   typedef Procedure<1, std::string, std::vector<int>> Proc2;<br>
+  ///   typedef Function<0, bool> Func1;<br>
+  ///   typedef Function<1, std::string, std::vector<int>> Func2;<br>
   ///<br>
-  ///   if (auto EC = call<Proc1>(Channel, true))<br>
+  ///   if (auto EC = call<Func1>(Channel, true))<br>
   ///     /* handle EC */;<br>
   ///<br>
-  ///   if (auto EC = expect<Proc2>(Channel,<br>
+  ///   if (auto EC = expect<Func2>(Channel,<br>
   ///         [](std::string &S, std::vector<int> &V) {<br>
   ///           // Stuff.<br>
   ///           return std::error_code();<br>
   ///         })<br>
   ///     /* handle EC */;<br>
   ///<br>
-  template <ProcedureIdT ProcId, typename FnT><br>
-  using Procedure = ProcedureHelper<ProcedureIdT, ProcId, FnT>;<br>
+  template <FunctionIdT FuncId, typename FnT><br>
+  using Function = FunctionHelper<FunctionIdT, FuncId, FnT>;<br>
+<br>
+  /// Return type for asynchronous call primitives.<br>
+  template <typename Func><br>
+  using AsyncCallResult =<br>
+    std::pair<std::future<typename Func::OptionalReturn>, SequenceNumberT>;<br>
<br>
   /// Serialize Args... to channel C, but do not call C.send().<br>
   ///<br>
-  /// For buffered channels, this can be used to queue up several calls before<br>
-  /// flushing the channel.<br>
-  template <typename Proc, typename... ArgTs><br>
-  static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) {<br>
-    return CallHelper<ChannelT, Proc>::call(C, Args...);<br>
+  /// For void functions returns a std::future<Error>. For functions that<br>
+  /// return an R, returns a std::future<Optional<R>>.<br>
+  template <typename Func, typename... ArgTs><br>
+  ErrorOr<AsyncCallResult<Func>><br>
+  appendCallAsync(ChannelT &C, const ArgTs &... Args) {<br>
+    auto SeqNo = SequenceNumberMgr.getSequenceNumber();<br>
+    std::promise<typename Func::OptionalReturn> Promise;<br>
+    auto Result = Promise.get_future();<br>
+    OutstandingResults[SeqNo] = std::move(Promise);<br>
+<br>
+    if (auto EC =<br>
+          CallHelper<ChannelT, SequenceNumberT, Func>::call(C, SeqNo,<br>
+                                                           Args...)) {<br>
+      abandonOutstandingResults();<br>
+      return EC;<br>
+    } else<br>
+      return AsyncCallResult<Func>(std::move(Result), SeqNo);<br>
   }<br>
<br>
   /// Serialize Args... to channel C and call C.send().<br>
-  template <typename Proc, typename... ArgTs><br>
-  static std::error_code call(ChannelT &C, const ArgTs &... Args) {<br>
-    if (auto EC = appendCall<Proc>(C, Args...))<br>
+  template <typename Func, typename... ArgTs><br>
+  ErrorOr<AsyncCallResult<Func>><br>
+  callAsync(ChannelT &C, const ArgTs &... Args) {<br>
+    auto SeqNo = SequenceNumberMgr.getSequenceNumber();<br>
+    std::promise<typename Func::OptionalReturn> Promise;<br>
+    auto Result = Promise.get_future();<br>
+    OutstandingResults[SeqNo] =<br>
+      createOutstandingResult<Func>(std::move(Promise));<br>
+    if (auto EC =<br>
+        CallHelper<ChannelT, SequenceNumberT, Func>::call(C, SeqNo, Args...)) {<br>
+      abandonOutstandingResults();<br>
       return EC;<br>
-    return C.send();<br>
+    }<br>
+    if (auto EC = C.send()) {<br>
+      abandonOutstandingResults();<br>
+      return EC;<br>
+    }<br>
+    return AsyncCallResult<Func>(std::move(Result), SeqNo);<br>
   }<br>
<br>
-  /// Deserialize and return an enum whose underlying type is ProcedureIdT.<br>
-  static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) {<br>
+  /// This can be used in single-threaded mode.<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 = callAsync<Func>(C, Args...)) {<br>
+      auto &ResultAndSeqNo = *ResultAndSeqNoOrErr;<br>
+      if (auto EC = waitForResult(C, ResultAndSeqNo.second, HandleOther))<br>
+       return EC;<br>
+      return Func::optionalToErrorReturn(ResultAndSeqNo.first.get());<br>
+    } else<br>
+      return ResultAndSeqNoOrErr.getError();<br>
+  }<br>
+<br>
+  // This can be used in single-threaded mode.<br>
+  template <typename Func, typename... ArgTs><br>
+  typename Func::ErrorReturn<br>
+  callST(ChannelT &C, const ArgTs &... Args) {<br>
+    return callSTHandling<Func>(C, handleNone, Args...);<br>
+  }<br>
+<br>
+  /// Start receiving a new function call.<br>
+  ///<br>
+  /// Calls startReceiveMessage on the channel, then deserializes a FunctionId<br>
+  /// into Id.<br>
+  std::error_code startReceivingFunction(ChannelT &C, FunctionIdT &Id) {<br>
+    if (auto EC = startReceiveMessage(C))<br>
+      return EC;<br>
+<br>
     return deserialize(C, Id);<br>
   }<br>
<br>
-  /// Deserialize args for Proc from C and call Handler. The signature of<br>
+  /// Deserialize args for Func from C and call Handler. The signature of<br>
   /// handler must conform to 'std::error_code(Args...)' where Args... matches<br>
-  /// the arguments used in the Proc typedef.<br>
-  template <typename Proc, typename HandlerT><br>
+  /// the arguments used in the Func typedef.<br>
+  template <typename Func, typename HandlerT><br>
   static std::error_code handle(ChannelT &C, HandlerT Handler) {<br>
-    return HandlerHelper<ChannelT, Proc>::handle(C, Handler);<br>
+    return HandlerHelper<ChannelT, SequenceNumberT, Func>::handle(C, Handler);<br>
   }<br>
<br>
   /// Helper version of 'handle' for calling member functions.<br>
-  template <typename Proc, typename ClassT, typename... ArgTs><br>
+  template <typename Func, typename ClassT, typename RetT, typename... ArgTs><br>
   static std::error_code<br>
   handle(ChannelT &C, ClassT &Instance,<br>
-         std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {<br>
-    return handle<Proc>(<br>
-        C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));<br>
+         RetT (ClassT::*HandlerMethod)(ArgTs...)) {<br>
+    return handle<Func>(<br>
+             C,<br>
+            MemberFnWrapper<ClassT, RetT, ArgTs...>(Instance, HandlerMethod));<br>
   }<br>
<br>
-  /// Deserialize a ProcedureIdT from C and verify it matches the id for Proc.<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 Proc, typename HandlerT><br>
-  static std::error_code expect(ChannelT &C, HandlerT Handler) {<br>
-    ProcedureIdT ProcId;<br>
-    if (auto EC = getNextProcId(C, ProcId))<br>
-      return EC;<br>
-    if (ProcId != Proc::Id)<br>
+  template <typename Func, typename HandlerT><br>
+  std::error_code expect(ChannelT &C, HandlerT Handler) {<br>
+    FunctionIdT FuncId;<br>
+    if (auto EC = startReceivingFunction(C, FuncId))<br>
+      return std::move(EC);<br>
+    if (FuncId != Func::Id)<br>
       return orcError(OrcErrorCode::UnexpectedRPCCall);<br>
-    return handle<Proc>(C, Handler);<br>
+    return handle<Func>(C, Handler);<br>
   }<br>
<br>
   /// Helper version of expect for calling member functions.<br>
-  template <typename Proc, typename ClassT, typename... ArgTs><br>
+  template <typename Func, typename ClassT, typename... ArgTs><br>
   static std::error_code<br>
   expect(ChannelT &C, ClassT &Instance,<br>
          std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {<br>
-    return expect<Proc>(<br>
+    return expect<Func>(<br>
         C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));<br>
   }<br>
<br>
@@ -251,18 +478,163 @@ public:<br>
   /// channel.<br>
   /// E.g.<br>
   ///<br>
-  ///   typedef Procedure<0, bool, int> Proc1;<br>
+  ///   typedef Function<0, bool, int> Func1;<br>
   ///<br>
   ///   ...<br>
   ///   bool B;<br>
   ///   int I;<br>
-  ///   if (auto EC = expect<Proc1>(Channel, readArgs(B, I)))<br>
+  ///   if (auto EC = expect<Func1>(Channel, readArgs(B, I)))<br>
   ///     /* Handle Args */ ;<br>
   ///<br>
   template <typename... ArgTs><br>
   static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {<br>
     return ReadArgs<ArgTs...>(Args...);<br>
   }<br>
+<br>
+  /// Read a response from Channel.<br>
+  /// This should be called from the receive loop to retrieve results.<br>
+  std::error_code handleResponse(ChannelT &C, SequenceNumberT &SeqNo) {<br>
+    if (auto EC = deserialize(C, SeqNo)) {<br>
+      abandonOutstandingResults();<br>
+      return EC;<br>
+    }<br>
+<br>
+    auto I = OutstandingResults.find(SeqNo);<br>
+    if (I == OutstandingResults.end()) {<br>
+      abandonOutstandingResults();<br>
+      return orcError(OrcErrorCode::UnexpectedRPCResponse);<br>
+    }<br>
+<br>
+    if (auto EC = I->second->readResult(C)) {<br>
+      abandonOutstandingResults();<br>
+      // FIXME: Release sequence numbers?<br>
+      return EC;<br>
+    }<br>
+<br>
+    OutstandingResults.erase(I);<br>
+    SequenceNumberMgr.releaseSequenceNumber(SeqNo);<br>
+<br>
+    return std::error_code();<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>
+  std::error_code waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo,<br>
+                               HandleOtherFtor &HandleOther = handleNone) {<br>
+    bool GotTgtResult = false;<br>
+<br>
+    while (!GotTgtResult) {<br>
+      FunctionIdT Id =<br>
+       RPCFunctionIdTraits<FunctionIdT>::InvalidId;<br>
+      if (auto EC = startReceivingFunction(C, Id))<br>
+       return EC;<br>
+      if (Id == RPCFunctionIdTraits<FunctionIdT>::ResponseId) {<br>
+        SequenceNumberT SeqNo;<br>
+       if (auto EC = handleResponse(C, SeqNo))<br></blockquote><div><br></div><div>Indentation looks a bit off here ^ ('if' is not indented the same as 'SequenceNumberT') & following into the next two lines and maybe the return in the else too?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+         return EC;<br>
+       GotTgtResult = (SeqNo == TgtSeqNo); </blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      } else if (auto EC = HandleOther(C, Id))<br>
+       return EC;<br>
+    }<br>
+<br>
+    return std::error_code();<br>
+  };<br>
+<br>
+  // Default handler for 'other' (non-response) functions when waiting for a<br>
+  // result from the channel.<br>
+  static std::error_code handleNone(ChannelT&, FunctionIdT) {<br>
+    return orcError(OrcErrorCode::UnexpectedRPCCall);<br>
+  };<br>
+<br>
+private:<br>
+<br>
+  // Manage sequence numbers.<br>
+  class SequenceNumberManager {<br>
+  public:<br>
+<br>
+    SequenceNumberManager() = default;<br>
+<br>
+    SequenceNumberManager(SequenceNumberManager &&Other)<br>
+      : NextSequenceNumber(std::move(Other.NextSequenceNumber)),<br>
+        FreeSequenceNumbers(std::move(Other.FreeSequenceNumbers)) {}<br>
+<br>
+    SequenceNumberManager& operator=(SequenceNumberManager &&Other) {<br>
+      NextSequenceNumber = std::move(Other.NextSequenceNumber);<br>
+      FreeSequenceNumbers = std::move(Other.FreeSequenceNumbers);<br>
+    }<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();<br>
+      return SequenceNumber;<br>
+    }<br>
+<br>
+    void releaseSequenceNumber(SequenceNumberT SequenceNumber) {<br>
+      std::lock_guard<std::mutex> Lock(SeqNoLock);<br>
+      FreeSequenceNumbers.push_back(SequenceNumber);<br>
+    }<br>
+<br>
+  private:<br>
+    std::mutex SeqNoLock;<br>
+    SequenceNumberT NextSequenceNumber = 0;<br>
+    std::vector<SequenceNumberT> FreeSequenceNumbers;<br>
+  };<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 std::error_code readResult(ChannelT &C) = 0;<br>
+    virtual void abandon() = 0;<br>
+  };<br>
+<br>
+  // Outstanding results for a specific function.<br>
+  template <typename Func><br>
+  class OutstandingResultImpl : public OutstandingResult {<br>
+  private:<br>
+  public:<br>
+    OutstandingResultImpl(std::promise<typename Func::OptionalReturn> &&P)<br>
+      : P(std::move(P)) {}<br>
+<br>
+    std::error_code readResult(ChannelT &C) override {<br>
+      return Func::readResult(C, P);<br>
+    }<br>
+<br>
+    void abandon() override { Func::abandon(P); }<br>
+<br>
+  private:<br>
+    std::promise<typename Func::OptionalReturn> P;<br>
+  };<br>
+<br>
+  // Create an outstanding result for the given function.<br>
+  template <typename Func><br>
+  std::unique_ptr<OutstandingResult><br>
+  createOutstandingResult(std::promise<typename Func::OptionalReturn> &&P) {<br>
+    return llvm::make_unique<OutstandingResultImpl<Func>>(std::move(P));<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>
+  }<br>
+<br>
+  SequenceNumberManager SequenceNumberMgr;<br>
+  std::map<SequenceNumberT, std::unique_ptr<OutstandingResult>><br>
+    OutstandingResults;<br>
 };<br>
<br>
 } // end namespace remote<br>
<br>
Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp (original)<br>
+++ llvm/trunk/lib/ExecutionEngine/Orc/OrcError.cpp Sun Apr 17 20:06:49 2016<br>
@@ -38,6 +38,8 @@ public:<br>
       return "Remote indirect stubs owner Id already in use";<br>
     case OrcErrorCode::UnexpectedRPCCall:<br>
       return "Unexpected RPC call";<br>
+    case OrcErrorCode::UnexpectedRPCResponse:<br>
+      return "Unexpected RPC response";<br>
     }<br>
     llvm_unreachable("Unhandled error code");<br>
   }<br>
<br>
Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp (original)<br>
+++ llvm/trunk/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp Sun Apr 17 20:06:49 2016<br>
@@ -13,50 +13,40 @@ namespace llvm {<br>
 namespace orc {<br>
 namespace remote {<br>
<br>
-#define PROCNAME(X) \<br>
+#define FUNCNAME(X) \<br>
   case X ## Id: \<br>
   return #X<br>
<br>
-const char *OrcRemoteTargetRPCAPI::getJITProcIdName(JITProcId Id) {<br>
+const char *OrcRemoteTargetRPCAPI::getJITFuncIdName(JITFuncId Id) {<br>
   switch (Id) {<br>
   case InvalidId:<br>
-    return "*** Invalid JITProcId ***";<br>
-  PROCNAME(CallIntVoid);<br>
-  PROCNAME(CallIntVoidResponse);<br>
-  PROCNAME(CallMain);<br>
-  PROCNAME(CallMainResponse);<br>
-  PROCNAME(CallVoidVoid);<br>
-  PROCNAME(CallVoidVoidResponse);<br>
-  PROCNAME(CreateRemoteAllocator);<br>
-  PROCNAME(CreateIndirectStubsOwner);<br>
-  PROCNAME(DeregisterEHFrames);<br>
-  PROCNAME(DestroyRemoteAllocator);<br>
-  PROCNAME(DestroyIndirectStubsOwner);<br>
-  PROCNAME(EmitIndirectStubs);<br>
-  PROCNAME(EmitIndirectStubsResponse);<br>
-  PROCNAME(EmitResolverBlock);<br>
-  PROCNAME(EmitTrampolineBlock);<br>
-  PROCNAME(EmitTrampolineBlockResponse);<br>
-  PROCNAME(GetSymbolAddress);<br>
-  PROCNAME(GetSymbolAddressResponse);<br>
-  PROCNAME(GetRemoteInfo);<br>
-  PROCNAME(GetRemoteInfoResponse);<br>
-  PROCNAME(ReadMem);<br>
-  PROCNAME(ReadMemResponse);<br>
-  PROCNAME(RegisterEHFrames);<br>
-  PROCNAME(ReserveMem);<br>
-  PROCNAME(ReserveMemResponse);<br>
-  PROCNAME(RequestCompile);<br>
-  PROCNAME(RequestCompileResponse);<br>
-  PROCNAME(SetProtections);<br>
-  PROCNAME(TerminateSession);<br>
-  PROCNAME(WriteMem);<br>
-  PROCNAME(WritePtr);<br>
+    return "*** Invalid JITFuncId ***";<br>
+  FUNCNAME(CallIntVoid);<br>
+  FUNCNAME(CallMain);<br>
+  FUNCNAME(CallVoidVoid);<br>
+  FUNCNAME(CreateRemoteAllocator);<br>
+  FUNCNAME(CreateIndirectStubsOwner);<br>
+  FUNCNAME(DeregisterEHFrames);<br>
+  FUNCNAME(DestroyRemoteAllocator);<br>
+  FUNCNAME(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 PROCNAME<br>
+#undef FUNCNAME<br>
<br>
 } // end namespace remote<br>
 } // end namespace orc<br>
<br>
Modified: llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp (original)<br>
+++ llvm/trunk/tools/lli/ChildTarget/ChildTarget.cpp Sun Apr 17 20:06:49 2016<br>
@@ -54,8 +54,8 @@ int main(int argc, char *argv[]) {<br>
   JITServer Server(Channel, SymbolLookup, RegisterEHFrames, DeregisterEHFrames);<br>
<br>
   while (1) {<br>
-    JITServer::JITProcId Id = JITServer::InvalidId;<br>
-    if (auto EC = Server.getNextProcId(Id)) {<br>
+    JITServer::JITFuncId Id = JITServer::InvalidId;<br>
+    if (auto EC = Server.getNextFuncId(Id)) {<br>
       errs() << "Error: " << EC.message() << "\n";<br>
       return 1;<br>
     }<br>
@@ -63,7 +63,7 @@ int main(int argc, char *argv[]) {<br>
     case JITServer::TerminateSessionId:<br>
       return 0;<br>
     default:<br>
-      if (auto EC = Server.handleKnownProcedure(Id)) {<br>
+      if (auto EC = Server.handleKnownFunction(Id)) {<br>
         errs() << "Error: " << EC.message() << "\n";<br>
         return 1;<br>
       }<br>
<br>
Modified: llvm/trunk/tools/lli/RemoteJITUtils.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RemoteJITUtils.h?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RemoteJITUtils.h?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/lli/RemoteJITUtils.h (original)<br>
+++ llvm/trunk/tools/lli/RemoteJITUtils.h Sun Apr 17 20:06:49 2016<br>
@@ -16,6 +16,7 @@<br>
<br>
 #include "llvm/ExecutionEngine/Orc/RPCChannel.h"<br>
 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"<br>
+#include <mutex><br>
<br>
 #if !defined(_MSC_VER) && !defined(__MINGW32__)<br>
 #include <unistd.h><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=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/lli.cpp?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/lli/lli.cpp (original)<br>
+++ llvm/trunk/tools/lli/lli.cpp Sun Apr 17 20:06:49 2016<br>
@@ -582,7 +582,7 @@ int main(int argc, char **argv, char * c<br>
   // Reset errno to zero on entry to main.<br>
   errno = 0;<br>
<br>
-  int Result;<br>
+  int Result = -1;<br>
<br>
   // Sanity check use of remote-jit: LLI currently only supports use of the<br>
   // remote JIT on Unix platforms.<br>
@@ -681,12 +681,13 @@ int main(int argc, char **argv, char * c<br>
     static_cast<ForwardingMemoryManager*>(RTDyldMM)->setResolver(<br>
       orc::createLambdaResolver(<br>
         [&](const std::string &Name) {<br>
-          orc::TargetAddress Addr = 0;<br>
-          if (auto EC = R->getSymbolAddress(Addr, Name)) {<br>
-            errs() << "Failure during symbol lookup: " << EC.message() << "\n";<br>
-            exit(1);<br>
-          }<br>
-          return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);<br>
+          if (auto AddrOrErr = R->getSymbolAddress(Name))<br>
+           return RuntimeDyld::SymbolInfo(*AddrOrErr, JITSymbolFlags::Exported);<br>
+         else {<br>
+           errs() << "Failure during symbol lookup: "<br>
+                  << AddrOrErr.getError().message() << "\n";<br>
+           exit(1);<br>
+         }<br>
         },<br>
         [](const std::string &Name) { return nullptr; }<br>
       ));<br>
@@ -698,8 +699,10 @@ 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>
-    if (auto EC = R->callIntVoid(Result, Entry))<br>
-      errs() << "ERROR: " << EC.message() << "\n";<br>
+    if (auto ResultOrErr = R->callIntVoid(Entry))<br>
+      Result = *ResultOrErr;<br>
+    else<br>
+      errs() << "ERROR: " << ResultOrErr.getError().message() << "\n";<br>
<br>
     // Like static constructors, the remote target MCJIT support doesn't handle<br>
     // this yet. It could. FIXME.<br>
<br>
Modified: llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp?rev=266581&r1=266580&r2=266581&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp?rev=266581&r1=266580&r2=266581&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp (original)<br>
+++ llvm/trunk/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp Sun Apr 17 20:06:49 2016<br>
@@ -44,26 +44,25 @@ private:<br>
 class DummyRPC : public testing::Test,<br>
                  public RPC<QueueChannel> {<br>
 public:<br>
-  typedef Procedure<1, void(bool)> Proc1;<br>
-  typedef Procedure<2, void(int8_t, uint8_t, int16_t, uint16_t,<br>
-                            int32_t, uint32_t, int64_t, uint64_t,<br>
-                            bool, std::string, std::vector<int>)> AllTheTypes;<br>
+  typedef Function<2, void(bool)> BasicVoid;<br>
+  typedef Function<3, int32_t(bool)> BasicInt;<br>
+  typedef Function<4, void(int8_t, uint8_t, int16_t, uint16_t,<br>
+                           int32_t, uint32_t, int64_t, uint64_t,<br>
+                           bool, std::string, std::vector<int>)> AllTheTypes;<br>
 };<br>
<br>
<br>
-TEST_F(DummyRPC, TestBasic) {<br>
+TEST_F(DummyRPC, TestAsyncBasicVoid) {<br>
   std::queue<char> Queue;<br>
   QueueChannel C(Queue);<br>
<br>
-  {<br>
-    // Make a call to Proc1.<br>
-    auto EC = call<Proc1>(C, true);<br>
-    EXPECT_FALSE(EC) << "Simple call over queue failed";<br>
-  }<br>
+  // Make an async call.<br>
+  auto ResOrErr = callAsync<BasicVoid>(C, true);<br>
+  EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";<br>
<br>
   {<br>
     // Expect a call to Proc1.<br>
-    auto EC = expect<Proc1>(C,<br>
+    auto EC = expect<BasicVoid>(C,<br>
                 [&](bool &B) {<br>
                   EXPECT_EQ(B, true)<br>
                     << "Bool serialization broken";<br>
@@ -71,31 +70,71 @@ TEST_F(DummyRPC, TestBasic) {<br>
                 });<br>
     EXPECT_FALSE(EC) << "Simple expect over queue failed";<br>
   }<br>
+<br>
+  {<br>
+    // Wait for the result.<br>
+    auto EC = waitForResult(C, ResOrErr->second, handleNone);<br>
+    EXPECT_FALSE(EC) << "Could not read result.";<br>
+  }<br>
+<br>
+  // Verify that the function returned ok.<br>
+  auto Val = ResOrErr->first.get();<br>
+  EXPECT_TRUE(Val) << "Remote void function failed to execute.";<br>
 }<br>
<br>
-TEST_F(DummyRPC, TestSerialization) {<br>
+TEST_F(DummyRPC, TestAsyncBasicInt) {<br>
   std::queue<char> Queue;<br>
   QueueChannel C(Queue);<br>
<br>
+  // Make an async call.<br>
+  auto ResOrErr = callAsync<BasicInt>(C, false);<br>
+  EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";<br>
+<br>
   {<br>
-    // Make a call to Proc1.<br>
-    std::vector<int> v({42, 7});<br>
-    auto EC = call<AllTheTypes>(C,<br>
-                                -101,<br>
-                                250,<br>
-                                -10000,<br>
-                                10000,<br>
-                                -1000000000,<br>
-                                1000000000,<br>
-                                -10000000000,<br>
-                                10000000000,<br>
-                                true,<br>
-                                "foo",<br>
-                                v);<br>
-    EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";<br>
+    // Expect a call to Proc1.<br>
+    auto EC = expect<BasicInt>(C,<br>
+                [&](bool &B) {<br>
+                  EXPECT_EQ(B, false)<br>
+                    << "Bool serialization broken";<br>
+                  return 42;<br>
+                });<br>
+    EXPECT_FALSE(EC) << "Simple expect over queue failed";<br>
   }<br>
<br>
   {<br>
+    // Wait for the result.<br>
+    auto EC = waitForResult(C, ResOrErr->second, handleNone);<br>
+    EXPECT_FALSE(EC) << "Could not read result.";<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>
+}<br>
+<br>
+TEST_F(DummyRPC, TestSerialization) {<br>
+  std::queue<char> Queue;<br>
+  QueueChannel C(Queue);<br>
+<br>
+  // Make a call to Proc1.<br>
+  std::vector<int> v({42, 7});<br>
+  auto ResOrErr = callAsync<AllTheTypes>(C,<br>
+                                         -101,<br>
+                                         250,<br>
+                                         -10000,<br>
+                                         10000,<br>
+                                         -1000000000,<br>
+                                         1000000000,<br>
+                                         -10000000000,<br>
+                                         10000000000,<br>
+                                         true,<br>
+                                         "foo",<br>
+                                         v);<br>
+  EXPECT_TRUE(!!ResOrErr)<br>
+    << "Big (serialization test) call over queue failed";<br>
+<br>
+  {<br>
     // Expect a call to Proc1.<br>
     auto EC = expect<AllTheTypes>(C,<br>
                 [&](int8_t &s8,<br>
@@ -136,4 +175,14 @@ TEST_F(DummyRPC, TestSerialization) {<br>
                   });<br>
     EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";<br>
   }<br>
+<br>
+  {<br>
+    // Wait for the result.<br>
+    auto EC = waitForResult(C, ResOrErr->second, handleNone);<br>
+    EXPECT_FALSE(EC) << "Could not read result.";<br>
+  }<br>
+<br>
+  // Verify that the function returned ok.<br>
+  auto Val = ResOrErr->first.get();<br>
+  EXPECT_TRUE(Val) << "Remote void function failed to execute.";<br>
 }<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">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/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>
</blockquote></div><br></div>