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