OrcRemoteTargetClient.h revision 360784
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
44namespace llvm {
45namespace orc {
46namespace 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.
55class OrcRemoteTargetClient
56    : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
57public:
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              std::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 std::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
585private:
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
703