llvm.org GIT mirror llvm / bd1968a
[ORC] Generalize the ORC RPC utils to support RPC function return values and asynchronous call/handle. Also updates the ORC remote JIT API to use the new scheme. The previous version of the RPC tools only supported void functions, and required the user to manually call a paired function to return results. This patch replaces the Procedure typedef (which only supported void functions) with the Function typedef which supports return values, e.g.: Function<FooId, int32_t(std::string)> Foo; The RPC primitives and channel operations are also expanded. RPC channels must support four new operations: startSendMessage, endSendMessage, startRecieveMessage and endRecieveMessage, to handle channel locking. In addition, serialization support for tuples to RPCChannels is added to enable multiple return values. The RPC primitives are expanded from callAppend, call, expect and handle, to: appendCallAsync - Make an asynchronous call to the given function. callAsync - The same as appendCallAsync, but calls send on the channel when done. callSTHandling - Blocking call for single-threaded code. Wraps a call to callAsync then waits on the result, using a user-supplied handler to handle any callbacks from the remote. callST - The same as callSTHandling, except that it doesn't handle callbacks - it expects the result to be the first return. expect and handle - as before. handleResponse - Handle a response from the remote. waitForResult - Wait for the response with the given sequence number to arrive. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@266581 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 4 years ago
12 changed file(s) with 928 addition(s) and 511 deletion(s). Raw diff Collapse all Expand all
2525 RemoteMProtectAddrUnrecognized,
2626 RemoteIndirectStubsOwnerDoesNotExist,
2727 RemoteIndirectStubsOwnerIdAlreadyInUse,
28 UnexpectedRPCCall
28 UnexpectedRPCCall,
29 UnexpectedRPCResponse,
2930 };
3031
3132 std::error_code orcError(OrcErrorCode ErrCode);
3535 template
3636 class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
3737 public:
38
3839 /// Remote memory manager.
3940 class RCMemoryManager : public RuntimeDyld::MemoryManager {
4041 public:
104105 DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
105106
106107 if (CodeSize != 0) {
107 std::error_code EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr,
108 Id, CodeSize, CodeAlign);
109 // FIXME; Add error to poll.
110 assert(!EC && "Failed reserving remote memory.");
111 (void)EC;
108 if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign))
109 Unmapped.back().RemoteCodeAddr = *AddrOrErr;
110 else {
111 // FIXME; Add error to poll.
112 assert(!AddrOrErr.getError() && "Failed reserving remote memory.");
113 }
114
112115 DEBUG(dbgs() << " code: "
113116 << format("0x%016x", Unmapped.back().RemoteCodeAddr)
114117 << " (" << CodeSize << " bytes, alignment " << CodeAlign
116119 }
117120
118121 if (RODataSize != 0) {
119 std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr,
120 Id, RODataSize, RODataAlign);
121 // FIXME; Add error to poll.
122 assert(!EC && "Failed reserving remote memory.");
123 (void)EC;
122 if (auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign))
123 Unmapped.back().RemoteRODataAddr = *AddrOrErr;
124 else {
125 // FIXME; Add error to poll.
126 assert(!AddrOrErr.getError() && "Failed reserving remote memory.");
127 }
128
124129 DEBUG(dbgs() << " ro-data: "
125130 << format("0x%016x", Unmapped.back().RemoteRODataAddr)
126131 << " (" << RODataSize << " bytes, alignment "
128133 }
129134
130135 if (RWDataSize != 0) {
131 std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr,
132 Id, RWDataSize, RWDataAlign);
133 // FIXME; Add error to poll.
134 assert(!EC && "Failed reserving remote memory.");
135 (void)EC;
136 if (auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign))
137 Unmapped.back().RemoteRWDataAddr = *AddrOrErr;
138 else {
139 // FIXME; Add error to poll.
140 assert(!AddrOrErr.getError() && "Failed reserving remote memory.");
141 }
142
136143 DEBUG(dbgs() << " rw-data: "
137144 << format("0x%016x", Unmapped.back().RemoteRWDataAddr)
138145 << " (" << RWDataSize << " bytes, alignment "
430437 TargetAddress PtrBase;
431438 unsigned NumStubsEmitted;
432439
433 Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id,
434 NewStubsRequired);
440 if (auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired))
441 std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
442 else
443 return StubInfoOrErr.getError();
435444
436445 unsigned NewBlockId = RemoteIndirectStubsInfos.size();
437446 RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
483492 void grow() override {
484493 TargetAddress BlockAddr = 0;
485494 uint32_t NumTrampolines = 0;
486 auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines);
487 assert(!EC && "Failed to create trampolines");
495 if (auto TrampolineInfoOrErr = Remote.emitTrampolineBlock())
496 std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
497 else {
498 // FIXME: Return error.
499 llvm_unreachable("Failed to create trampolines");
500 }
488501
489502 uint32_t TrampolineSize = Remote.getTrampolineSize();
490503 for (unsigned I = 0; I < NumTrampolines; ++I)
502515 OrcRemoteTargetClient H(Channel, EC);
503516 if (EC)
504517 return EC;
505 return H;
518 return ErrorOr(std::move(H));
506519 }
507520
508521 /// Call the int(void) function at the given address in the target and return
509522 /// its result.
510 std::error_code callIntVoid(int &Result, TargetAddress Addr) {
523 ErrorOr callIntVoid(TargetAddress Addr) {
511524 DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
512525
513 if (auto EC = call(Channel, Addr))
514 return EC;
515
516 unsigned NextProcId;
517 if (auto EC = listenForCompileRequests(NextProcId))
518 return EC;
519
520 if (NextProcId != CallIntVoidResponseId)
521 return orcError(OrcErrorCode::UnexpectedRPCCall);
522
523 return handle(Channel, [&](int R) {
524 Result = R;
525 DEBUG(dbgs() << "Result: " << R << "\n");
526 return std::error_code();
527 });
526 auto Listen =
527 [&](RPCChannel &C, uint32_t Id) {
528 return listenForCompileRequests(C, Id);
529 };
530 return callSTHandling(Channel, Listen, Addr);
528531 }
529532
530533 /// Call the int(int, char*[]) function at the given address in the target and
531534 /// return its result.
532 std::error_code callMain(int &Result, TargetAddress Addr,
533 const std::vector &Args) {
535 ErrorOr callMain(TargetAddress Addr,
536 const std::vector &Args) {
534537 DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
535538 << "\n");
536539
537 if (auto EC = call(Channel, Addr, Args))
538 return EC;
539
540 unsigned NextProcId;
541 if (auto EC = listenForCompileRequests(NextProcId))
542 return EC;
543
544 if (NextProcId != CallMainResponseId)
545 return orcError(OrcErrorCode::UnexpectedRPCCall);
546
547 return handle(Channel, [&](int R) {
548 Result = R;
549 DEBUG(dbgs() << "Result: " << R << "\n");
550 return std::error_code();
551 });
540 auto Listen =
541 [&](RPCChannel &C, uint32_t Id) {
542 return listenForCompileRequests(C, Id);
543 };
544 return callSTHandling(Channel, Listen, Addr, Args);
552545 }
553546
554547 /// Call the void() function at the given address in the target and wait for
557550 DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
558551 << "\n");
559552
560 if (auto EC = call(Channel, Addr))
561 return EC;
562
563 unsigned NextProcId;
564 if (auto EC = listenForCompileRequests(NextProcId))
565 return EC;
566
567 if (NextProcId != CallVoidVoidResponseId)
568 return orcError(OrcErrorCode::UnexpectedRPCCall);
569
570 return handle(Channel, doNothing);
553 auto Listen =
554 [&](RPCChannel &C, JITFuncId Id) {
555 return listenForCompileRequests(C, Id);
556 };
557 return callSTHandling(Channel, Listen, Addr);
571558 }
572559
573560 /// Create an RCMemoryManager which will allocate its memory on the remote
577564 assert(!MM && "MemoryManager should be null before creation.");
578565
579566 auto Id = AllocatorIds.getNext();
580 if (auto EC = call(Channel, Id))
567 if (auto EC = callST(Channel, Id))
581568 return EC;
582569 MM = llvm::make_unique(*this, Id);
583570 return std::error_code();
589576 createIndirectStubsManager(std::unique_ptr &I) {
590577 assert(!I && "Indirect stubs manager should be null before creation.");
591578 auto Id = IndirectStubOwnerIds.getNext();
592 if (auto EC = call(Channel, Id))
579 if (auto EC = callST(Channel, Id))
593580 return EC;
594581 I = llvm::make_unique(*this, Id);
595582 return std::error_code();
598585 /// Search for symbols in the remote process. Note: This should be used by
599586 /// symbol resolvers *after* they've searched the local symbol table in the
600587 /// JIT stack.
601 std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) {
588 ErrorOr getSymbolAddress(StringRef Name) {
602589 // Check for an 'out-of-band' error, e.g. from an MM destructor.
603590 if (ExistingError)
604591 return ExistingError;
605592
606 // Request remote symbol address.
607 if (auto EC = call(Channel, Name))
608 return EC;
609
610 return expect(Channel, [&](TargetAddress &A) {
611 Addr = A;
612 DEBUG(dbgs() << "Remote address lookup " << Name << " = "
613 << format("0x%016x", Addr) << "\n");
614 return std::error_code();
615 });
593 return callST(Channel, Name);
616594 }
617595
618596 /// Get the triple for the remote target.
619597 const std::string &getTargetTriple() const { return RemoteTargetTriple; }
620598
621 std::error_code terminateSession() { return call(Channel); }
599 std::error_code terminateSession() {
600 return callST(Channel);
601 }
622602
623603 private:
624604 OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC)
625605 : Channel(Channel) {
626 if ((EC = call(Channel)))
627 return;
628
629 EC = expect(
630 Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
631 RemoteTrampolineSize, RemoteIndirectStubSize));
606 if (auto RIOrErr = callST(Channel)) {
607 std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
608 RemoteTrampolineSize, RemoteIndirectStubSize) =
609 *RIOrErr;
610 EC = std::error_code();
611 } else
612 EC = RIOrErr.getError();
632613 }
633614
634615 std::error_code deregisterEHFrames(TargetAddress Addr, uint32_t Size) {
635 return call(Channel, Addr, Size);
616 return callST(Channel, Addr, Size);
636617 }
637618
638619 void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
639 if (auto EC = call(Channel, Id)) {
620 if (auto EC = callST(Channel, Id)) {
640621 // FIXME: This will be triggered by a removeModuleSet call: Propagate
641622 // error return up through that.
642623 llvm_unreachable("Failed to destroy remote allocator.");
646627
647628 std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
648629 IndirectStubOwnerIds.release(Id);
649 return call(Channel, Id);
650 }
651
652 std::error_code emitIndirectStubs(TargetAddress &StubBase,
653 TargetAddress &PtrBase,
654 uint32_t &NumStubsEmitted,
655 ResourceIdMgr::ResourceId Id,
656 uint32_t NumStubsRequired) {
657 if (auto EC = call(Channel, Id, NumStubsRequired))
658 return EC;
659
660 return expect(
661 Channel, readArgs(StubBase, PtrBase, NumStubsEmitted));
630 return callST(Channel, Id);
631 }
632
633 ErrorOr>
634 emitIndirectStubs(ResourceIdMgr::ResourceId Id,
635 uint32_t NumStubsRequired) {
636 return callST(Channel, Id, NumStubsRequired);
662637 }
663638
664639 std::error_code emitResolverBlock() {
666641 if (ExistingError)
667642 return ExistingError;
668643
669 return call(Channel);
670 }
671
672 std::error_code emitTrampolineBlock(TargetAddress &BlockAddr,
673 uint32_t &NumTrampolines) {
644 return callST(Channel);
645 }
646
647 ErrorOr>
648 emitTrampolineBlock() {
674649 // Check for an 'out-of-band' error, e.g. from an MM destructor.
675650 if (ExistingError)
676651 return ExistingError;
677652
678 if (auto EC = call(Channel))
679 return EC;
680
681 return expect(
682 Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) {
683 BlockAddr = BAddr;
684 NumTrampolines = NTrampolines;
685 return std::error_code();
686 });
653 return callST(Channel);
687654 }
688655
689656 uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
692659
693660 uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
694661
695 std::error_code listenForCompileRequests(uint32_t &NextId) {
662 std::error_code listenForCompileRequests(RPCChannel &C, uint32_t &Id) {
696663 // Check for an 'out-of-band' error, e.g. from an MM destructor.
697664 if (ExistingError)
698665 return ExistingError;
699666
700 if (auto EC = getNextProcId(Channel, NextId))
701 return EC;
702
703 while (NextId == RequestCompileId) {
704 TargetAddress TrampolineAddr = 0;
705 if (auto EC = handle(Channel, readArgs(TrampolineAddr)))
667 if (Id == RequestCompileId) {
668 if (auto EC = handle(C, CompileCallback))
706669 return EC;
707
708 TargetAddress ImplAddr = CompileCallback(TrampolineAddr);
709 if (auto EC = call(Channel, ImplAddr))
710 return EC;
711
712 if (auto EC = getNextProcId(Channel, NextId))
713 return EC;
714 }
715
716 return std::error_code();
717 }
718
719 std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) {
670 return std::error_code();
671 }
672 // else
673 return orcError(OrcErrorCode::UnexpectedRPCCall);
674 }
675
676 ErrorOr> readMem(char *Dst, TargetAddress Src, uint64_t Size) {
720677 // Check for an 'out-of-band' error, e.g. from an MM destructor.
721678 if (ExistingError)
722679 return ExistingError;
723680
724 if (auto EC = call(Channel, Src, Size))
725 return EC;
726
727 if (auto EC = expect(
728 Channel, [&]() { return Channel.readBytes(Dst, Size); }))
729 return EC;
730
731 return std::error_code();
681 return callST(Channel, Src, Size);
732682 }
733683
734684 std::error_code registerEHFrames(TargetAddress &RAddr, uint32_t Size) {
735 return call(Channel, RAddr, Size);
736 }
737
738 std::error_code reserveMem(TargetAddress &RemoteAddr,
739 ResourceIdMgr::ResourceId Id, uint64_t Size,
740 uint32_t Align) {
685 return callST(Channel, RAddr, Size);
686 }
687
688 ErrorOr reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
689 uint32_t Align) {
741690
742691 // Check for an 'out-of-band' error, e.g. from an MM destructor.
743692 if (ExistingError)
744693 return ExistingError;
745694
746 if (std::error_code EC = call(Channel, Id, Size, Align))
747 return EC;
748
749 return expect(Channel, readArgs(RemoteAddr));
695 return callST(Channel, Id, Size, Align);
750696 }
751697
752698 std::error_code setProtections(ResourceIdMgr::ResourceId Id,
753699 TargetAddress RemoteSegAddr,
754700 unsigned ProtFlags) {
755 return call(Channel, Id, RemoteSegAddr, ProtFlags);
701 return callST(Channel, Id, RemoteSegAddr, ProtFlags);
756702 }
757703
758704 std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {
760706 if (ExistingError)
761707 return ExistingError;
762708
763 // Make the send call.
764 if (auto EC = call(Channel, Addr, Size))
765 return EC;
766
767 // Follow this up with the section contents.
768 if (auto EC = Channel.appendBytes(Src, Size))
769 return EC;
770
771 return Channel.send();
709 return callST(Channel, DirectBufferWriter(Src, Addr, Size));
772710 }
773711
774712 std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) {
776714 if (ExistingError)
777715 return ExistingError;
778716
779 return call(Channel, Addr, PtrVal);
717 return callST(Channel, Addr, PtrVal);
780718 }
781719
782720 static std::error_code doNothing() { return std::error_code(); }
2323 namespace orc {
2424 namespace remote {
2525
26 class DirectBufferWriter {
27 public:
28 DirectBufferWriter() = default;
29 DirectBufferWriter(const char *Src, TargetAddress Dst, uint64_t Size)
30 : Src(Src), Dst(Dst), Size(Size) {}
31
32 const char *getSrc() const { return Src; }
33 TargetAddress getDst() const { return Dst; }
34 uint64_t getSize() const { return Size; }
35 private:
36 const char *Src;
37 TargetAddress Dst;
38 uint64_t Size;
39 };
40
41 inline std::error_code serialize(RPCChannel &C,
42 const DirectBufferWriter &DBW) {
43 if (auto EC = serialize(C, DBW.getDst()))
44 return EC;
45 if (auto EC = serialize(C, DBW.getSize()))
46 return EC;
47 return C.appendBytes(DBW.getSrc(), DBW.getSize());
48 }
49
50 inline std::error_code deserialize(RPCChannel &C,
51 DirectBufferWriter &DBW) {
52 TargetAddress Dst;
53 if (auto EC = deserialize(C, Dst))
54 return EC;
55 uint64_t Size;
56 if (auto EC = deserialize(C, Size))
57 return EC;
58 char *Addr = reinterpret_cast(static_cast(Dst));
59
60 DBW = DirectBufferWriter(0, Dst, Size);
61
62 return C.readBytes(Addr, Size);
63 }
64
2665 class OrcRemoteTargetRPCAPI : public RPC {
2766 protected:
67
2868 class ResourceIdMgr {
2969 public:
3070 typedef uint64_t ResourceId;
4484 };
4585
4686 public:
47 enum JITProcId : uint32_t {
48 InvalidId = 0,
49 CallIntVoidId,
50 CallIntVoidResponseId,
87 enum JITFuncId : uint32_t {
88 InvalidId = RPCFunctionIdTraits::InvalidId,
89 CallIntVoidId = RPCFunctionIdTraits::FirstValidId,
5190 CallMainId,
52 CallMainResponseId,
5391 CallVoidVoidId,
54 CallVoidVoidResponseId,
5592 CreateRemoteAllocatorId,
5693 CreateIndirectStubsOwnerId,
5794 DeregisterEHFramesId,
5895 DestroyRemoteAllocatorId,
5996 DestroyIndirectStubsOwnerId,
6097 EmitIndirectStubsId,
61 EmitIndirectStubsResponseId,
6298 EmitResolverBlockId,
6399 EmitTrampolineBlockId,
64 EmitTrampolineBlockResponseId,
65100 GetSymbolAddressId,
66 GetSymbolAddressResponseId,
67101 GetRemoteInfoId,
68 GetRemoteInfoResponseId,
69102 ReadMemId,
70 ReadMemResponseId,
71103 RegisterEHFramesId,
72104 ReserveMemId,
73 ReserveMemResponseId,
74105 RequestCompileId,
75 RequestCompileResponseId,
76106 SetProtectionsId,
77107 TerminateSessionId,
78108 WriteMemId,
79109 WritePtrId
80110 };
81111
82 static const char *getJITProcIdName(JITProcId Id);
83
84 typedef Procedure CallIntVoid;
85
86 typedef Procedure
87 CallIntVoidResponse;
88
89 typedef Procedure
90 std::vector Args)>
112 static const char *getJITFuncIdName(JITFuncId Id);
113
114 typedef Function CallIntVoid;
115
116 typedef Function
117 std::vector Args)>
91118 CallMain;
92119
93 typedef Procedure CallMainResponse;
94
95 typedef Procedure CallVoidVoid;
96
97 typedef Procedure CallVoidVoidResponse;
98
99 typedef Procedure
100 void(ResourceIdMgr::ResourceId AllocatorID)>
120 typedef Function CallVoidVoid;
121
122 typedef Function
123 void(ResourceIdMgr::ResourceId AllocatorID)>
101124 CreateRemoteAllocator;
102125
103 typedef Procedure
104 void(ResourceIdMgr::ResourceId StubOwnerID)>
126 typedef Function
127 void(ResourceIdMgr::ResourceId StubOwnerID)>
105128 CreateIndirectStubsOwner;
106129
107 typedef Procedure
108 void(TargetAddress Addr, uint32_t Size)>
130 typedef Function
131 void(TargetAddress Addr, uint32_t Size)>
109132 DeregisterEHFrames;
110133
111 typedef Procedure
112 void(ResourceIdMgr::ResourceId AllocatorID)>
134 typedef Function
135 void(ResourceIdMgr::ResourceId AllocatorID)>
113136 DestroyRemoteAllocator;
114137
115 typedef Procedure
116 void(ResourceIdMgr::ResourceId StubsOwnerID)>
138 typedef Function
139 void(ResourceIdMgr::ResourceId StubsOwnerID)>
117140 DestroyIndirectStubsOwner;
118141
119 typedef Procedure
120 void(ResourceIdMgr::ResourceId StubsOwnerID,
121 uint32_t NumStubsRequired)>
142 /// EmitIndirectStubs result is (StubsBase, PtrsBase, NumStubsEmitted).
143 typedef Function
144 std::tuple(
145 ResourceIdMgr::ResourceId StubsOwnerID,
146 uint32_t NumStubsRequired)>
122147 EmitIndirectStubs;
123148
124 typedef Procedure
125 void(TargetAddress StubsBaseAddr,
126 TargetAddress PtrsBaseAddr,
127 uint32_t NumStubsEmitted)>
128 EmitIndirectStubsResponse;
129
130 typedef Procedure EmitResolverBlock;
131
132 typedef Procedure EmitTrampolineBlock;
133
134 typedef Procedure
135 void(TargetAddress BlockAddr, uint32_t NumTrampolines)>
136 EmitTrampolineBlockResponse;
137
138 typedef Procedure
149 typedef Function EmitResolverBlock;
150
151 /// EmitTrampolineBlock result is (BlockAddr, NumTrampolines).
152 typedef Function
153 std::tuple()> EmitTrampolineBlock;
154
155 typedef Function
139156 GetSymbolAddress;
140157
141 typedef Procedure
142 GetSymbolAddressResponse;
143
144 typedef Procedure GetRemoteInfo;
145
146 typedef Procedure
147 void(std::string Triple, uint32_t PointerSize,
148 uint32_t PageSize, uint32_t TrampolineSize,
149 uint32_t IndirectStubSize)>
150 GetRemoteInfoResponse;
151
152 typedef Procedure
158 /// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize,
159 /// IndirectStubsSize).
160 typedef Function
161 std::tuple
162 uint32_t>()> GetRemoteInfo;
163
164 typedef Function
165 std::vector(TargetAddress Src, uint64_t Size)>
153166 ReadMem;
154167
155 typedef Procedure ReadMemResponse;
156
157 typedef Procedure
158 void(TargetAddress Addr, uint32_t Size)>
168 typedef Function
169 void(TargetAddress Addr, uint32_t Size)>
159170 RegisterEHFrames;
160171
161 typedef Procedure
162 void(ResourceIdMgr::ResourceId AllocID, uint64_t Size,
163 uint32_t Align)>
172 typedef Function
173 TargetAddress(ResourceIdMgr::ResourceId AllocID,
174 uint64_t Size, uint32_t Align)>
164175 ReserveMem;
165176
166 typedef Procedure
167 ReserveMemResponse;
168
169 typedef Procedure
177 typedef Function
178 TargetAddress(TargetAddress TrampolineAddr)>
170179 RequestCompile;
171180
172 typedef Procedure
173 RequestCompileResponse;
174
175 typedef Procedure
176 void(ResourceIdMgr::ResourceId AllocID, TargetAddress Dst,
177 uint32_t ProtFlags)>
181 typedef Function
182 void(ResourceIdMgr::ResourceId AllocID, TargetAddress Dst,
183 uint32_t ProtFlags)>
178184 SetProtections;
179185
180 typedef Procedure TerminateSession;
181
182 typedef Procedure
183 void(TargetAddress Dst, uint64_t Size /* Data to follow */)>
186 typedef Function TerminateSession;
187
188 typedef Function
184189 WriteMem;
185190
186 typedef Procedure
191 typedef Function
187192 WritePtr;
188193 };
189194
4444 EHFramesRegister(std::move(EHFramesRegister)),
4545 EHFramesDeregister(std::move(EHFramesDeregister)) {}
4646
47 std::error_code getNextProcId(JITProcId &Id) {
47 std::error_code getNextFuncId(JITFuncId &Id) {
4848 return deserialize(Channel, Id);
4949 }
5050
51 std::error_code handleKnownProcedure(JITProcId Id) {
51 std::error_code handleKnownFunction(JITFuncId Id) {
5252 typedef OrcRemoteTargetServer ThisT;
5353
54 DEBUG(dbgs() << "Handling known proc: " << getJITProcIdName(Id) << "\n");
54 DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) << "\n");
5555
5656 switch (Id) {
5757 case CallIntVoidId:
110110 llvm_unreachable("Unhandled JIT RPC procedure Id.");
111111 }
112112
113 std::error_code requestCompile(TargetAddress &CompiledFnAddr,
114 TargetAddress TrampolineAddr) {
115 if (auto EC = call(Channel, TrampolineAddr))
116 return EC;
117
118 while (1) {
119 JITProcId Id = InvalidId;
120 if (auto EC = getNextProcId(Id))
121 return EC;
122
123 switch (Id) {
124 case RequestCompileResponseId:
125 return handle(Channel,
126 readArgs(CompiledFnAddr));
127 default:
128 if (auto EC = handleKnownProcedure(Id))
129 return EC;
130 }
131 }
132
133 llvm_unreachable("Fell through request-compile command loop.");
113 ErrorOr requestCompile(TargetAddress TrampolineAddr) {
114 auto Listen =
115 [&](RPCChannel &C, uint32_t Id) {
116 return handleKnownFunction(static_cast(Id));
117 };
118
119 return callSTHandling(Channel, Listen, TrampolineAddr);
120 }
121
122 void handleTerminateSession() {
123 handle(Channel, [](){ return std::error_code(); });
134124 }
135125
136126 private:
174164 static std::error_code doNothing() { return std::error_code(); }
175165
176166 static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
177 TargetAddress CompiledFnAddr = 0;
178
179167 auto T = static_cast(JITTargetAddr);
180 auto EC = T->requestCompile(
181 CompiledFnAddr, static_cast(
182 reinterpret_cast(TrampolineAddr)));
183 assert(!EC && "Compile request failed");
184 (void)EC;
185 return CompiledFnAddr;
186 }
187
188 std::error_code handleCallIntVoid(TargetAddress Addr) {
168 auto AddrOrErr = T->requestCompile(
169 static_cast(
170 reinterpret_cast(TrampolineAddr)));
171 // FIXME: Allow customizable failure substitution functions.
172 assert(AddrOrErr && "Compile request failed");
173 return *AddrOrErr;
174 }
175
176 ErrorOr handleCallIntVoid(TargetAddress Addr) {
189177 typedef int (*IntVoidFnTy)();
190178 IntVoidFnTy Fn =
191179 reinterpret_cast(static_cast(Addr));
194182 int Result = Fn();
195183 DEBUG(dbgs() << " Result = " << Result << "\n");
196184
197 return call(Channel, Result);
198 }
199
200 std::error_code handleCallMain(TargetAddress Addr,
201 std::vector Args) {
185 return Result;
186 }
187
188 ErrorOr handleCallMain(TargetAddress Addr,
189 std::vector Args) {
202190 typedef int (*MainFnTy)(int, const char *[]);
203191
204192 MainFnTy Fn = reinterpret_cast(static_cast(Addr));
213201 int Result = Fn(ArgC, ArgV.get());
214202 DEBUG(dbgs() << " Result = " << Result << "\n");
215203
216 return call(Channel, Result);
204 return Result;
217205 }
218206
219207 std::error_code handleCallVoidVoid(TargetAddress Addr) {
225213 Fn();
226214 DEBUG(dbgs() << " Complete.\n");
227215
228 return call(Channel);
216 return std::error_code();
229217 }
230218
231219 std::error_code handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
272260 return std::error_code();
273261 }
274262
275 std::error_code handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
276 uint32_t NumStubsRequired) {
263 ErrorOr>
264 handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
265 uint32_t NumStubsRequired) {
277266 DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
278267 << " stubs.\n");
279268
295284 auto &BlockList = StubOwnerItr->second;
296285 BlockList.push_back(std::move(IS));
297286
298 return call(Channel, StubsBase, PtrsBase,
299 NumStubsEmitted);
287 return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted);
300288 }
301289
302290 std::error_code handleEmitResolverBlock() {
315303 sys::Memory::MF_EXEC);
316304 }
317305
318 std::error_code handleEmitTrampolineBlock() {
306 ErrorOr>
307 handleEmitTrampolineBlock() {
319308 std::error_code EC;
320309 auto TrampolineBlock =
321310 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
324313 if (EC)
325314 return EC;
326315
327 unsigned NumTrampolines =
316 uint32_t NumTrampolines =
328317 (sys::Process::getPageSize() - TargetT::PointerSize) /
329318 TargetT::TrampolineSize;
330319
338327
339328 TrampolineBlocks.push_back(std::move(TrampolineBlock));
340329
341 return call(
342 Channel,
343 static_cast(reinterpret_cast(TrampolineMem)),
344 NumTrampolines);
345 }
346
347 std::error_code handleGetSymbolAddress(const std::string &Name) {
330 auto TrampolineBaseAddr =
331 static_cast(reinterpret_cast(TrampolineMem));
332
333 return std::make_tuple(TrampolineBaseAddr, NumTrampolines);
334 }
335
336 ErrorOr handleGetSymbolAddress(const std::string &Name) {
348337 TargetAddress Addr = SymbolLookup(Name);
349338 DEBUG(dbgs() << " Symbol '" << Name << "' = " << format("0x%016x", Addr)
350339 << "\n");
351 return call(Channel, Addr);
352 }
353
354 std::error_code handleGetRemoteInfo() {
340 return Addr;
341 }
342
343 ErrorOr>
344 handleGetRemoteInfo() {
355345 std::string ProcessTriple = sys::getProcessTriple();
356346 uint32_t PointerSize = TargetT::PointerSize;
357347 uint32_t PageSize = sys::Process::getPageSize();
363353 << " page size = " << PageSize << "\n"
364354 << " trampoline size = " << TrampolineSize << "\n"
365355 << " indirect stub size = " << IndirectStubSize << "\n");
366 return call(Channel, ProcessTriple, PointerSize,
367 PageSize, TrampolineSize,
368 IndirectStubSize);
369 }
370
371 std::error_code handleReadMem(TargetAddress RSrc, uint64_t Size) {
356 return std::make_tuple(ProcessTriple, PointerSize, PageSize ,TrampolineSize,
357 IndirectStubSize);
358 }
359
360 ErrorOr>
361 handleReadMem(TargetAddress RSrc, uint64_t Size) {
372362 char *Src = reinterpret_cast(static_cast(RSrc));
373363
374364 DEBUG(dbgs() << " Reading " << Size << " bytes from "
375365 << format("0x%016x", RSrc) << "\n");
376366
377 if (auto EC = call(Channel))
378 return EC;
379
380 if (auto EC = Channel.appendBytes(Src, Size))
381 return EC;
382
383 return Channel.send();
367 std::vector Buffer;
368 Buffer.resize(Size);
369 for (char *P = Src; Size != 0; --Size)
370 Buffer.push_back(*P++);
371
372 return Buffer;
384373 }
385374
386375 std::error_code handleRegisterEHFrames(TargetAddress TAddr, uint32_t Size) {
391380 return std::error_code();
392381 }
393382
394 std::error_code handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
395 uint32_t Align) {
383 ErrorOr
384 handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
385 uint32_t Align) {
396386 auto I = Allocators.find(Id);
397387 if (I == Allocators.end())
398388 return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
407397 TargetAddress AllocAddr =
408398 static_cast(reinterpret_cast(LocalAllocAddr));
409399
410 return call(Channel, AllocAddr);
400 return AllocAddr;
411401 }
412402
413403 std::error_code handleSetProtections(ResourceIdMgr::ResourceId Id,
424414 return Allocator.setProtections(LocalAddr, Flags);
425415 }
426416
427 std::error_code handleWriteMem(TargetAddress RDst, uint64_t Size) {
428 char *Dst = reinterpret_cast(static_cast(RDst));
429 DEBUG(dbgs() << " Writing " << Size << " bytes to "
430 << format("0x%016x", RDst) << "\n");
431 return Channel.readBytes(Dst, Size);
417 std::error_code handleWriteMem(DirectBufferWriter DBW) {
418 DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to "
419 << format("0x%016x", DBW.getDst()) << "\n");
420 return std::error_code();
432421 }
433422
434423 std::error_code handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) {
44
55 #include "OrcError.h"
66 #include "llvm/ADT/ArrayRef.h"
7 #include "llvm/ADT/STLExtras.h"
78 #include "llvm/Support/Endian.h"
89
10 #include
911 #include
1012
1113 namespace llvm {
2527
2628 /// Flush the stream if possible.
2729 virtual std::error_code send() = 0;
30
31 /// Get the lock for stream reading.
32 std::mutex& getReadLock() { return readLock; }
33
34 /// Get the lock for stream writing.
35 std::mutex& getWriteLock() { return writeLock; }
36
37 private:
38 std::mutex readLock, writeLock;
2839 };
40
41 /// Notify the channel that we're starting a message send.
42 /// Locks the channel for writing.
43 inline std::error_code startSendMessage(RPCChannel &C) {
44 C.getWriteLock().lock();
45 return std::error_code();
46 }
47
48 /// Notify the channel that we're ending a message send.
49 /// Unlocks the channel for writing.
50 inline std::error_code endSendMessage(RPCChannel &C) {
51 C.getWriteLock().unlock();
52 return std::error_code();
53 }
54
55 /// Notify the channel that we're starting a message receive.
56 /// Locks the channel for reading.
57 inline std::error_code startReceiveMessage(RPCChannel &C) {
58 C.getReadLock().lock();
59 return std::error_code();
60 }
61
62 /// Notify the channel that we're ending a message receive.
63 /// Unlocks the channel for reading.
64 inline std::error_code endReceiveMessage(RPCChannel &C) {
65 C.getReadLock().unlock();
66 return std::error_code();
67 }
2968
3069 /// RPC channel serialization for a variadic list of arguments.
3170 template
32 std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) {
71 std::error_code serializeSeq(RPCChannel &C, const T &Arg, const Ts &... Args) {
3372 if (auto EC = serialize(C, Arg))
3473 return EC;
35 return serialize_seq(C, Args...);
74 return serializeSeq(C, Args...);
3675 }
3776
3877 /// RPC channel serialization for an (empty) variadic list of arguments.
39 inline std::error_code serialize_seq(RPCChannel &C) {
78 inline std::error_code serializeSeq(RPCChannel &C) {
4079 return std::error_code();
4180 }
4281
4382 /// RPC channel deserialization for a variadic list of arguments.
4483 template
45 std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) {
84 std::error_code deserializeSeq(RPCChannel &C, T &Arg, Ts &... Args) {
4685 if (auto EC = deserialize(C, Arg))
4786 return EC;
48 return deserialize_seq(C, Args...);
87 return deserializeSeq(C, Args...);
4988 }
5089
5190 /// RPC channel serialization for an (empty) variadic list of arguments.
52 inline std::error_code deserialize_seq(RPCChannel &C) {
91 inline std::error_code deserializeSeq(RPCChannel &C) {
5392 return std::error_code();
5493 }
5594
137176 return C.readBytes(&S[0], Count);
138177 }
139178
179 // Serialization helper for std::tuple.
180 template
181 inline std::error_code serializeTupleHelper(RPCChannel &C,
182 const TupleT &V,
183 llvm::index_sequence _) {
184 return serializeSeq(C, std::get(V)...);
185 }
186
187 /// RPC channel serialization for std::tuple.
188 template
189 inline std::error_code serialize(RPCChannel &C, const std::tuple &V) {
190 return serializeTupleHelper(C, V, llvm::index_sequence_for());
191 }
192
193 // Serialization helper for std::tuple.
194 template
195 inline std::error_code deserializeTupleHelper(RPCChannel &C,
196 TupleT &V,
197 llvm::index_sequence _) {
198 return deserializeSeq(C, std::get(V)...);
199 }
200
201 /// RPC channel deserialization for std::tuple.
202 template
203 inline std::error_code deserialize(RPCChannel &C, std::tuple &V) {
204 return deserializeTupleHelper(C, V, llvm::index_sequence_for());
205 }
206
140207 /// RPC channel serialization for ArrayRef.
141208 template
142209 std::error_code serialize(RPCChannel &C, const ArrayRef &A) {
1313 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
1414 #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
1515
16 #include "llvm/ADT/Optional.h"
1617 #include "llvm/ADT/STLExtras.h"
1718 #include "llvm/ExecutionEngine/Orc/OrcError.h"
19 #include "llvm/Support/ErrorOr.h"
20 #include
21 #include
1822
1923 namespace llvm {
2024 namespace orc {
2125 namespace remote {
26
27 /// Describes reserved RPC Function Ids.
28 ///
29 /// The default implementation will serve for integer and enum function id
30 /// types. If you want to use a custom type as your FunctionId you can
31 /// specialize this class and provide unique values for InvalidId,
32 /// ResponseId and FirstValidId.
33
34 template
35 class RPCFunctionIdTraits {
36 public:
37 constexpr static const T InvalidId = static_cast(0);
38 constexpr static const T ResponseId = static_cast(1);
39 constexpr static const T FirstValidId = static_cast(2);
40 };
2241
2342 // Base class containing utilities that require partial specialization.
2443 // These cannot be included in RPC, as template class members cannot be
2544 // partially specialized.
2645 class RPCBase {
2746 protected:
28 template
29 class ProcedureHelper {
30 public:
31 static const ProcedureIdT Id = ProcId;
32 };
33
34 template class CallHelper;
35
36 template
47
48 // RPC Function description type.
49 //
50 // This class provides the information and operations needed to support the
51 // RPC primitive operations (call, expect, etc) for a given function. It
52 // is specialized for void and non-void functions to deal with the differences
53 // betwen the two. Both specializations have the same interface:
54 //
55 // Id - The function's unique identifier.
56 // OptionalReturn - The return type for asyncronous calls.
57 // ErrorReturn - The return type for synchronous calls.
58 // optionalToErrorReturn - Conversion from a valid OptionalReturn to an
59 // ErrorReturn.
60 // readResult - Deserialize a result from a channel.
61 // abandon - Abandon a promised (asynchronous) result.
62 // respond - Retun a result on the channel.
63 template
64 class FunctionHelper {};
65
66 // RPC Function description specialization for non-void functions.
67 template
3768 typename... ArgTs>
38 class CallHelper
39 ProcedureHelper> {
40 public:
41 static std::error_code call(ChannelT &C, const ArgTs &... Args) {
42 if (auto EC = serialize(C, ProcId))
43 return EC;
44 // If you see a compile-error on this line you're probably calling a
45 // function with the wrong signature.
46 return serialize_seq(C, Args...);
47 }
48 };
49
50 template class HandlerHelper;
51
52 template
53 typename... ArgTs>
54 class HandlerHelper
55 ProcedureHelper> {
69 class FunctionHelper> {
70 public:
71
72 static_assert(FuncId != RPCFunctionIdTraits::InvalidId &&
73 FuncId != RPCFunctionIdTraits::ResponseId,
74 "Cannot define custom function with InvalidId or ResponseId. "
75 "Please use RPCFunctionTraits::FirstValidId.");
76
77 static const FunctionIdT Id = FuncId;
78
79 typedef Optional OptionalReturn;
80
81 typedef ErrorOr ErrorReturn;
82
83 static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) {
84 assert(V && "Return value not available");
85 return std::move(*V);
86 }
87
88 template
89 static std::error_code readResult(ChannelT &C,
90 std::promise &P) {
91 RetT Val;
92 auto EC = deserialize(C, Val);
93 // FIXME: Join error EC2 from endReceiveMessage with the deserialize
94 // error once we switch to using Error.
95 auto EC2 = endReceiveMessage(C);
96 (void)EC2;
97
98 if (EC) {
99 P.set_value(OptionalReturn());
100 return EC;
101 }
102 P.set_value(std::move(Val));
103 return std::error_code();
104 }
105
106 static void abandon(std::promise &P) {
107 P.set_value(OptionalReturn());
108 }
109
110 template
111 static std::error_code respond(ChannelT &C, SequenceNumberT SeqNo,
112 const ErrorReturn &Result) {
113 FunctionIdT ResponseId =
114 RPCFunctionIdTraits::ResponseId;
115
116 // If the handler returned an error then bail out with that.
117 if (!Result)
118 return Result.getError();
119
120 // Otherwise open a new message on the channel and send the result.
121 if (auto EC = startSendMessage(C))
122 return EC;
123 if (auto EC = serializeSeq(C, ResponseId, SeqNo, *Result))
124 return EC;
125 return endSendMessage(C);
126 }
127 };
128
129 // RPC Function description specialization for void functions.
130 template
131 class FunctionHelper {
132 public:
133
134 static_assert(FuncId != RPCFunctionIdTraits::InvalidId &&
135 FuncId != RPCFunctionIdTraits::ResponseId,
136 "Cannot define custom function with InvalidId or ResponseId. "
137 "Please use RPCFunctionTraits::FirstValidId.");
138
139 static const FunctionIdT Id = FuncId;
140
141 typedef bool OptionalReturn;
142 typedef std::error_code ErrorReturn;
143
144 static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) {
145 assert(V && "Return value not available");
146 return std::error_code();
147 }
148
149 template
150 static std::error_code readResult(ChannelT &C,
151 std::promise &P) {
152 // Void functions don't have anything to deserialize, so we're good.
153 P.set_value(true);
154 return endReceiveMessage(C);
155 }
156
157 static void abandon(std::promise &P) {
158 P.set_value(false);
159 }
160
161 template
162 static std::error_code respond(ChannelT &C, SequenceNumberT SeqNo,
163 const ErrorReturn &Result) {
164 const FunctionIdT ResponseId =
165 RPCFunctionIdTraits::ResponseId;
166
167 // If the handler returned an error then bail out with that.
168 if (Result)
169 return Result;
170
171 // Otherwise open a new message on the channel and send the result.
172 if (auto EC = startSendMessage(C))
173 return EC;
174 if (auto EC = serializeSeq(C, ResponseId, SeqNo))
175 return EC;
176 return endSendMessage(C);
177 }
178 };
179
180 // Helper for the call primitive.
181 template
182 class CallHelper;
183
184 template
185 FunctionIdT FuncId, typename RetT, typename... ArgTs>
186 class CallHelper
187 FunctionHelper> {
188 public:
189 static std::error_code call(ChannelT &C, SequenceNumberT SeqNo,
190 const ArgTs &... Args) {
191 if (auto EC = startSendMessage(C))
192 return EC;
193 if (auto EC = serializeSeq(C, FuncId, SeqNo, Args...))
194 return EC;
195 return endSendMessage(C);
196 }
197 };
198
199 // Helper for handle primitive.
200 template
201 class HandlerHelper;
202
203 template
204 FunctionIdT FuncId, typename RetT, typename... ArgTs>
205 class HandlerHelper
206 FunctionHelper> {
56207 public:
57208 template
58209 static std::error_code handle(ChannelT &C, HandlerT Handler) {
60211 }
61212
62213 private:
214
215 typedef FunctionHelper Func;
216
63217 template
64218 static std::error_code readAndHandle(ChannelT &C, HandlerT Handler,
65219 llvm::index_sequence _) {
66220 std::tuple RPCArgs;
221 SequenceNumberT SeqNo;
67222 // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
68223 // for RPCArgs. Void cast RPCArgs to work around this for now.
69224 // FIXME: Remove this workaround once we can assume a working GCC version.
70225 (void)RPCArgs;
71 if (auto EC = deserialize_seq(C, std::get(RPCArgs)...))
72 return EC;
73 return Handler(std::get(RPCArgs)...);
74 }
75 };
76
77 template class MemberFnWrapper {
78 public:
79 typedef std::error_code (ClassT::*MethodT)(ArgTs...);
226 if (auto EC = deserializeSeq(C, SeqNo, std::get(RPCArgs)...))
227 return EC;
228
229 // We've deserialized the arguments, so unlock the channel for reading
230 // before we call the handler. This allows recursive RPC calls.
231 if (auto EC = endReceiveMessage(C))
232 return EC;
233
234 return Func::template respond(
235 C, SeqNo, Handler(std::get(RPCArgs)...));
236 }
237
238 };
239
240 // Helper for wrapping member functions up as functors.
241 template
242 class MemberFnWrapper {
243 public:
244 typedef RetT(ClassT::*MethodT)(ArgTs...);
80245 MemberFnWrapper(ClassT &Instance, MethodT Method)
81246 : Instance(Instance), Method(Method) {}
82 std::error_code operator()(ArgTs &... Args) {
83 return (Instance.*Method)(Args...);
84 }
85
247 RetT operator()(ArgTs &... Args) { return (Instance.*Method)(Args...); }
86248 private:
87249 ClassT &Instance;
88250 MethodT Method;
89251 };
90252
253 // Helper that provides a Functor for deserializing arguments.
91254 template class ReadArgs {
92255 public:
93256 std::error_code operator()() { return std::error_code(); }
111274
112275 /// Contains primitive utilities for defining, calling and handling calls to
113276 /// remote procedures. ChannelT is a bidirectional stream conforming to the
114 /// RPCChannel interface (see RPCChannel.h), and ProcedureIdT is a procedure
277 /// RPCChannel interface (see RPCChannel.h), and FunctionIdT is a procedure
115278 /// identifier type that must be serializable on ChannelT.
116279 ///
117280 /// These utilities support the construction of very primitive RPC utilities.
128291 ///
129292 /// Overview (see comments individual types/methods for details):
130293 ///
131 /// Procedure :
294 /// Function :
132295 ///
133296 /// associates a unique serializable id with an argument list.
134297 ///
135298 ///
136 /// call(Channel, Args...) :
137 ///
138 /// Calls the remote procedure 'Proc' by serializing Proc's id followed by its
299 /// call(Channel, Args...) :
300 ///
301 /// Calls the remote procedure 'Func' by serializing Func's id followed by its
139302 /// arguments and sending the resulting bytes to 'Channel'.
140303 ///
141304 ///
142 /// handle(Channel, :
143 ///
144 /// Handles a call to 'Proc' by deserializing its arguments and calling the
145 /// given functor. This assumes that the id for 'Proc' has already been
305 /// handle(Channel, :
306 ///
307 /// Handles a call to 'Func' by deserializing its arguments and calling the
308 /// given functor. This assumes that the id for 'Func' has already been
146309 /// deserialized.
147310 ///
148 /// expect<Proc>(Channel, :
311 /// expect<Func>(Channel, :
149312 ///
150313 /// The same as 'handle', except that the procedure id should not have been
151 /// read yet. Expect will deserialize the id and assert that it matches Proc's
314 /// read yet. Expect will deserialize the id and assert that it matches Func's
152315 /// id. If it does not, and unexpected RPC call error is returned.
153
154 template ProcedureIdT = uint32_t>
316 template FunctionIdT = uint32_t,
317 typename SequenceNumberT = uint16_t>
155318 class RPC : public RPCBase {
156319 public:
320
321 RPC() = default;
322 RPC(const RPC&) = delete;
323 RPC& operator=(const RPC&) = delete;
324 RPC(RPC &&Other) : SequenceNumberMgr(std::move(Other.SequenceNumberMgr)), OutstandingResults(std::move(Other.OutstandingResults)) {}
325 RPC& operator=(RPC&&) = default;
326
157327 /// Utility class for defining/referring to RPC procedures.
158328 ///
159329 /// Typedefs of this utility are used when calling/handling remote procedures.
160330 ///
161 /// ProcId should be a unique value of ProcedureIdT (i.e. not used with any
162 /// other Procedure typedef in the RPC API being defined.
331 /// FuncId should be a unique value of FunctionIdT (i.e. not used with any
332 /// other Function typedef in the RPC API being defined.
163333 ///
164334 /// the template argument Ts... gives the argument list for the remote
165335 /// procedure.
166336 ///
167337 /// E.g.
168338 ///
169 /// typedef Procedure<0, bool> Proc1;
170 /// typedef Procedure<1, std::string, std::vector> Proc2;
171 ///
172 /// if (auto EC = call(Channel, true))
339 /// typedef Function<0, bool> Func1;
340 /// typedef Function<1, std::string, std::vector> Func2;
341 ///
342 /// if (auto EC = call(Channel, true))
173343 /// /* handle EC */;
174344 ///
175 /// if (auto EC = expect<Proc2>(Channel,
345 /// if (auto EC = expect<Func2>(Channel,
176346 /// [](std::string &S, std::vector &V) {
177347 /// // Stuff.
178348 /// return std::error_code();
179349 /// })
180350 /// /* handle EC */;
181351 ///
182 template
183 using Procedure = ProcedureHelper;
352 template
353 using Function = FunctionHelper;
354
355 /// Return type for asynchronous call primitives.
356 template
357 using AsyncCallResult =
358 std::pair, SequenceNumberT>;
184359
185360 /// Serialize Args... to channel C, but do not call C.send().
186361 ///
187 /// For buffered channels, this can be used to queue up several calls before
188 /// flushing the channel.
189 template
190 static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) {
191 return CallHelper::call(C, Args...);
362 /// For void functions returns a std::future. For functions that
363 /// return an R, returns a std::future>.
364 template
365 ErrorOr>
366 appendCallAsync(ChannelT &C, const ArgTs &... Args) {
367 auto SeqNo = SequenceNumberMgr.getSequenceNumber();
368 std::promise Promise;
369 auto Result = Promise.get_future();
370 OutstandingResults[SeqNo] = std::move(Promise);
371
372 if (auto EC =
373 CallHelper::call(C, SeqNo,
374 Args...)) {
375 abandonOutstandingResults();
376 return EC;
377 } else
378 return AsyncCallResult(std::move(Result), SeqNo);
192379 }
193380
194381 /// Serialize Args... to channel C and call C.send().
195 template
196 static std::error_code call(ChannelT &C, const ArgTs &... Args) {
197 if (auto EC = appendCall(C, Args...))
382 template
383 ErrorOr>
384 callAsync(ChannelT &C, const ArgTs &... Args) {
385 auto SeqNo = SequenceNumberMgr.getSequenceNumber();
386 std::promise Promise;
387 auto Result = Promise.get_future();
388 OutstandingResults[SeqNo] =
389 createOutstandingResult(std::move(Promise));
390 if (auto EC =
391 CallHelper::call(C, SeqNo, Args...)) {
392 abandonOutstandingResults();
198393 return EC;
199 return C.send();
200 }
201
202 /// Deserialize and return an enum whose underlying type is ProcedureIdT.
203 static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) {
394 }
395 if (auto EC = C.send()) {
396 abandonOutstandingResults();
397 return EC;
398 }
399 return AsyncCallResult(std::move(Result), SeqNo);
400 }
401
402 /// This can be used in single-threaded mode.
403 template
404 typename Func::ErrorReturn
405 callSTHandling(ChannelT &C, HandleFtor &HandleOther, const ArgTs &... Args) {
406 if (auto ResultAndSeqNoOrErr = callAsync(C, Args...)) {
407 auto &ResultAndSeqNo = *ResultAndSeqNoOrErr;
408 if (auto EC = waitForResult(C, ResultAndSeqNo.second, HandleOther))
409 return EC;
410 return Func::optionalToErrorReturn(ResultAndSeqNo.first.get());
411 } else
412 return ResultAndSeqNoOrErr.getError();
413 }
414
415 // This can be used in single-threaded mode.
416 template
417 typename Func::ErrorReturn
418 callST(ChannelT &C, const ArgTs &... Args) {
419 return callSTHandling(C, handleNone, Args...);
420 }
421
422 /// Start receiving a new function call.
423 ///
424 /// Calls startReceiveMessage on the channel, then deserializes a FunctionId
425 /// into Id.
426 std::error_code startReceivingFunction(ChannelT &C, FunctionIdT &Id) {
427 if (auto EC = startReceiveMessage(C))
428 return EC;
429
204430 return deserialize(C, Id);
205431 }
206432
207 /// Deserialize args for Proc from C and call Handler. The signature of
433 /// Deserialize args for Func from C and call Handler. The signature of
208434 /// handler must conform to 'std::error_code(Args...)' where Args... matches
209 /// the arguments used in the Proc typedef.
210 template
435 /// the arguments used in the Func typedef.
436 template
211437 static std::error_code handle(ChannelT &C, HandlerT Handler) {
212 return HandlerHelperProc>::handle(C, Handler);
438 return HandlerHelperSequenceNumberT, Func>::handle(C, Handler);
213439 }
214440
215441 /// Helper version of 'handle' for calling member functions.
216 template Proc, typename ClassT, typename... ArgTs>
442 template Func, typename ClassT, typename RetT, typename... ArgTs>
217443 static std::error_code
218444 handle(ChannelT &C, ClassT &Instance,
219 std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {
220 return handle(
221 C, MemberFnWrapper(Instance, HandlerMethod));
222 }
223
224 /// Deserialize a ProcedureIdT from C and verify it matches the id for Proc.
445 RetT (ClassT::*HandlerMethod)(ArgTs...)) {
446 return handle(
447 C,
448 MemberFnWrapper(Instance, HandlerMethod));
449 }
450
451 /// Deserialize a FunctionIdT from C and verify it matches the id for Func.
225452 /// If the id does match, deserialize the arguments and call the handler
226453 /// (similarly to handle).
227454 /// If the id does not match, return an unexpect RPC call error and do not
228455 /// deserialize any further bytes.
229 template
230 static std::error_code expect(ChannelT &C, HandlerT Handler) {
231 ProcedureIdT ProcId;
232 if (auto EC = getNextProcId(C, ProcId))
233 return EC;
234 if (ProcId != Proc::Id)
456 template
457 std::error_code expect(ChannelT &C, HandlerT Handler) {
458 FunctionIdT FuncId;
459 if (auto EC = startReceivingFunction(C, FuncId))
460 return std::move(EC);
461 if (FuncId != Func::Id)
235462 return orcError(OrcErrorCode::UnexpectedRPCCall);
236 return handle<Proc>(C, Handler);
463 return handle<Func>(C, Handler);
237464 }
238465
239466 /// Helper version of expect for calling member functions.
240 template Proc, typename ClassT, typename... ArgTs>
467 template Func, typename ClassT, typename... ArgTs>
241468 static std::error_code
242469 expect(ChannelT &C, ClassT &Instance,
243470 std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {
244 return expect<Proc>(
471 return expect<Func>(
245472 C, MemberFnWrapper(Instance, HandlerMethod));
246473 }
247474
250477 /// channel.
251478 /// E.g.
252479 ///
253 /// typedef Procedure<0, bool, int> Proc1;
480 /// typedef Function<0, bool, int> Func1;
254481 ///
255482 /// ...
256483 /// bool B;
257484 /// int I;
258 /// if (auto EC = expect<Proc1>(Channel, readArgs(B, I)))
485 /// if (auto EC = expect<Func1>(Channel, readArgs(B, I)))
259486 /// /* Handle Args */ ;
260487 ///
261488 template
262489 static ReadArgs readArgs(ArgTs &... Args) {
263490 return ReadArgs(Args...);
264491 }
492
493 /// Read a response from Channel.
494 /// This should be called from the receive loop to retrieve results.
495 std::error_code handleResponse(ChannelT &C, SequenceNumberT &SeqNo) {
496 if (auto EC = deserialize(C, SeqNo)) {
497 abandonOutstandingResults();
498 return EC;
499 }
500
501 auto I = OutstandingResults.find(SeqNo);
502 if (I == OutstandingResults.end()) {
503 abandonOutstandingResults();
504 return orcError(OrcErrorCode::UnexpectedRPCResponse);
505 }
506
507 if (auto EC = I->second->readResult(C)) {
508 abandonOutstandingResults();
509 // FIXME: Release sequence numbers?
510 return EC;
511 }
512
513 OutstandingResults.erase(I);
514 SequenceNumberMgr.releaseSequenceNumber(SeqNo);
515
516 return std::error_code();
517 }
518
519 // Loop waiting for a result with the given sequence number.
520 // This can be used as a receive loop if the user doesn't have a default.
521 template
522 std::error_code waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo,
523 HandleOtherFtor &HandleOther = handleNone) {
524 bool GotTgtResult = false;
525
526 while (!GotTgtResult) {
527 FunctionIdT Id =
528 RPCFunctionIdTraits::InvalidId;
529 if (auto EC = startReceivingFunction(C, Id))
530 return EC;
531 if (Id == RPCFunctionIdTraits::ResponseId) {
532 SequenceNumberT SeqNo;
533 if (auto EC = handleResponse(C, SeqNo))
534 return EC;
535 GotTgtResult = (SeqNo == TgtSeqNo);
536 } else if (auto EC = HandleOther(C, Id))
537 return EC;
538 }
539
540 return std::error_code();
541 };
542
543 // Default handler for 'other' (non-response) functions when waiting for a
544 // result from the channel.
545 static std::error_code handleNone(ChannelT&, FunctionIdT) {
546 return orcError(OrcErrorCode::UnexpectedRPCCall);
547 };
548
549 private:
550
551 // Manage sequence numbers.
552 class SequenceNumberManager {
553 public:
554
555 SequenceNumberManager() = default;
556
557 SequenceNumberManager(SequenceNumberManager &&Other)
558 : NextSequenceNumber(std::move(Other.NextSequenceNumber)),
559 FreeSequenceNumbers(std::move(Other.FreeSequenceNumbers)) {}
560
561 SequenceNumberManager& operator=(SequenceNumberManager &&Other) {
562 NextSequenceNumber = std::move(Other.NextSequenceNumber);
563 FreeSequenceNumbers = std::move(Other.FreeSequenceNumbers);
564 }
565
566 void reset() {
567 std::lock_guard Lock(SeqNoLock);
568 NextSequenceNumber = 0;
569 FreeSequenceNumbers.clear();
570 }
571
572 SequenceNumberT getSequenceNumber() {
573 std::lock_guard Lock(SeqNoLock);
574 if (FreeSequenceNumbers.empty())
575 return NextSequenceNumber++;
576 auto SequenceNumber = FreeSequenceNumbers.back();
577 FreeSequenceNumbers.pop_back();
578 return SequenceNumber;
579 }
580
581 void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
582 std::lock_guard Lock(SeqNoLock);
583 FreeSequenceNumbers.push_back(SequenceNumber);
584 }
585
586 private:
587 std::mutex SeqNoLock;
588 SequenceNumberT NextSequenceNumber = 0;
589 std::vector FreeSequenceNumbers;
590 };
591
592 // Base class for results that haven't been returned from the other end of the
593 // RPC connection yet.
594 class OutstandingResult {
595 public:
596 virtual ~OutstandingResult() {}
597 virtual std::error_code readResult(ChannelT &C) = 0;
598 virtual void abandon() = 0;
599 };
600
601 // Outstanding results for a specific function.
602 template
603 class OutstandingResultImpl : public OutstandingResult {
604 private:
605 public:
606 OutstandingResultImpl(std::promise &&P)
607 : P(std::move(P)) {}
608
609 std::error_code readResult(ChannelT &C) override {
610 return Func::readResult(C, P);
611 }
612
613 void abandon() override { Func::abandon(P); }
614
615 private:
616 std::promise P;
617 };
618
619 // Create an outstanding result for the given function.
620 template
621 std::unique_ptr
622 createOutstandingResult(std::promise &&P) {
623 return llvm::make_unique>(std::move(P));
624 }
625
626 // Abandon all outstanding results.
627 void abandonOutstandingResults() {
628 for (auto &KV : OutstandingResults)
629 KV.second->abandon();
630 OutstandingResults.clear();
631 SequenceNumberMgr.reset();
632 }
633
634 SequenceNumberManager SequenceNumberMgr;
635 std::map>
636 OutstandingResults;
265637 };
266638
267639 } // end namespace remote
3737 return "Remote indirect stubs owner Id already in use";
3838 case OrcErrorCode::UnexpectedRPCCall:
3939 return "Unexpected RPC call";
40 case OrcErrorCode::UnexpectedRPCResponse:
41 return "Unexpected RPC response";
4042 }
4143 llvm_unreachable("Unhandled error code");
4244 }
1212 namespace orc {
1313 namespace remote {
1414
15 #define PROCNAME(X) \
15 #define FUNCNAME(X) \
1616 case X ## Id: \
1717 return #X
1818
19 const char *OrcRemoteTargetRPCAPI::getJITProcIdName(JITProcId Id) {
19 const char *OrcRemoteTargetRPCAPI::getJITFuncIdName(JITFuncId Id) {
2020 switch (Id) {
2121 case InvalidId:
22 return "*** Invalid JITProcId ***";
23 PROCNAME(CallIntVoid);
24 PROCNAME(CallIntVoidResponse);
25 PROCNAME(CallMain);
26 PROCNAME(CallMainResponse);
27 PROCNAME(CallVoidVoid);
28 PROCNAME(CallVoidVoidResponse);
29 PROCNAME(CreateRemoteAllocator);
30 PROCNAME(CreateIndirectStubsOwner);
31 PROCNAME(DeregisterEHFrames);
32 PROCNAME(DestroyRemoteAllocator);
33 PROCNAME(DestroyIndirectStubsOwner);
34 PROCNAME(EmitIndirectStubs);
35 PROCNAME(EmitIndirectStubsResponse);
36 PROCNAME(EmitResolverBlock);
37 PROCNAME(EmitTrampolineBlock);
38 PROCNAME(EmitTrampolineBlockResponse);
39 PROCNAME(GetSymbolAddress);
40 PROCNAME(GetSymbolAddressResponse);
41 PROCNAME(GetRemoteInfo);
42 PROCNAME(GetRemoteInfoResponse);
43 PROCNAME(ReadMem);
44 PROCNAME(ReadMemResponse);
45 PROCNAME(RegisterEHFrames);
46 PROCNAME(ReserveMem);
47 PROCNAME(ReserveMemResponse);
48 PROCNAME(RequestCompile);
49 PROCNAME(RequestCompileResponse);
50 PROCNAME(SetProtections);
51 PROCNAME(TerminateSession);
52 PROCNAME(WriteMem);
53 PROCNAME(WritePtr);
22 return "*** Invalid JITFuncId ***";
23 FUNCNAME(CallIntVoid);
24 FUNCNAME(CallMain);
25 FUNCNAME(CallVoidVoid);
26 FUNCNAME(CreateRemoteAllocator);
27 FUNCNAME(CreateIndirectStubsOwner);
28 FUNCNAME(DeregisterEHFrames);
29 FUNCNAME(DestroyRemoteAllocator);
30 FUNCNAME(DestroyIndirectStubsOwner);
31 FUNCNAME(EmitIndirectStubs);
32 FUNCNAME(EmitResolverBlock);
33 FUNCNAME(EmitTrampolineBlock);
34 FUNCNAME(GetSymbolAddress);
35 FUNCNAME(GetRemoteInfo);
36 FUNCNAME(ReadMem);
37 FUNCNAME(RegisterEHFrames);
38 FUNCNAME(ReserveMem);
39 FUNCNAME(RequestCompile);
40 FUNCNAME(SetProtections);
41 FUNCNAME(TerminateSession);
42 FUNCNAME(WriteMem);
43 FUNCNAME(WritePtr);
5444 };
5545 return nullptr;
5646 }
5747
58 #undef PROCNAME
48 #undef FUNCNAME
5949
6050 } // end namespace remote
6151 } // end namespace orc
5353 JITServer Server(Channel, SymbolLookup, RegisterEHFrames, DeregisterEHFrames);
5454
5555 while (1) {
56 JITServer::JITProcId Id = JITServer::InvalidId;
57 if (auto EC = Server.getNextProcId(Id)) {
56 JITServer::JITFuncId Id = JITServer::InvalidId;
57 if (auto EC = Server.getNextFuncId(Id)) {
5858 errs() << "Error: " << EC.message() << "\n";
5959 return 1;
6060 }
6262 case JITServer::TerminateSessionId:
6363 return 0;
6464 default:
65 if (auto EC = Server.handleKnownProcedure(Id)) {
65 if (auto EC = Server.handleKnownFunction(Id)) {
6666 errs() << "Error: " << EC.message() << "\n";
6767 return 1;
6868 }
1515
1616 #include "llvm/ExecutionEngine/Orc/RPCChannel.h"
1717 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
18 #include
1819
1920 #if !defined(_MSC_VER) && !defined(__MINGW32__)
2021 #include
581581 // Reset errno to zero on entry to main.
582582 errno = 0;
583583
584 int Result;
584 int Result = -1;
585585
586586 // Sanity check use of remote-jit: LLI currently only supports use of the
587587 // remote JIT on Unix platforms.
680680 static_cast(RTDyldMM)->setResolver(
681681 orc::createLambdaResolver(
682682 [&](const std::string &Name) {
683 orc::TargetAddress Addr = 0;
684 if (auto EC = R->getSymbolAddress(Addr, Name)) {
685 errs() << "Failure during symbol lookup: " << EC.message() << "\n";
686 exit(1);
687 }
688 return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);
683 if (auto AddrOrErr = R->getSymbolAddress(Name))
684 return RuntimeDyld::SymbolInfo(*AddrOrErr, JITSymbolFlags::Exported);
685 else {
686 errs() << "Failure during symbol lookup: "
687 << AddrOrErr.getError().message() << "\n";
688 exit(1);
689 }
689690 },
690691 [](const std::string &Name) { return nullptr; }
691692 ));
697698 EE->finalizeObject();
698699 DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x"
699700 << format("%llx", Entry) << "\n");
700 if (auto EC = R->callIntVoid(Result, Entry))
701 errs() << "ERROR: " << EC.message() << "\n";
701 if (auto ResultOrErr = R->callIntVoid(Entry))
702 Result = *ResultOrErr;
703 else
704 errs() << "ERROR: " << ResultOrErr.getError().message() << "\n";
702705
703706 // Like static constructors, the remote target MCJIT support doesn't handle
704707 // this yet. It could. FIXME.
4343 class DummyRPC : public testing::Test,
4444 public RPC {
4545 public:
46 typedef Procedure<1, void(bool)> Proc1;
47 typedef Procedure<2, void(int8_t, uint8_t, int16_t, uint16_t,
48 int32_t, uint32_t, int64_t, uint64_t,
49 bool, std::string, std::vector)> AllTheTypes;
46 typedef Function<2, void(bool)> BasicVoid;
47 typedef Function<3, int32_t(bool)> BasicInt;
48 typedef Function<4, void(int8_t, uint8_t, int16_t, uint16_t,
49 int32_t, uint32_t, int64_t, uint64_t,
50 bool, std::string, std::vector)> AllTheTypes;
5051 };
5152
5253
53 TEST_F(DummyRPC, TestBasic) {
54 TEST_F(DummyRPC, TestAsyncBasicVoid) {
5455 std::queue Queue;
5556 QueueChannel C(Queue);
5657
57 {
58 // Make a call to Proc1.
59 auto EC = call(C, true);
60 EXPECT_FALSE(EC) << "Simple call over queue failed";
61 }
58 // Make an async call.
59 auto ResOrErr = callAsync(C, true);
60 EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
6261
6362 {
6463 // Expect a call to Proc1.
65 auto EC = expect<Proc1>(C,
64 auto EC = expect<BasicVoid>(C,
6665 [&](bool &B) {
6766 EXPECT_EQ(B, true)
6867 << "Bool serialization broken";
7069 });
7170 EXPECT_FALSE(EC) << "Simple expect over queue failed";
7271 }
72
73 {
74 // Wait for the result.
75 auto EC = waitForResult(C, ResOrErr->second, handleNone);
76 EXPECT_FALSE(EC) << "Could not read result.";
77 }
78
79 // Verify that the function returned ok.
80 auto Val = ResOrErr->first.get();
81 EXPECT_TRUE(Val) << "Remote void function failed to execute.";
82 }
83
84 TEST_F(DummyRPC, TestAsyncBasicInt) {
85 std::queue Queue;
86 QueueChannel C(Queue);
87
88 // Make an async call.
89 auto ResOrErr = callAsync(C, false);
90 EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
91
92 {
93 // Expect a call to Proc1.
94 auto EC = expect(C,
95 [&](bool &B) {
96 EXPECT_EQ(B, false)
97 << "Bool serialization broken";
98 return 42;
99 });
100 EXPECT_FALSE(EC) << "Simple expect over queue failed";
101 }
102
103 {
104 // Wait for the result.
105 auto EC = waitForResult(C, ResOrErr->second, handleNone);
106 EXPECT_FALSE(EC) << "Could not read result.";
107 }
108
109 // Verify that the function returned ok.
110 auto Val = ResOrErr->first.get();
111 EXPECT_TRUE(!!Val) << "Remote int function failed to execute.";
112 EXPECT_EQ(*Val, 42) << "Remote int function return wrong value.";
73113 }
74114
75115 TEST_F(DummyRPC, TestSerialization) {
76116 std::queue Queue;
77117 QueueChannel C(Queue);
78118
79 {
80 // Make a call to Proc1.
81 std::vector v({42, 7});
82 auto EC = call(C,
83 -101,
84 250,
85 -10000,
86 10000,
87 -1000000000,
88 1000000000,
89 -10000000000,
90 10000000000,
91 true,
92 "foo",
93 v);
94 EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
95 }
119 // Make a call to Proc1.
120 std::vector v({42, 7});
121 auto ResOrErr = callAsync(C,
122 -101,
123 250,
124 -10000,
125 10000,
126 -1000000000,
127 1000000000,
128 -10000000000,
129 10000000000,
130 true,
131 "foo",
132 v);
133 EXPECT_TRUE(!!ResOrErr)
134 << "Big (serialization test) call over queue failed";
96135
97136 {
98137 // Expect a call to Proc1.
135174 });
136175 EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
137176 }
177
178 {
179 // Wait for the result.
180 auto EC = waitForResult(C, ResOrErr->second, handleNone);
181 EXPECT_FALSE(EC) << "Could not read result.";
182 }
183
184 // Verify that the function returned ok.
185 auto Val = ResOrErr->first.get();
186 EXPECT_TRUE(Val) << "Remote void function failed to execute.";
138187 }