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({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 
    638 private:
    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