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