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