]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / 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 RawByteChannel with an
12 // OrcRemoteTargetServer 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 "llvm/ADT/Optional.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/StringMap.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/ExecutionEngine/JITSymbol.h"
24 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
25 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
26 #include "llvm/ExecutionEngine/RuntimeDyld.h"
27 #include "llvm/Support/Debug.h"
28 #include "llvm/Support/Error.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/Format.h"
31 #include "llvm/Support/MathExtras.h"
32 #include "llvm/Support/Memory.h"
33 #include "llvm/Support/raw_ostream.h"
34 #include <algorithm>
35 #include <cassert>
36 #include <cstdint>
37 #include <memory>
38 #include <string>
39 #include <tuple>
40 #include <utility>
41 #include <vector>
42
43 #define DEBUG_TYPE "orc-remote"
44
45 namespace llvm {
46 namespace orc {
47 namespace remote {
48
49 /// This class provides utilities (including memory manager, indirect stubs
50 /// manager, and compile callback manager types) that support remote JITing
51 /// in ORC.
52 ///
53 /// Each of the utility classes talks to a JIT server (an instance of the
54 /// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
55 /// its actions.
56 class OrcRemoteTargetClient
57     : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
58 public:
59   /// Remote-mapped RuntimeDyld-compatible memory manager.
60   class RemoteRTDyldMemoryManager : public RuntimeDyld::MemoryManager {
61     friend class OrcRemoteTargetClient;
62
63   public:
64     ~RemoteRTDyldMemoryManager() {
65       Client.destroyRemoteAllocator(Id);
66       LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
67     }
68
69     RemoteRTDyldMemoryManager(const RemoteRTDyldMemoryManager &) = delete;
70     RemoteRTDyldMemoryManager &
71     operator=(const RemoteRTDyldMemoryManager &) = delete;
72     RemoteRTDyldMemoryManager(RemoteRTDyldMemoryManager &&) = default;
73     RemoteRTDyldMemoryManager &operator=(RemoteRTDyldMemoryManager &&) = delete;
74
75     uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
76                                  unsigned SectionID,
77                                  StringRef SectionName) override {
78       Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
79       uint8_t *Alloc = reinterpret_cast<uint8_t *>(
80           Unmapped.back().CodeAllocs.back().getLocalAddress());
81       LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
82                         << SectionName << ": " << Alloc << " (" << Size
83                         << " bytes, alignment " << Alignment << ")\n");
84       return Alloc;
85     }
86
87     uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
88                                  unsigned SectionID, StringRef SectionName,
89                                  bool IsReadOnly) override {
90       if (IsReadOnly) {
91         Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
92         uint8_t *Alloc = reinterpret_cast<uint8_t *>(
93             Unmapped.back().RODataAllocs.back().getLocalAddress());
94         LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
95                           << SectionName << ": " << Alloc << " (" << Size
96                           << " bytes, alignment " << Alignment << ")\n");
97         return Alloc;
98       } // else...
99
100       Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
101       uint8_t *Alloc = reinterpret_cast<uint8_t *>(
102           Unmapped.back().RWDataAllocs.back().getLocalAddress());
103       LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
104                         << SectionName << ": " << Alloc << " (" << Size
105                         << " bytes, alignment " << Alignment << ")\n");
106       return Alloc;
107     }
108
109     void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
110                                 uintptr_t RODataSize, uint32_t RODataAlign,
111                                 uintptr_t RWDataSize,
112                                 uint32_t RWDataAlign) override {
113       Unmapped.push_back(ObjectAllocs());
114
115       LLVM_DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
116
117       if (CodeSize != 0) {
118         Unmapped.back().RemoteCodeAddr =
119             Client.reserveMem(Id, CodeSize, CodeAlign);
120
121         LLVM_DEBUG(dbgs() << "  code: "
122                           << format("0x%016x", Unmapped.back().RemoteCodeAddr)
123                           << " (" << CodeSize << " bytes, alignment "
124                           << CodeAlign << ")\n");
125       }
126
127       if (RODataSize != 0) {
128         Unmapped.back().RemoteRODataAddr =
129             Client.reserveMem(Id, RODataSize, RODataAlign);
130
131         LLVM_DEBUG(dbgs() << "  ro-data: "
132                           << format("0x%016x", Unmapped.back().RemoteRODataAddr)
133                           << " (" << RODataSize << " bytes, alignment "
134                           << RODataAlign << ")\n");
135       }
136
137       if (RWDataSize != 0) {
138         Unmapped.back().RemoteRWDataAddr =
139             Client.reserveMem(Id, RWDataSize, RWDataAlign);
140
141         LLVM_DEBUG(dbgs() << "  rw-data: "
142                           << format("0x%016x", Unmapped.back().RemoteRWDataAddr)
143                           << " (" << RWDataSize << " bytes, alignment "
144                           << RWDataAlign << ")\n");
145       }
146     }
147
148     bool needsToReserveAllocationSpace() override { return true; }
149
150     void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
151                           size_t Size) override {
152       UnfinalizedEHFrames.push_back({LoadAddr, Size});
153     }
154
155     void deregisterEHFrames() override {
156       for (auto &Frame : RegisteredEHFrames) {
157         // FIXME: Add error poll.
158         Client.deregisterEHFrames(Frame.Addr, Frame.Size);
159       }
160     }
161
162     void notifyObjectLoaded(RuntimeDyld &Dyld,
163                             const object::ObjectFile &Obj) override {
164       LLVM_DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
165       for (auto &ObjAllocs : Unmapped) {
166         mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
167                                ObjAllocs.RemoteCodeAddr);
168         mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
169                                ObjAllocs.RemoteRODataAddr);
170         mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
171                                ObjAllocs.RemoteRWDataAddr);
172         Unfinalized.push_back(std::move(ObjAllocs));
173       }
174       Unmapped.clear();
175     }
176
177     bool finalizeMemory(std::string *ErrMsg = nullptr) override {
178       LLVM_DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
179
180       for (auto &ObjAllocs : Unfinalized) {
181         if (copyAndProtect(ObjAllocs.CodeAllocs, ObjAllocs.RemoteCodeAddr,
182                            sys::Memory::MF_READ | sys::Memory::MF_EXEC))
183           return true;
184
185         if (copyAndProtect(ObjAllocs.RODataAllocs, ObjAllocs.RemoteRODataAddr,
186                            sys::Memory::MF_READ))
187           return true;
188
189         if (copyAndProtect(ObjAllocs.RWDataAllocs, ObjAllocs.RemoteRWDataAddr,
190                            sys::Memory::MF_READ | sys::Memory::MF_WRITE))
191           return true;
192       }
193       Unfinalized.clear();
194
195       for (auto &EHFrame : UnfinalizedEHFrames) {
196         if (auto Err = Client.registerEHFrames(EHFrame.Addr, EHFrame.Size)) {
197           // FIXME: Replace this once finalizeMemory can return an Error.
198           handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
199             if (ErrMsg) {
200               raw_string_ostream ErrOut(*ErrMsg);
201               EIB.log(ErrOut);
202             }
203           });
204           return false;
205         }
206       }
207       RegisteredEHFrames = std::move(UnfinalizedEHFrames);
208       UnfinalizedEHFrames = {};
209
210       return false;
211     }
212
213   private:
214     class Alloc {
215     public:
216       Alloc(uint64_t Size, unsigned Align)
217           : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
218
219       Alloc(const Alloc &) = delete;
220       Alloc &operator=(const Alloc &) = delete;
221       Alloc(Alloc &&) = default;
222       Alloc &operator=(Alloc &&) = default;
223
224       uint64_t getSize() const { return Size; }
225
226       unsigned getAlign() const { return Align; }
227
228       char *getLocalAddress() const {
229         uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
230         LocalAddr = alignTo(LocalAddr, Align);
231         return reinterpret_cast<char *>(LocalAddr);
232       }
233
234       void setRemoteAddress(JITTargetAddress RemoteAddr) {
235         this->RemoteAddr = RemoteAddr;
236       }
237
238       JITTargetAddress getRemoteAddress() const { return RemoteAddr; }
239
240     private:
241       uint64_t Size;
242       unsigned Align;
243       std::unique_ptr<char[]> Contents;
244       JITTargetAddress RemoteAddr = 0;
245     };
246
247     struct ObjectAllocs {
248       ObjectAllocs() = default;
249       ObjectAllocs(const ObjectAllocs &) = delete;
250       ObjectAllocs &operator=(const ObjectAllocs &) = delete;
251       ObjectAllocs(ObjectAllocs &&) = default;
252       ObjectAllocs &operator=(ObjectAllocs &&) = default;
253
254       JITTargetAddress RemoteCodeAddr = 0;
255       JITTargetAddress RemoteRODataAddr = 0;
256       JITTargetAddress RemoteRWDataAddr = 0;
257       std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
258     };
259
260     RemoteRTDyldMemoryManager(OrcRemoteTargetClient &Client,
261                               ResourceIdMgr::ResourceId Id)
262         : Client(Client), Id(Id) {
263       LLVM_DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
264     }
265
266     // Maps all allocations in Allocs to aligned blocks
267     void mapAllocsToRemoteAddrs(RuntimeDyld &Dyld, std::vector<Alloc> &Allocs,
268                                 JITTargetAddress NextAddr) {
269       for (auto &Alloc : Allocs) {
270         NextAddr = alignTo(NextAddr, Alloc.getAlign());
271         Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextAddr);
272         LLVM_DEBUG(dbgs() << "     "
273                           << static_cast<void *>(Alloc.getLocalAddress())
274                           << " -> " << format("0x%016x", NextAddr) << "\n");
275         Alloc.setRemoteAddress(NextAddr);
276
277         // Only advance NextAddr if it was non-null to begin with,
278         // otherwise leave it as null.
279         if (NextAddr)
280           NextAddr += Alloc.getSize();
281       }
282     }
283
284     // Copies data for each alloc in the list, then set permissions on the
285     // segment.
286     bool copyAndProtect(const std::vector<Alloc> &Allocs,
287                         JITTargetAddress RemoteSegmentAddr,
288                         unsigned Permissions) {
289       if (RemoteSegmentAddr) {
290         assert(!Allocs.empty() && "No sections in allocated segment");
291
292         for (auto &Alloc : Allocs) {
293           LLVM_DEBUG(dbgs() << "  copying section: "
294                             << static_cast<void *>(Alloc.getLocalAddress())
295                             << " -> "
296                             << format("0x%016x", Alloc.getRemoteAddress())
297                             << " (" << Alloc.getSize() << " bytes)\n";);
298
299           if (Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
300                               Alloc.getSize()))
301             return true;
302         }
303
304         LLVM_DEBUG(dbgs() << "  setting "
305                           << (Permissions & sys::Memory::MF_READ ? 'R' : '-')
306                           << (Permissions & sys::Memory::MF_WRITE ? 'W' : '-')
307                           << (Permissions & sys::Memory::MF_EXEC ? 'X' : '-')
308                           << " permissions on block: "
309                           << format("0x%016x", RemoteSegmentAddr) << "\n");
310         if (Client.setProtections(Id, RemoteSegmentAddr, Permissions))
311           return true;
312       }
313       return false;
314     }
315
316     OrcRemoteTargetClient &Client;
317     ResourceIdMgr::ResourceId Id;
318     std::vector<ObjectAllocs> Unmapped;
319     std::vector<ObjectAllocs> Unfinalized;
320
321     struct EHFrame {
322       JITTargetAddress Addr;
323       uint64_t Size;
324     };
325     std::vector<EHFrame> UnfinalizedEHFrames;
326     std::vector<EHFrame> RegisteredEHFrames;
327   };
328
329   /// Remote indirect stubs manager.
330   class RemoteIndirectStubsManager : public IndirectStubsManager {
331   public:
332     RemoteIndirectStubsManager(OrcRemoteTargetClient &Client,
333                                ResourceIdMgr::ResourceId Id)
334         : Client(Client), Id(Id) {}
335
336     ~RemoteIndirectStubsManager() override {
337       Client.destroyIndirectStubsManager(Id);
338     }
339
340     Error createStub(StringRef StubName, JITTargetAddress StubAddr,
341                      JITSymbolFlags StubFlags) override {
342       if (auto Err = reserveStubs(1))
343         return Err;
344
345       return createStubInternal(StubName, StubAddr, StubFlags);
346     }
347
348     Error createStubs(const StubInitsMap &StubInits) override {
349       if (auto Err = reserveStubs(StubInits.size()))
350         return Err;
351
352       for (auto &Entry : StubInits)
353         if (auto Err = createStubInternal(Entry.first(), Entry.second.first,
354                                           Entry.second.second))
355           return Err;
356
357       return Error::success();
358     }
359
360     JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
361       auto I = StubIndexes.find(Name);
362       if (I == StubIndexes.end())
363         return nullptr;
364       auto Key = I->second.first;
365       auto Flags = I->second.second;
366       auto StubSymbol = JITEvaluatedSymbol(getStubAddr(Key), Flags);
367       if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
368         return nullptr;
369       return StubSymbol;
370     }
371
372     JITEvaluatedSymbol findPointer(StringRef Name) 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       return JITEvaluatedSymbol(getPtrAddr(Key), Flags);
379     }
380
381     Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
382       auto I = StubIndexes.find(Name);
383       assert(I != StubIndexes.end() && "No stub pointer for symbol");
384       auto Key = I->second.first;
385       return Client.writePointer(getPtrAddr(Key), NewAddr);
386     }
387
388   private:
389     struct RemoteIndirectStubsInfo {
390       JITTargetAddress StubBase;
391       JITTargetAddress PtrBase;
392       unsigned NumStubs;
393     };
394
395     using StubKey = std::pair<uint16_t, uint16_t>;
396
397     Error reserveStubs(unsigned NumStubs) {
398       if (NumStubs <= FreeStubs.size())
399         return Error::success();
400
401       unsigned NewStubsRequired = NumStubs - FreeStubs.size();
402       JITTargetAddress StubBase;
403       JITTargetAddress PtrBase;
404       unsigned NumStubsEmitted;
405
406       if (auto StubInfoOrErr = Client.emitIndirectStubs(Id, NewStubsRequired))
407         std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
408       else
409         return StubInfoOrErr.takeError();
410
411       unsigned NewBlockId = RemoteIndirectStubsInfos.size();
412       RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
413
414       for (unsigned I = 0; I < NumStubsEmitted; ++I)
415         FreeStubs.push_back(std::make_pair(NewBlockId, I));
416
417       return Error::success();
418     }
419
420     Error createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
421                              JITSymbolFlags StubFlags) {
422       auto Key = FreeStubs.back();
423       FreeStubs.pop_back();
424       StubIndexes[StubName] = std::make_pair(Key, StubFlags);
425       return Client.writePointer(getPtrAddr(Key), InitAddr);
426     }
427
428     JITTargetAddress getStubAddr(StubKey K) {
429       assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
430              "Missing stub address");
431       return RemoteIndirectStubsInfos[K.first].StubBase +
432              K.second * Client.getIndirectStubSize();
433     }
434
435     JITTargetAddress getPtrAddr(StubKey K) {
436       assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
437              "Missing pointer address");
438       return RemoteIndirectStubsInfos[K.first].PtrBase +
439              K.second * Client.getPointerSize();
440     }
441
442     OrcRemoteTargetClient &Client;
443     ResourceIdMgr::ResourceId Id;
444     std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
445     std::vector<StubKey> FreeStubs;
446     StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
447   };
448
449   /// Remote compile callback manager.
450   class RemoteCompileCallbackManager : public JITCompileCallbackManager {
451   public:
452     RemoteCompileCallbackManager(OrcRemoteTargetClient &Client,
453                                  ExecutionSession &ES,
454                                  JITTargetAddress ErrorHandlerAddress)
455         : JITCompileCallbackManager(ES, ErrorHandlerAddress), Client(Client) {}
456
457   private:
458     Error grow() override {
459       JITTargetAddress BlockAddr = 0;
460       uint32_t NumTrampolines = 0;
461       if (auto TrampolineInfoOrErr = Client.emitTrampolineBlock())
462         std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
463       else
464         return TrampolineInfoOrErr.takeError();
465
466       uint32_t TrampolineSize = Client.getTrampolineSize();
467       for (unsigned I = 0; I < NumTrampolines; ++I)
468         this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
469
470       return Error::success();
471     }
472
473     OrcRemoteTargetClient &Client;
474   };
475
476   /// Create an OrcRemoteTargetClient.
477   /// Channel is the ChannelT instance to communicate on. It is assumed that
478   /// the channel is ready to be read from and written to.
479   static Expected<std::unique_ptr<OrcRemoteTargetClient>>
480   Create(rpc::RawByteChannel &Channel, ExecutionSession &ES) {
481     Error Err = Error::success();
482     auto Client = std::unique_ptr<OrcRemoteTargetClient>(
483         new OrcRemoteTargetClient(Channel, ES, Err));
484     if (Err)
485       return std::move(Err);
486     return std::move(Client);
487   }
488
489   /// Call the int(void) function at the given address in the target and return
490   /// its result.
491   Expected<int> callIntVoid(JITTargetAddress Addr) {
492     LLVM_DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr)
493                       << "\n");
494     return callB<exec::CallIntVoid>(Addr);
495   }
496
497   /// Call the int(int, char*[]) function at the given address in the target and
498   /// return its result.
499   Expected<int> callMain(JITTargetAddress Addr,
500                          const std::vector<std::string> &Args) {
501     LLVM_DEBUG(dbgs() << "Calling int(*)(int, char*[]) "
502                       << format("0x%016x", Addr) << "\n");
503     return callB<exec::CallMain>(Addr, Args);
504   }
505
506   /// Call the void() function at the given address in the target and wait for
507   /// it to finish.
508   Error callVoidVoid(JITTargetAddress Addr) {
509     LLVM_DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
510                       << "\n");
511     return callB<exec::CallVoidVoid>(Addr);
512   }
513
514   /// Create an RCMemoryManager which will allocate its memory on the remote
515   /// target.
516   Expected<std::unique_ptr<RemoteRTDyldMemoryManager>>
517   createRemoteMemoryManager() {
518     auto Id = AllocatorIds.getNext();
519     if (auto Err = callB<mem::CreateRemoteAllocator>(Id))
520       return std::move(Err);
521     return std::unique_ptr<RemoteRTDyldMemoryManager>(
522         new RemoteRTDyldMemoryManager(*this, Id));
523   }
524
525   /// Create an RCIndirectStubsManager that will allocate stubs on the remote
526   /// target.
527   Expected<std::unique_ptr<RemoteIndirectStubsManager>>
528   createIndirectStubsManager() {
529     auto Id = IndirectStubOwnerIds.getNext();
530     if (auto Err = callB<stubs::CreateIndirectStubsOwner>(Id))
531       return std::move(Err);
532     return llvm::make_unique<RemoteIndirectStubsManager>(*this, Id);
533   }
534
535   Expected<RemoteCompileCallbackManager &>
536   enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress) {
537     assert(!CallbackManager && "CallbackManager already obtained");
538
539     // Emit the resolver block on the JIT server.
540     if (auto Err = callB<stubs::EmitResolverBlock>())
541       return std::move(Err);
542
543     // Create the callback manager.
544     CallbackManager.emplace(*this, ES, ErrorHandlerAddress);
545     RemoteCompileCallbackManager &Mgr = *CallbackManager;
546     return Mgr;
547   }
548
549   /// Search for symbols in the remote process. Note: This should be used by
550   /// symbol resolvers *after* they've searched the local symbol table in the
551   /// JIT stack.
552   Expected<JITTargetAddress> getSymbolAddress(StringRef Name) {
553     return callB<utils::GetSymbolAddress>(Name);
554   }
555
556   /// Get the triple for the remote target.
557   const std::string &getTargetTriple() const { return RemoteTargetTriple; }
558
559   Error terminateSession() { return callB<utils::TerminateSession>(); }
560
561 private:
562   OrcRemoteTargetClient(rpc::RawByteChannel &Channel, ExecutionSession &ES,
563                         Error &Err)
564       : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(Channel, true),
565         ES(ES) {
566     ErrorAsOutParameter EAO(&Err);
567
568     addHandler<utils::RequestCompile>(
569         [this](JITTargetAddress Addr) -> JITTargetAddress {
570           if (CallbackManager)
571             return CallbackManager->executeCompileCallback(Addr);
572           return 0;
573         });
574
575     if (auto RIOrErr = callB<utils::GetRemoteInfo>()) {
576       std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
577                RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
578       Err = Error::success();
579     } else
580       Err = RIOrErr.takeError();
581   }
582
583   void deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
584     if (auto Err = callB<eh::RegisterEHFrames>(Addr, Size))
585       ES.reportError(std::move(Err));
586   }
587
588   void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
589     if (auto Err = callB<mem::DestroyRemoteAllocator>(Id)) {
590       // FIXME: This will be triggered by a removeModuleSet call: Propagate
591       //        error return up through that.
592       llvm_unreachable("Failed to destroy remote allocator.");
593       AllocatorIds.release(Id);
594     }
595   }
596
597   void destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
598     IndirectStubOwnerIds.release(Id);
599     if (auto Err = callB<stubs::DestroyIndirectStubsOwner>(Id))
600       ES.reportError(std::move(Err));
601   }
602
603   Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
604   emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
605     return callB<stubs::EmitIndirectStubs>(Id, NumStubsRequired);
606   }
607
608   Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() {
609     return callB<stubs::EmitTrampolineBlock>();
610   }
611
612   uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
613   uint32_t getPageSize() const { return RemotePageSize; }
614   uint32_t getPointerSize() const { return RemotePointerSize; }
615
616   uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
617
618   Expected<std::vector<uint8_t>> readMem(char *Dst, JITTargetAddress Src,
619                                          uint64_t Size) {
620     return callB<mem::ReadMem>(Src, Size);
621   }
622
623   Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) {
624     // FIXME: Duplicate error and report it via ReportError too?
625     return callB<eh::RegisterEHFrames>(RAddr, Size);
626   }
627
628   JITTargetAddress reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
629                               uint32_t Align) {
630     if (auto AddrOrErr = callB<mem::ReserveMem>(Id, Size, Align))
631       return *AddrOrErr;
632     else {
633       ES.reportError(AddrOrErr.takeError());
634       return 0;
635     }
636   }
637
638   bool setProtections(ResourceIdMgr::ResourceId Id,
639                       JITTargetAddress RemoteSegAddr, unsigned ProtFlags) {
640     if (auto Err = callB<mem::SetProtections>(Id, RemoteSegAddr, ProtFlags)) {
641       ES.reportError(std::move(Err));
642       return true;
643     } else
644       return false;
645   }
646
647   bool writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) {
648     if (auto Err = callB<mem::WriteMem>(DirectBufferWriter(Src, Addr, Size))) {
649       ES.reportError(std::move(Err));
650       return true;
651     } else
652       return false;
653   }
654
655   Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
656     return callB<mem::WritePtr>(Addr, PtrVal);
657   }
658
659   static Error doNothing() { return Error::success(); }
660
661   ExecutionSession &ES;
662   std::function<void(Error)> ReportError;
663   std::string RemoteTargetTriple;
664   uint32_t RemotePointerSize = 0;
665   uint32_t RemotePageSize = 0;
666   uint32_t RemoteTrampolineSize = 0;
667   uint32_t RemoteIndirectStubSize = 0;
668   ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
669   Optional<RemoteCompileCallbackManager> CallbackManager;
670 };
671
672 } // end namespace remote
673 } // end namespace orc
674 } // end namespace llvm
675
676 #undef DEBUG_TYPE
677
678 #endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H