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