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