[Orc] Include the IndirectionUtils header in OrcRemoteTargetClient.
[oota-llvm.git] / include / llvm / ExecutionEngine / Orc / OrcRemoteTargetClient.h
1 //===---- OrcRemoteTargetClient.h - Orc Remote-target Client ----*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the OrcRemoteTargetClient class and helpers. This class
11 // can be used to communicate over an RPCChannel with an OrcRemoteTargetServer
12 // instance to support remote-JITing.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
17 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
18
19 #include "IndirectionUtils.h"
20 #include "OrcRemoteTargetRPCAPI.h"
21
22 #define DEBUG_TYPE "orc-remote"
23
24 namespace llvm {
25 namespace orc {
26 namespace remote {
27
28 /// This class provides utilities (including memory manager, indirect stubs
29 /// manager, and compile callback manager types) that support remote JITing
30 /// in ORC.
31 ///
32 /// Each of the utility classes talks to a JIT server (an instance of the
33 /// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
34 /// its actions.
35 template <typename ChannelT>
36 class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
37 public:
38   /// Remote memory manager.
39   class RCMemoryManager : public RuntimeDyld::MemoryManager {
40   public:
41     RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id)
42         : Client(Client), Id(Id) {
43       DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
44     }
45
46     ~RCMemoryManager() {
47       Client.destroyRemoteAllocator(Id);
48       DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
49     }
50
51     uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
52                                  unsigned SectionID,
53                                  StringRef SectionName) override {
54       Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
55       uint8_t *Alloc = reinterpret_cast<uint8_t *>(
56           Unmapped.back().CodeAllocs.back().getLocalAddress());
57       DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
58                    << SectionName << ": " << Alloc << " (" << Size
59                    << " bytes, alignment " << Alignment << ")\n");
60       return Alloc;
61     }
62
63     uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
64                                  unsigned SectionID, StringRef SectionName,
65                                  bool IsReadOnly) override {
66       if (IsReadOnly) {
67         Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
68         uint8_t *Alloc = reinterpret_cast<uint8_t *>(
69             Unmapped.back().RODataAllocs.back().getLocalAddress());
70         DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
71                      << SectionName << ": " << Alloc << " (" << Size
72                      << " bytes, alignment " << Alignment << ")\n");
73         return Alloc;
74       } // else...
75
76       Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
77       uint8_t *Alloc = reinterpret_cast<uint8_t *>(
78           Unmapped.back().RWDataAllocs.back().getLocalAddress());
79       DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
80                    << SectionName << ": " << Alloc << " (" << Size
81                    << " bytes, alignment " << Alignment << "\n");
82       return Alloc;
83     }
84
85     void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
86                                 uintptr_t RODataSize, uint32_t RODataAlign,
87                                 uintptr_t RWDataSize,
88                                 uint32_t RWDataAlign) override {
89       Unmapped.push_back(ObjectAllocs());
90
91       DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
92
93       if (CodeSize != 0) {
94         if (auto EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr, Id,
95                                         CodeSize, CodeAlign)) {
96           // FIXME; Add error to poll.
97           llvm_unreachable("Failed reserving remote memory.");
98         }
99         DEBUG(dbgs() << "  code: "
100                      << format("0x%016x", Unmapped.back().RemoteCodeAddr)
101                      << " (" << CodeSize << " bytes, alignment " << CodeAlign
102                      << ")\n");
103       }
104
105       if (RODataSize != 0) {
106         if (auto EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr, Id,
107                                         RODataSize, RODataAlign)) {
108           // FIXME; Add error to poll.
109           llvm_unreachable("Failed reserving remote memory.");
110         }
111         DEBUG(dbgs() << "  ro-data: "
112                      << format("0x%016x", Unmapped.back().RemoteRODataAddr)
113                      << " (" << RODataSize << " bytes, alignment "
114                      << RODataAlign << ")\n");
115       }
116
117       if (RWDataSize != 0) {
118         if (auto EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr, Id,
119                                         RWDataSize, RWDataAlign)) {
120           // FIXME; Add error to poll.
121           llvm_unreachable("Failed reserving remote memory.");
122         }
123         DEBUG(dbgs() << "  rw-data: "
124                      << format("0x%016x", Unmapped.back().RemoteRWDataAddr)
125                      << " (" << RWDataSize << " bytes, alignment "
126                      << RWDataAlign << ")\n");
127       }
128     }
129
130     bool needsToReserveAllocationSpace() override { return true; }
131
132     void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
133                           size_t Size) override {}
134
135     void deregisterEHFrames(uint8_t *addr, uint64_t LoadAddr,
136                             size_t Size) override {}
137
138     void notifyObjectLoaded(RuntimeDyld &Dyld,
139                             const object::ObjectFile &Obj) override {
140       DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
141       for (auto &ObjAllocs : Unmapped) {
142         {
143           TargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr;
144           for (auto &Alloc : ObjAllocs.CodeAllocs) {
145             NextCodeAddr = RoundUpToAlignment(NextCodeAddr, Alloc.getAlign());
146             Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr);
147             DEBUG(dbgs() << "     code: "
148                          << static_cast<void *>(Alloc.getLocalAddress())
149                          << " -> " << format("0x%016x", NextCodeAddr) << "\n");
150             Alloc.setRemoteAddress(NextCodeAddr);
151             NextCodeAddr += Alloc.getSize();
152           }
153         }
154         {
155           TargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr;
156           for (auto &Alloc : ObjAllocs.RODataAllocs) {
157             NextRODataAddr =
158                 RoundUpToAlignment(NextRODataAddr, Alloc.getAlign());
159             Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr);
160             DEBUG(dbgs() << "  ro-data: "
161                          << static_cast<void *>(Alloc.getLocalAddress())
162                          << " -> " << format("0x%016x", NextRODataAddr)
163                          << "\n");
164             Alloc.setRemoteAddress(NextRODataAddr);
165             NextRODataAddr += Alloc.getSize();
166           }
167         }
168         {
169           TargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr;
170           for (auto &Alloc : ObjAllocs.RWDataAllocs) {
171             NextRWDataAddr =
172                 RoundUpToAlignment(NextRWDataAddr, Alloc.getAlign());
173             Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr);
174             DEBUG(dbgs() << "  rw-data: "
175                          << static_cast<void *>(Alloc.getLocalAddress())
176                          << " -> " << format("0x%016x", NextRWDataAddr)
177                          << "\n");
178             Alloc.setRemoteAddress(NextRWDataAddr);
179             NextRWDataAddr += Alloc.getSize();
180           }
181         }
182         Unfinalized.push_back(std::move(ObjAllocs));
183       }
184       Unmapped.clear();
185     }
186
187     bool finalizeMemory(std::string *ErrMsg = nullptr) override {
188       DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
189
190       for (auto &ObjAllocs : Unfinalized) {
191
192         for (auto &Alloc : ObjAllocs.CodeAllocs) {
193           DEBUG(dbgs() << "  copying code: "
194                        << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
195                        << format("0x%016x", Alloc.getRemoteAddress()) << " ("
196                        << Alloc.getSize() << " bytes)\n");
197           Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
198                           Alloc.getSize());
199         }
200
201         if (ObjAllocs.RemoteCodeAddr) {
202           DEBUG(dbgs() << "  setting R-X permissions on code block: "
203                        << format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n");
204           Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
205                                 sys::Memory::MF_READ | sys::Memory::MF_EXEC);
206         }
207
208         for (auto &Alloc : ObjAllocs.RODataAllocs) {
209           DEBUG(dbgs() << "  copying ro-data: "
210                        << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
211                        << format("0x%016x", Alloc.getRemoteAddress()) << " ("
212                        << Alloc.getSize() << " bytes)\n");
213           Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
214                           Alloc.getSize());
215         }
216
217         if (ObjAllocs.RemoteRODataAddr) {
218           DEBUG(dbgs() << "  setting R-- permissions on ro-data block: "
219                        << format("0x%016x", ObjAllocs.RemoteRODataAddr)
220                        << "\n");
221           Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
222                                 sys::Memory::MF_READ);
223         }
224
225         for (auto &Alloc : ObjAllocs.RWDataAllocs) {
226           DEBUG(dbgs() << "  copying rw-data: "
227                        << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
228                        << format("0x%016x", Alloc.getRemoteAddress()) << " ("
229                        << Alloc.getSize() << " bytes)\n");
230           Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
231                           Alloc.getSize());
232         }
233
234         if (ObjAllocs.RemoteRWDataAddr) {
235           DEBUG(dbgs() << "  setting RW- permissions on rw-data block: "
236                        << format("0x%016x", ObjAllocs.RemoteRWDataAddr)
237                        << "\n");
238           Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
239                                 sys::Memory::MF_READ | sys::Memory::MF_WRITE);
240         }
241       }
242       Unfinalized.clear();
243
244       return false;
245     }
246
247   private:
248     class Alloc {
249     public:
250       Alloc(uint64_t Size, unsigned Align)
251           : Size(Size), Align(Align), Contents(new char[Size + Align - 1]),
252             RemoteAddr(0) {}
253
254       uint64_t getSize() const { return Size; }
255
256       unsigned getAlign() const { return Align; }
257
258       char *getLocalAddress() const {
259         uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
260         LocalAddr = RoundUpToAlignment(LocalAddr, Align);
261         return reinterpret_cast<char *>(LocalAddr);
262       }
263
264       void setRemoteAddress(TargetAddress RemoteAddr) {
265         this->RemoteAddr = RemoteAddr;
266       }
267
268       TargetAddress getRemoteAddress() const { return RemoteAddr; }
269
270     private:
271       uint64_t Size;
272       unsigned Align;
273       std::unique_ptr<char[]> Contents;
274       TargetAddress RemoteAddr;
275     };
276
277     struct ObjectAllocs {
278       ObjectAllocs()
279           : RemoteCodeAddr(0), RemoteRODataAddr(0), RemoteRWDataAddr(0) {}
280       TargetAddress RemoteCodeAddr;
281       TargetAddress RemoteRODataAddr;
282       TargetAddress RemoteRWDataAddr;
283       std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
284     };
285
286     OrcRemoteTargetClient &Client;
287     ResourceIdMgr::ResourceId Id;
288     std::vector<ObjectAllocs> Unmapped;
289     std::vector<ObjectAllocs> Unfinalized;
290   };
291
292   /// Remote indirect stubs manager.
293   class RCIndirectStubsManager : public IndirectStubsManager {
294   public:
295     RCIndirectStubsManager(OrcRemoteTargetClient &Remote,
296                            ResourceIdMgr::ResourceId Id)
297         : Remote(Remote), Id(Id) {}
298
299     ~RCIndirectStubsManager() { Remote.destroyIndirectStubsManager(Id); }
300
301     std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
302                                JITSymbolFlags StubFlags) override {
303       if (auto EC = reserveStubs(1))
304         return EC;
305
306       return createStubInternal(StubName, StubAddr, StubFlags);
307     }
308
309     std::error_code createStubs(const StubInitsMap &StubInits) override {
310       if (auto EC = reserveStubs(StubInits.size()))
311         return EC;
312
313       for (auto &Entry : StubInits)
314         if (auto EC = createStubInternal(Entry.first(), Entry.second.first,
315                                          Entry.second.second))
316           return EC;
317
318       return std::error_code();
319     }
320
321     JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
322       auto I = StubIndexes.find(Name);
323       if (I == StubIndexes.end())
324         return nullptr;
325       auto Key = I->second.first;
326       auto Flags = I->second.second;
327       auto StubSymbol = JITSymbol(getStubAddr(Key), Flags);
328       if (ExportedStubsOnly && !StubSymbol.isExported())
329         return nullptr;
330       return StubSymbol;
331     }
332
333     JITSymbol findPointer(StringRef Name) override {
334       auto I = StubIndexes.find(Name);
335       if (I == StubIndexes.end())
336         return nullptr;
337       auto Key = I->second.first;
338       auto Flags = I->second.second;
339       return JITSymbol(getPtrAddr(Key), Flags);
340     }
341
342     std::error_code updatePointer(StringRef Name,
343                                   TargetAddress NewAddr) override {
344       auto I = StubIndexes.find(Name);
345       assert(I != StubIndexes.end() && "No stub pointer for symbol");
346       auto Key = I->second.first;
347       return Remote.writePointer(getPtrAddr(Key), NewAddr);
348     }
349
350   private:
351     struct RemoteIndirectStubsInfo {
352       RemoteIndirectStubsInfo(TargetAddress StubBase, TargetAddress PtrBase,
353                               unsigned NumStubs)
354           : StubBase(StubBase), PtrBase(PtrBase), NumStubs(NumStubs) {}
355       TargetAddress StubBase;
356       TargetAddress PtrBase;
357       unsigned NumStubs;
358     };
359
360     OrcRemoteTargetClient &Remote;
361     ResourceIdMgr::ResourceId Id;
362     std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
363     typedef std::pair<uint16_t, uint16_t> StubKey;
364     std::vector<StubKey> FreeStubs;
365     StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
366
367     std::error_code reserveStubs(unsigned NumStubs) {
368       if (NumStubs <= FreeStubs.size())
369         return std::error_code();
370
371       unsigned NewStubsRequired = NumStubs - FreeStubs.size();
372       TargetAddress StubBase;
373       TargetAddress PtrBase;
374       unsigned NumStubsEmitted;
375
376       Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id,
377                                NewStubsRequired);
378
379       unsigned NewBlockId = RemoteIndirectStubsInfos.size();
380       RemoteIndirectStubsInfos.push_back(
381           RemoteIndirectStubsInfo(StubBase, PtrBase, NumStubsEmitted));
382
383       for (unsigned I = 0; I < NumStubsEmitted; ++I)
384         FreeStubs.push_back(std::make_pair(NewBlockId, I));
385
386       return std::error_code();
387     }
388
389     std::error_code createStubInternal(StringRef StubName,
390                                        TargetAddress InitAddr,
391                                        JITSymbolFlags StubFlags) {
392       auto Key = FreeStubs.back();
393       FreeStubs.pop_back();
394       StubIndexes[StubName] = std::make_pair(Key, StubFlags);
395       return Remote.writePointer(getPtrAddr(Key), InitAddr);
396     }
397
398     TargetAddress getStubAddr(StubKey K) {
399       assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
400              "Missing stub address");
401       return RemoteIndirectStubsInfos[K.first].StubBase +
402              K.second * Remote.getIndirectStubSize();
403     }
404
405     TargetAddress getPtrAddr(StubKey K) {
406       assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
407              "Missing pointer address");
408       return RemoteIndirectStubsInfos[K.first].PtrBase +
409              K.second * Remote.getPointerSize();
410     }
411   };
412
413   /// Remote compile callback manager.
414   class RCCompileCallbackManager : public JITCompileCallbackManager {
415   public:
416     RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,
417                              OrcRemoteTargetClient &Remote)
418         : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {
419       assert(!Remote.CompileCallback && "Compile callback already set");
420       Remote.CompileCallback = [this](TargetAddress TrampolineAddr) {
421         return executeCompileCallback(TrampolineAddr);
422       };
423       Remote.emitResolverBlock();
424     }
425
426   private:
427     void grow() {
428       TargetAddress BlockAddr = 0;
429       uint32_t NumTrampolines = 0;
430       auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines);
431       assert(!EC && "Failed to create trampolines");
432
433       uint32_t TrampolineSize = Remote.getTrampolineSize();
434       for (unsigned I = 0; I < NumTrampolines; ++I)
435         this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
436     }
437
438     OrcRemoteTargetClient &Remote;
439   };
440
441   /// Create an OrcRemoteTargetClient.
442   /// Channel is the ChannelT instance to communicate on. It is assumed that
443   /// the channel is ready to be read from and written to.
444   static ErrorOr<OrcRemoteTargetClient> Create(ChannelT &Channel) {
445     std::error_code EC;
446     OrcRemoteTargetClient H(Channel, EC);
447     if (EC)
448       return EC;
449     return H;
450   }
451
452   /// Call the int(void) function at the given address in the target and return
453   /// its result.
454   std::error_code callIntVoid(int &Result, TargetAddress Addr) {
455     DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
456
457     if (auto EC = call<CallIntVoid>(Channel, Addr))
458       return EC;
459
460     unsigned NextProcId;
461     if (auto EC = listenForCompileRequests(NextProcId))
462       return EC;
463
464     if (NextProcId != CallIntVoidResponseId)
465       return orcError(OrcErrorCode::UnexpectedRPCCall);
466
467     return handle<CallIntVoidResponse>(Channel, [&](int R) {
468       Result = R;
469       DEBUG(dbgs() << "Result: " << R << "\n");
470       return std::error_code();
471     });
472   }
473
474   /// Call the int(int, char*[]) function at the given address in the target and
475   /// return its result.
476   std::error_code callMain(int &Result, TargetAddress Addr,
477                            const std::vector<std::string> &Args) {
478     DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
479                  << "\n");
480
481     if (auto EC = call<CallMain>(Channel, Addr, Args))
482       return EC;
483
484     unsigned NextProcId;
485     if (auto EC = listenForCompileRequests(NextProcId))
486       return EC;
487
488     if (NextProcId != CallMainResponseId)
489       return orcError(OrcErrorCode::UnexpectedRPCCall);
490
491     return handle<CallMainResponse>(Channel, [&](int R) {
492       Result = R;
493       DEBUG(dbgs() << "Result: " << R << "\n");
494       return std::error_code();
495     });
496   }
497
498   /// Call the void() function at the given address in the target and wait for
499   /// it to finish.
500   std::error_code callVoidVoid(TargetAddress Addr) {
501     DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
502                  << "\n");
503
504     if (auto EC = call<CallVoidVoid>(Channel, Addr))
505       return EC;
506
507     unsigned NextProcId;
508     if (auto EC = listenForCompileRequests(NextProcId))
509       return EC;
510
511     if (NextProcId != CallVoidVoidResponseId)
512       return orcError(OrcErrorCode::UnexpectedRPCCall);
513
514     return handle<CallVoidVoidResponse>(Channel, doNothing);
515   }
516
517   /// Create an RCMemoryManager which will allocate its memory on the remote
518   /// target.
519   std::error_code
520   createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) {
521     assert(!MM && "MemoryManager should be null before creation.");
522
523     auto Id = AllocatorIds.getNext();
524     if (auto EC = call<CreateRemoteAllocator>(Channel, Id))
525       return EC;
526     MM = llvm::make_unique<RCMemoryManager>(*this, Id);
527     return std::error_code();
528   }
529
530   /// Create an RCIndirectStubsManager that will allocate stubs on the remote
531   /// target.
532   std::error_code
533   createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {
534     assert(!I && "Indirect stubs manager should be null before creation.");
535     auto Id = IndirectStubOwnerIds.getNext();
536     if (auto EC = call<CreateIndirectStubsOwner>(Channel, Id))
537       return EC;
538     I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);
539     return std::error_code();
540   }
541
542   /// Search for symbols in the remote process. Note: This should be used by
543   /// symbol resolvers *after* they've searched the local symbol table in the
544   /// JIT stack.
545   std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) {
546     // Check for an 'out-of-band' error, e.g. from an MM destructor.
547     if (ExistingError)
548       return ExistingError;
549
550     // Request remote symbol address.
551     if (auto EC = call<GetSymbolAddress>(Channel, Name))
552       return EC;
553
554     return expect<GetSymbolAddressResponse>(Channel, [&](TargetAddress &A) {
555       Addr = A;
556       DEBUG(dbgs() << "Remote address lookup " << Name << " = "
557                    << format("0x%016x", Addr) << "\n");
558       return std::error_code();
559     });
560   }
561
562   /// Get the triple for the remote target.
563   const std::string &getTargetTriple() const { return RemoteTargetTriple; }
564
565   std::error_code terminateSession() { return call<TerminateSession>(Channel); }
566
567 private:
568   OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC)
569       : Channel(Channel), RemotePointerSize(0), RemotePageSize(0),
570         RemoteTrampolineSize(0), RemoteIndirectStubSize(0) {
571     if ((EC = call<GetRemoteInfo>(Channel)))
572       return;
573
574     EC = expect<GetRemoteInfoResponse>(
575         Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
576                           RemoteTrampolineSize, RemoteIndirectStubSize));
577   }
578
579   void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
580     if (auto EC = call<DestroyRemoteAllocator>(Channel, Id)) {
581       // FIXME: This will be triggered by a removeModuleSet call: Propagate
582       //        error return up through that.
583       llvm_unreachable("Failed to destroy remote allocator.");
584       AllocatorIds.release(Id);
585     }
586   }
587
588   std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
589     IndirectStubOwnerIds.release(Id);
590     return call<DestroyIndirectStubsOwner>(Channel, Id);
591   }
592
593   std::error_code emitIndirectStubs(TargetAddress &StubBase,
594                                     TargetAddress &PtrBase,
595                                     uint32_t &NumStubsEmitted,
596                                     ResourceIdMgr::ResourceId Id,
597                                     uint32_t NumStubsRequired) {
598     if (auto EC = call<EmitIndirectStubs>(Channel, Id, NumStubsRequired))
599       return EC;
600
601     return expect<EmitIndirectStubsResponse>(
602         Channel, readArgs(StubBase, PtrBase, NumStubsEmitted));
603   }
604
605   std::error_code emitResolverBlock() {
606     // Check for an 'out-of-band' error, e.g. from an MM destructor.
607     if (ExistingError)
608       return ExistingError;
609
610     return call<EmitResolverBlock>(Channel);
611   }
612
613   std::error_code emitTrampolineBlock(TargetAddress &BlockAddr,
614                                       uint32_t &NumTrampolines) {
615     // Check for an 'out-of-band' error, e.g. from an MM destructor.
616     if (ExistingError)
617       return ExistingError;
618
619     if (auto EC = call<EmitTrampolineBlock>(Channel))
620       return EC;
621
622     return expect<EmitTrampolineBlockResponse>(
623         Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) {
624           BlockAddr = BAddr;
625           NumTrampolines = NTrampolines;
626           return std::error_code();
627         });
628   }
629
630   uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
631   uint32_t getPageSize() const { return RemotePageSize; }
632   uint32_t getPointerSize() const { return RemotePointerSize; }
633
634   uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
635
636   std::error_code listenForCompileRequests(uint32_t &NextId) {
637     // Check for an 'out-of-band' error, e.g. from an MM destructor.
638     if (ExistingError)
639       return ExistingError;
640
641     if (auto EC = getNextProcId(Channel, NextId))
642       return EC;
643
644     while (NextId == RequestCompileId) {
645       TargetAddress TrampolineAddr = 0;
646       if (auto EC = handle<RequestCompile>(Channel, readArgs(TrampolineAddr)))
647         return EC;
648
649       TargetAddress ImplAddr = CompileCallback(TrampolineAddr);
650       if (auto EC = call<RequestCompileResponse>(Channel, ImplAddr))
651         return EC;
652
653       if (auto EC = getNextProcId(Channel, NextId))
654         return EC;
655     }
656
657     return std::error_code();
658   }
659
660   std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) {
661     // Check for an 'out-of-band' error, e.g. from an MM destructor.
662     if (ExistingError)
663       return ExistingError;
664
665     if (auto EC = call<ReadMem>(Channel, Src, Size))
666       return EC;
667
668     if (auto EC = expect<ReadMemResponse>(
669             Channel, [&]() { return Channel.readBytes(Dst, Size); }))
670       return EC;
671
672     return std::error_code();
673   }
674
675   std::error_code reserveMem(TargetAddress &RemoteAddr,
676                              ResourceIdMgr::ResourceId Id, uint64_t Size,
677                              uint32_t Align) {
678
679     // Check for an 'out-of-band' error, e.g. from an MM destructor.
680     if (ExistingError)
681       return ExistingError;
682
683     if (auto EC = call<ReserveMem>(Channel, Id, Size, Align))
684       return EC;
685
686     if (auto EC = expect<ReserveMemResponse>(Channel, [&](TargetAddress Addr) {
687           RemoteAddr = Addr;
688           return std::error_code();
689         }))
690       return EC;
691
692     return std::error_code();
693   }
694
695   std::error_code setProtections(ResourceIdMgr::ResourceId Id,
696                                  TargetAddress RemoteSegAddr,
697                                  unsigned ProtFlags) {
698     return call<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);
699   }
700
701   std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {
702     // Check for an 'out-of-band' error, e.g. from an MM destructor.
703     if (ExistingError)
704       return ExistingError;
705
706     // Make the send call.
707     if (auto EC = call<WriteMem>(Channel, Addr, Size))
708       return EC;
709
710     // Follow this up with the section contents.
711     if (auto EC = Channel.appendBytes(Src, Size))
712       return EC;
713
714     return Channel.send();
715   }
716
717   std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) {
718     // Check for an 'out-of-band' error, e.g. from an MM destructor.
719     if (ExistingError)
720       return ExistingError;
721
722     return call<WritePtr>(Channel, Addr, PtrVal);
723   }
724
725   static std::error_code doNothing() { return std::error_code(); }
726
727   ChannelT &Channel;
728   std::error_code ExistingError;
729   std::string RemoteTargetTriple;
730   uint32_t RemotePointerSize;
731   uint32_t RemotePageSize;
732   uint32_t RemoteTrampolineSize;
733   uint32_t RemoteIndirectStubSize;
734   ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
735   std::function<TargetAddress(TargetAddress)> CompileCallback;
736 };
737
738 } // end namespace remote
739 } // end namespace orc
740 } // end namespace llvm
741
742 #undef DEBUG_TYPE
743
744 #endif