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