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