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