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