diff options
Diffstat (limited to 'include/llvm/ExecutionEngine/Orc')
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h | 35 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h | 11 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/IndirectionUtils.h | 32 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/OrcError.h | 3 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h | 483 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h | 263 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h | 55 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/RPCSerialization.h | 14 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/RPCUtils.h | 14 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h | 38 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h | 538 | ||||
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/SymbolStringPool.h | 136 |
12 files changed, 1161 insertions, 461 deletions
diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 27b5457fc8ff..a961992c2147 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -140,12 +140,6 @@ private: struct LogicalDylib { using SymbolResolverFtor = std::function<JITSymbol(const std::string&)>; - using ModuleAdderFtor = - std::function<typename BaseLayerT::ModuleHandleT( - BaseLayerT&, - std::unique_ptr<Module>, - std::unique_ptr<JITSymbolResolver>)>; - struct SourceModuleEntry { std::shared_ptr<Module> SourceMod; std::set<Function*> StubsToClone; @@ -349,19 +343,22 @@ private: // Create a callback, associate it with the stub for the function, // and set the compile action to compile the partition containing the // function. - auto CCInfo = CompileCallbackMgr.getCompileCallback(); - StubInits[MangledName] = - std::make_pair(CCInfo.getAddress(), - JITSymbolFlags::fromGlobalValue(F)); - CCInfo.setCompileAction([this, &LD, LMId, &F]() -> JITTargetAddress { - if (auto FnImplAddrOrErr = this->extractAndCompile(LD, LMId, F)) - return *FnImplAddrOrErr; - else { - // FIXME: Report error, return to 'abort' or something similar. - consumeError(FnImplAddrOrErr.takeError()); - return 0; - } - }); + if (auto CCInfoOrErr = CompileCallbackMgr.getCompileCallback()) { + auto &CCInfo = *CCInfoOrErr; + StubInits[MangledName] = + std::make_pair(CCInfo.getAddress(), + JITSymbolFlags::fromGlobalValue(F)); + CCInfo.setCompileAction([this, &LD, LMId, &F]() -> JITTargetAddress { + if (auto FnImplAddrOrErr = this->extractAndCompile(LD, LMId, F)) + return *FnImplAddrOrErr; + else { + // FIXME: Report error, return to 'abort' or something similar. + consumeError(FnImplAddrOrErr.takeError()); + return 0; + } + }); + } else + return CCInfoOrErr.takeError(); } if (auto Err = LD.StubsMgr->createStubs(StubInits)) diff --git a/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h b/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h index ff54ef625ebb..8a48c36f4141 100644 --- a/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h @@ -46,13 +46,14 @@ public: /// @brief Add the given module to the JIT. /// @return A handle for the added modules. - ModuleHandleT addModule(std::shared_ptr<Module> M, - std::shared_ptr<JITSymbolResolver> Resolver) { + Expected<ModuleHandleT> + addModule(std::shared_ptr<Module> M, + std::shared_ptr<JITSymbolResolver> Resolver) { return BaseLayer.addModule(std::move(M), std::move(Resolver)); } /// @brief Remove the module set associated with the handle H. - void removeModule(ModuleHandleT H) { BaseLayer.removeModule(H); } + Error removeModule(ModuleHandleT H) { return BaseLayer.removeModule(H); } /// @brief Manually set the address to return for the given symbol. void setGlobalMapping(const std::string &Name, JITTargetAddress Addr) { @@ -96,8 +97,8 @@ public: /// @brief Immediately emit and finalize the module set represented by the /// given handle. /// @param H Handle for module set to emit/finalize. - void emitAndFinalize(ModuleHandleT H) { - BaseLayer.emitAndFinalize(H); + Error emitAndFinalize(ModuleHandleT H) { + return BaseLayer.emitAndFinalize(H); } private: diff --git a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h index e038093d7628..029b86a6d2ca 100644 --- a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h +++ b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h @@ -105,10 +105,13 @@ public: } /// @brief Reserve a compile callback. - CompileCallbackInfo getCompileCallback() { - JITTargetAddress TrampolineAddr = getAvailableTrampolineAddr(); - auto &Compile = this->ActiveTrampolines[TrampolineAddr]; - return CompileCallbackInfo(TrampolineAddr, Compile); + Expected<CompileCallbackInfo> getCompileCallback() { + if (auto TrampolineAddrOrErr = getAvailableTrampolineAddr()) { + const auto &TrampolineAddr = *TrampolineAddrOrErr; + auto &Compile = this->ActiveTrampolines[TrampolineAddr]; + return CompileCallbackInfo(TrampolineAddr, Compile); + } else + return TrampolineAddrOrErr.takeError(); } /// @brief Get a CompileCallbackInfo for an existing callback. @@ -138,9 +141,10 @@ protected: std::vector<JITTargetAddress> AvailableTrampolines; private: - JITTargetAddress getAvailableTrampolineAddr() { + Expected<JITTargetAddress> getAvailableTrampolineAddr() { if (this->AvailableTrampolines.empty()) - grow(); + if (auto Err = grow()) + return std::move(Err); assert(!this->AvailableTrampolines.empty() && "Failed to grow available trampolines."); JITTargetAddress TrampolineAddr = this->AvailableTrampolines.back(); @@ -149,7 +153,7 @@ private: } // Create new trampolines - to be implemented in subclasses. - virtual void grow() = 0; + virtual Error grow() = 0; virtual void anchor(); }; @@ -188,7 +192,7 @@ private: reinterpret_cast<uintptr_t>(TrampolineId))); } - void grow() override { + Error grow() override { assert(this->AvailableTrampolines.empty() && "Growing prematurely?"); std::error_code EC; @@ -196,7 +200,8 @@ private: sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( sys::Process::getPageSize(), nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); - assert(!EC && "Failed to allocate trampoline block"); + if (EC) + return errorCodeToError(EC); unsigned NumTrampolines = (sys::Process::getPageSize() - TargetT::PointerSize) / @@ -211,12 +216,13 @@ private: static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>( TrampolineMem + (I * TargetT::TrampolineSize)))); - EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(), - sys::Memory::MF_READ | - sys::Memory::MF_EXEC); - assert(!EC && "Failed to mprotect trampoline block"); + if (auto EC = sys::Memory::protectMappedMemory( + TrampolineBlock.getMemoryBlock(), + sys::Memory::MF_READ | sys::Memory::MF_EXEC)) + return errorCodeToError(EC); TrampolineBlocks.push_back(std::move(TrampolineBlock)); + return Error::success(); } sys::OwningMemoryBlock ResolverBlock; diff --git a/include/llvm/ExecutionEngine/Orc/OrcError.h b/include/llvm/ExecutionEngine/Orc/OrcError.h index e6374b70967a..e1ac87075ac0 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcError.h +++ b/include/llvm/ExecutionEngine/Orc/OrcError.h @@ -33,7 +33,8 @@ enum class OrcErrorCode : int { RPCResponseAbandoned, UnexpectedRPCCall, UnexpectedRPCResponse, - UnknownErrorCodeFromRemote + UnknownErrorCodeFromRemote, + UnknownResourceHandle }; std::error_code orcError(OrcErrorCode ErrCode); diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h index da02250ba169..7179e5ff66fd 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h @@ -53,27 +53,26 @@ namespace remote { /// Each of the utility classes talks to a JIT server (an instance of the /// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out /// its actions. -template <typename ChannelT> -class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI { +class OrcRemoteTargetClient + : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> { public: - /// Remote memory manager. - class RCMemoryManager : public RuntimeDyld::MemoryManager { - public: - RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id) - : Client(Client), Id(Id) { - DEBUG(dbgs() << "Created remote allocator " << Id << "\n"); - } - - RCMemoryManager(const RCMemoryManager &) = delete; - RCMemoryManager &operator=(const RCMemoryManager &) = delete; - RCMemoryManager(RCMemoryManager &&) = default; - RCMemoryManager &operator=(RCMemoryManager &&) = default; + /// Remote-mapped RuntimeDyld-compatible memory manager. + class RemoteRTDyldMemoryManager : public RuntimeDyld::MemoryManager { + friend class OrcRemoteTargetClient; - ~RCMemoryManager() override { + public: + ~RemoteRTDyldMemoryManager() { Client.destroyRemoteAllocator(Id); DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n"); } + RemoteRTDyldMemoryManager(const RemoteRTDyldMemoryManager &) = delete; + RemoteRTDyldMemoryManager & + operator=(const RemoteRTDyldMemoryManager &) = delete; + RemoteRTDyldMemoryManager(RemoteRTDyldMemoryManager &&) = default; + RemoteRTDyldMemoryManager & + operator=(RemoteRTDyldMemoryManager &&) = default; + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) override { @@ -117,12 +116,8 @@ public: DEBUG(dbgs() << "Allocator " << Id << " reserved:\n"); if (CodeSize != 0) { - if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign)) - Unmapped.back().RemoteCodeAddr = *AddrOrErr; - else { - // FIXME; Add error to poll. - assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); - } + Unmapped.back().RemoteCodeAddr = + Client.reserveMem(Id, CodeSize, CodeAlign); DEBUG(dbgs() << " code: " << format("0x%016x", Unmapped.back().RemoteCodeAddr) @@ -131,12 +126,8 @@ public: } if (RODataSize != 0) { - if (auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign)) - Unmapped.back().RemoteRODataAddr = *AddrOrErr; - else { - // FIXME; Add error to poll. - assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); - } + Unmapped.back().RemoteRODataAddr = + Client.reserveMem(Id, RODataSize, RODataAlign); DEBUG(dbgs() << " ro-data: " << format("0x%016x", Unmapped.back().RemoteRODataAddr) @@ -145,12 +136,8 @@ public: } if (RWDataSize != 0) { - if (auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign)) - Unmapped.back().RemoteRWDataAddr = *AddrOrErr; - else { - // FIXME; Add error to poll. - assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); - } + Unmapped.back().RemoteRWDataAddr = + Client.reserveMem(Id, RWDataSize, RWDataAlign); DEBUG(dbgs() << " rw-data: " << format("0x%016x", Unmapped.back().RemoteRWDataAddr) @@ -168,10 +155,8 @@ public: void deregisterEHFrames() override { for (auto &Frame : RegisteredEHFrames) { - auto Err = Client.deregisterEHFrames(Frame.Addr, Frame.Size); // FIXME: Add error poll. - assert(!Err && "Failed to register remote EH frames."); - (void)Err; + Client.deregisterEHFrames(Frame.Addr, Frame.Size); } } @@ -179,44 +164,12 @@ public: const object::ObjectFile &Obj) override { DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n"); for (auto &ObjAllocs : Unmapped) { - { - JITTargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr; - for (auto &Alloc : ObjAllocs.CodeAllocs) { - NextCodeAddr = alignTo(NextCodeAddr, Alloc.getAlign()); - Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr); - DEBUG(dbgs() << " code: " - << static_cast<void *>(Alloc.getLocalAddress()) - << " -> " << format("0x%016x", NextCodeAddr) << "\n"); - Alloc.setRemoteAddress(NextCodeAddr); - NextCodeAddr += Alloc.getSize(); - } - } - { - JITTargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr; - for (auto &Alloc : ObjAllocs.RODataAllocs) { - NextRODataAddr = alignTo(NextRODataAddr, Alloc.getAlign()); - Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr); - DEBUG(dbgs() << " ro-data: " - << static_cast<void *>(Alloc.getLocalAddress()) - << " -> " << format("0x%016x", NextRODataAddr) - << "\n"); - Alloc.setRemoteAddress(NextRODataAddr); - NextRODataAddr += Alloc.getSize(); - } - } - { - JITTargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr; - for (auto &Alloc : ObjAllocs.RWDataAllocs) { - NextRWDataAddr = alignTo(NextRWDataAddr, Alloc.getAlign()); - Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr); - DEBUG(dbgs() << " rw-data: " - << static_cast<void *>(Alloc.getLocalAddress()) - << " -> " << format("0x%016x", NextRWDataAddr) - << "\n"); - Alloc.setRemoteAddress(NextRWDataAddr); - NextRWDataAddr += Alloc.getSize(); - } - } + mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs, + ObjAllocs.RemoteCodeAddr); + mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs, + ObjAllocs.RemoteRODataAddr); + mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs, + ObjAllocs.RemoteRWDataAddr); Unfinalized.push_back(std::move(ObjAllocs)); } Unmapped.clear(); @@ -226,114 +179,17 @@ public: DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n"); for (auto &ObjAllocs : Unfinalized) { - for (auto &Alloc : ObjAllocs.CodeAllocs) { - DEBUG(dbgs() << " copying code: " - << static_cast<void *>(Alloc.getLocalAddress()) << " -> " - << format("0x%016x", Alloc.getRemoteAddress()) << " (" - << Alloc.getSize() << " bytes)\n"); - if (auto Err = - Client.writeMem(Alloc.getRemoteAddress(), - Alloc.getLocalAddress(), Alloc.getSize())) { - // FIXME: Replace this once finalizeMemory can return an Error. - handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { - if (ErrMsg) { - raw_string_ostream ErrOut(*ErrMsg); - EIB.log(ErrOut); - } - }); - return true; - } - } - - if (ObjAllocs.RemoteCodeAddr) { - DEBUG(dbgs() << " setting R-X permissions on code block: " - << format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n"); - if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteCodeAddr, - sys::Memory::MF_READ | - sys::Memory::MF_EXEC)) { - // FIXME: Replace this once finalizeMemory can return an Error. - handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { - if (ErrMsg) { - raw_string_ostream ErrOut(*ErrMsg); - EIB.log(ErrOut); - } - }); - return true; - } - } + if (copyAndProtect(ObjAllocs.CodeAllocs, ObjAllocs.RemoteCodeAddr, + sys::Memory::MF_READ | sys::Memory::MF_EXEC)) + return true; - for (auto &Alloc : ObjAllocs.RODataAllocs) { - DEBUG(dbgs() << " copying ro-data: " - << static_cast<void *>(Alloc.getLocalAddress()) << " -> " - << format("0x%016x", Alloc.getRemoteAddress()) << " (" - << Alloc.getSize() << " bytes)\n"); - if (auto Err = - Client.writeMem(Alloc.getRemoteAddress(), - Alloc.getLocalAddress(), Alloc.getSize())) { - // FIXME: Replace this once finalizeMemory can return an Error. - handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { - if (ErrMsg) { - raw_string_ostream ErrOut(*ErrMsg); - EIB.log(ErrOut); - } - }); - return true; - } - } - - if (ObjAllocs.RemoteRODataAddr) { - DEBUG(dbgs() << " setting R-- permissions on ro-data block: " - << format("0x%016x", ObjAllocs.RemoteRODataAddr) - << "\n"); - if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRODataAddr, - sys::Memory::MF_READ)) { - // FIXME: Replace this once finalizeMemory can return an Error. - handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { - if (ErrMsg) { - raw_string_ostream ErrOut(*ErrMsg); - EIB.log(ErrOut); - } - }); - return false; - } - } - - for (auto &Alloc : ObjAllocs.RWDataAllocs) { - DEBUG(dbgs() << " copying rw-data: " - << static_cast<void *>(Alloc.getLocalAddress()) << " -> " - << format("0x%016x", Alloc.getRemoteAddress()) << " (" - << Alloc.getSize() << " bytes)\n"); - if (auto Err = - Client.writeMem(Alloc.getRemoteAddress(), - Alloc.getLocalAddress(), Alloc.getSize())) { - // FIXME: Replace this once finalizeMemory can return an Error. - handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { - if (ErrMsg) { - raw_string_ostream ErrOut(*ErrMsg); - EIB.log(ErrOut); - } - }); - return false; - } - } + if (copyAndProtect(ObjAllocs.RODataAllocs, ObjAllocs.RemoteRODataAddr, + sys::Memory::MF_READ)) + return true; - if (ObjAllocs.RemoteRWDataAddr) { - DEBUG(dbgs() << " setting RW- permissions on rw-data block: " - << format("0x%016x", ObjAllocs.RemoteRWDataAddr) - << "\n"); - if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr, - sys::Memory::MF_READ | - sys::Memory::MF_WRITE)) { - // FIXME: Replace this once finalizeMemory can return an Error. - handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { - if (ErrMsg) { - raw_string_ostream ErrOut(*ErrMsg); - EIB.log(ErrOut); - } - }); - return false; - } - } + if (copyAndProtect(ObjAllocs.RWDataAllocs, ObjAllocs.RemoteRWDataAddr, + sys::Memory::MF_READ | sys::Memory::MF_WRITE)) + return true; } Unfinalized.clear(); @@ -402,6 +258,60 @@ public: std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs; }; + RemoteRTDyldMemoryManager(OrcRemoteTargetClient &Client, + ResourceIdMgr::ResourceId Id) + : Client(Client), Id(Id) { + DEBUG(dbgs() << "Created remote allocator " << Id << "\n"); + } + + // Maps all allocations in Allocs to aligned blocks + void mapAllocsToRemoteAddrs(RuntimeDyld &Dyld, std::vector<Alloc> &Allocs, + JITTargetAddress NextAddr) { + for (auto &Alloc : Allocs) { + NextAddr = alignTo(NextAddr, Alloc.getAlign()); + Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextAddr); + DEBUG(dbgs() << " " << static_cast<void *>(Alloc.getLocalAddress()) + << " -> " << format("0x%016x", NextAddr) << "\n"); + Alloc.setRemoteAddress(NextAddr); + + // Only advance NextAddr if it was non-null to begin with, + // otherwise leave it as null. + if (NextAddr) + NextAddr += Alloc.getSize(); + } + } + + // Copies data for each alloc in the list, then set permissions on the + // segment. + bool copyAndProtect(const std::vector<Alloc> &Allocs, + JITTargetAddress RemoteSegmentAddr, + unsigned Permissions) { + if (RemoteSegmentAddr) { + assert(!Allocs.empty() && "No sections in allocated segment"); + + for (auto &Alloc : Allocs) { + DEBUG(dbgs() << " copying section: " + << static_cast<void *>(Alloc.getLocalAddress()) << " -> " + << format("0x%016x", Alloc.getRemoteAddress()) << " (" + << Alloc.getSize() << " bytes)\n";); + + if (Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), + Alloc.getSize())) + return true; + } + + DEBUG(dbgs() << " setting " + << (Permissions & sys::Memory::MF_READ ? 'R' : '-') + << (Permissions & sys::Memory::MF_WRITE ? 'W' : '-') + << (Permissions & sys::Memory::MF_EXEC ? 'X' : '-') + << " permissions on block: " + << format("0x%016x", RemoteSegmentAddr) << "\n"); + if (Client.setProtections(Id, RemoteSegmentAddr, Permissions)) + return true; + } + return false; + } + OrcRemoteTargetClient &Client; ResourceIdMgr::ResourceId Id; std::vector<ObjectAllocs> Unmapped; @@ -416,17 +326,14 @@ public: }; /// Remote indirect stubs manager. - class RCIndirectStubsManager : public IndirectStubsManager { + class RemoteIndirectStubsManager : public IndirectStubsManager { public: - RCIndirectStubsManager(OrcRemoteTargetClient &Remote, - ResourceIdMgr::ResourceId Id) - : Remote(Remote), Id(Id) {} - - ~RCIndirectStubsManager() override { - if (auto Err = Remote.destroyIndirectStubsManager(Id)) { - // FIXME: Thread this error back to clients. - consumeError(std::move(Err)); - } + RemoteIndirectStubsManager(OrcRemoteTargetClient &Client, + ResourceIdMgr::ResourceId Id) + : Client(Client), Id(Id) {} + + ~RemoteIndirectStubsManager() override { + Client.destroyIndirectStubsManager(Id); } Error createStub(StringRef StubName, JITTargetAddress StubAddr, @@ -474,7 +381,7 @@ public: auto I = StubIndexes.find(Name); assert(I != StubIndexes.end() && "No stub pointer for symbol"); auto Key = I->second.first; - return Remote.writePointer(getPtrAddr(Key), NewAddr); + return Client.writePointer(getPtrAddr(Key), NewAddr); } private: @@ -484,12 +391,7 @@ public: unsigned NumStubs; }; - OrcRemoteTargetClient &Remote; - ResourceIdMgr::ResourceId Id; - std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos; using StubKey = std::pair<uint16_t, uint16_t>; - std::vector<StubKey> FreeStubs; - StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; Error reserveStubs(unsigned NumStubs) { if (NumStubs <= FreeStubs.size()) @@ -500,7 +402,7 @@ public: JITTargetAddress PtrBase; unsigned NumStubsEmitted; - if (auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired)) + if (auto StubInfoOrErr = Client.emitIndirectStubs(Id, NewStubsRequired)) std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr; else return StubInfoOrErr.takeError(); @@ -519,58 +421,64 @@ public: auto Key = FreeStubs.back(); FreeStubs.pop_back(); StubIndexes[StubName] = std::make_pair(Key, StubFlags); - return Remote.writePointer(getPtrAddr(Key), InitAddr); + return Client.writePointer(getPtrAddr(Key), InitAddr); } JITTargetAddress getStubAddr(StubKey K) { assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 && "Missing stub address"); return RemoteIndirectStubsInfos[K.first].StubBase + - K.second * Remote.getIndirectStubSize(); + K.second * Client.getIndirectStubSize(); } JITTargetAddress getPtrAddr(StubKey K) { assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 && "Missing pointer address"); return RemoteIndirectStubsInfos[K.first].PtrBase + - K.second * Remote.getPointerSize(); + K.second * Client.getPointerSize(); } + + OrcRemoteTargetClient &Client; + ResourceIdMgr::ResourceId Id; + std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos; + std::vector<StubKey> FreeStubs; + StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; }; /// Remote compile callback manager. - class RCCompileCallbackManager : public JITCompileCallbackManager { + class RemoteCompileCallbackManager : public JITCompileCallbackManager { public: - RCCompileCallbackManager(JITTargetAddress ErrorHandlerAddress, - OrcRemoteTargetClient &Remote) - : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {} + RemoteCompileCallbackManager(OrcRemoteTargetClient &Client, + JITTargetAddress ErrorHandlerAddress) + : JITCompileCallbackManager(ErrorHandlerAddress), Client(Client) {} private: - void grow() override { + Error grow() override { JITTargetAddress BlockAddr = 0; uint32_t NumTrampolines = 0; - if (auto TrampolineInfoOrErr = Remote.emitTrampolineBlock()) + if (auto TrampolineInfoOrErr = Client.emitTrampolineBlock()) std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr; - else { - // FIXME: Return error. - llvm_unreachable("Failed to create trampolines"); - } + else + return TrampolineInfoOrErr.takeError(); - uint32_t TrampolineSize = Remote.getTrampolineSize(); + uint32_t TrampolineSize = Client.getTrampolineSize(); for (unsigned I = 0; I < NumTrampolines; ++I) this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize)); + + return Error::success(); } - OrcRemoteTargetClient &Remote; + OrcRemoteTargetClient &Client; }; /// Create an OrcRemoteTargetClient. /// Channel is the ChannelT instance to communicate on. It is assumed that /// the channel is ready to be read from and written to. static Expected<std::unique_ptr<OrcRemoteTargetClient>> - Create(ChannelT &Channel) { + Create(rpc::RawByteChannel &Channel, std::function<void(Error)> ReportError) { Error Err = Error::success(); - std::unique_ptr<OrcRemoteTargetClient> Client( - new OrcRemoteTargetClient(Channel, Err)); + auto Client = std::unique_ptr<OrcRemoteTargetClient>( + new OrcRemoteTargetClient(Channel, std::move(ReportError), Err)); if (Err) return std::move(Err); return std::move(Client); @@ -580,7 +488,7 @@ public: /// its result. Expected<int> callIntVoid(JITTargetAddress Addr) { DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n"); - return callB<CallIntVoid>(Addr); + return callB<exec::CallIntVoid>(Addr); } /// Call the int(int, char*[]) function at the given address in the target and @@ -589,7 +497,7 @@ public: const std::vector<std::string> &Args) { DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr) << "\n"); - return callB<CallMain>(Addr, Args); + return callB<exec::CallMain>(Addr, Args); } /// Call the void() function at the given address in the target and wait for @@ -597,45 +505,39 @@ public: Error callVoidVoid(JITTargetAddress Addr) { DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr) << "\n"); - return callB<CallVoidVoid>(Addr); + return callB<exec::CallVoidVoid>(Addr); } /// Create an RCMemoryManager which will allocate its memory on the remote /// target. - Error createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) { - assert(!MM && "MemoryManager should be null before creation."); - + Expected<std::unique_ptr<RemoteRTDyldMemoryManager>> + createRemoteMemoryManager() { auto Id = AllocatorIds.getNext(); - if (auto Err = callB<CreateRemoteAllocator>(Id)) - return Err; - MM = llvm::make_unique<RCMemoryManager>(*this, Id); - return Error::success(); + if (auto Err = callB<mem::CreateRemoteAllocator>(Id)) + return std::move(Err); + return std::unique_ptr<RemoteRTDyldMemoryManager>( + new RemoteRTDyldMemoryManager(*this, Id)); } /// Create an RCIndirectStubsManager that will allocate stubs on the remote /// target. - Error createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) { - assert(!I && "Indirect stubs manager should be null before creation."); + Expected<std::unique_ptr<RemoteIndirectStubsManager>> + createIndirectStubsManager() { auto Id = IndirectStubOwnerIds.getNext(); - if (auto Err = callB<CreateIndirectStubsOwner>(Id)) - return Err; - I = llvm::make_unique<RCIndirectStubsManager>(*this, Id); - return Error::success(); + if (auto Err = callB<stubs::CreateIndirectStubsOwner>(Id)) + return std::move(Err); + return llvm::make_unique<RemoteIndirectStubsManager>(*this, Id); } - Expected<RCCompileCallbackManager &> + Expected<RemoteCompileCallbackManager &> enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress) { - // Check for an 'out-of-band' error, e.g. from an MM destructor. - if (ExistingError) - return std::move(ExistingError); - // Emit the resolver block on the JIT server. - if (auto Err = callB<EmitResolverBlock>()) + if (auto Err = callB<stubs::EmitResolverBlock>()) return std::move(Err); // Create the callback manager. - CallbackManager.emplace(ErrorHandlerAddress, *this); - RCCompileCallbackManager &Mgr = *CallbackManager; + CallbackManager.emplace(*this, ErrorHandlerAddress); + RemoteCompileCallbackManager &Mgr = *CallbackManager; return Mgr; } @@ -643,45 +545,43 @@ public: /// symbol resolvers *after* they've searched the local symbol table in the /// JIT stack. Expected<JITTargetAddress> getSymbolAddress(StringRef Name) { - // Check for an 'out-of-band' error, e.g. from an MM destructor. - if (ExistingError) - return std::move(ExistingError); - - return callB<GetSymbolAddress>(Name); + return callB<utils::GetSymbolAddress>(Name); } /// Get the triple for the remote target. const std::string &getTargetTriple() const { return RemoteTargetTriple; } - Error terminateSession() { return callB<TerminateSession>(); } + Error terminateSession() { return callB<utils::TerminateSession>(); } private: - OrcRemoteTargetClient(ChannelT &Channel, Error &Err) - : OrcRemoteTargetRPCAPI(Channel) { + OrcRemoteTargetClient(rpc::RawByteChannel &Channel, + std::function<void(Error)> ReportError, Error &Err) + : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(Channel, true), + ReportError(std::move(ReportError)) { ErrorAsOutParameter EAO(&Err); - addHandler<RequestCompile>( + addHandler<utils::RequestCompile>( [this](JITTargetAddress Addr) -> JITTargetAddress { if (CallbackManager) return CallbackManager->executeCompileCallback(Addr); return 0; }); - if (auto RIOrErr = callB<GetRemoteInfo>()) { + if (auto RIOrErr = callB<utils::GetRemoteInfo>()) { std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize, RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr; Err = Error::success(); - } else { - Err = joinErrors(RIOrErr.takeError(), std::move(ExistingError)); - } + } else + Err = RIOrErr.takeError(); } - Error deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) { - return callB<RegisterEHFrames>(Addr, Size); + void deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) { + if (auto Err = callB<eh::RegisterEHFrames>(Addr, Size)) + ReportError(std::move(Err)); } void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { - if (auto Err = callB<DestroyRemoteAllocator>(Id)) { + if (auto Err = callB<mem::DestroyRemoteAllocator>(Id)) { // FIXME: This will be triggered by a removeModuleSet call: Propagate // error return up through that. llvm_unreachable("Failed to destroy remote allocator."); @@ -689,22 +589,19 @@ private: } } - Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) { + void destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) { IndirectStubOwnerIds.release(Id); - return callB<DestroyIndirectStubsOwner>(Id); + if (auto Err = callB<stubs::DestroyIndirectStubsOwner>(Id)) + ReportError(std::move(Err)); } Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>> emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) { - return callB<EmitIndirectStubs>(Id, NumStubsRequired); + return callB<stubs::EmitIndirectStubs>(Id, NumStubsRequired); } Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() { - // Check for an 'out-of-band' error, e.g. from an MM destructor. - if (ExistingError) - return std::move(ExistingError); - - return callB<EmitTrampolineBlock>(); + return callB<stubs::EmitTrampolineBlock>(); } uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; } @@ -713,59 +610,57 @@ private: uint32_t getTrampolineSize() const { return RemoteTrampolineSize; } - Expected<std::vector<char>> readMem(char *Dst, JITTargetAddress Src, - uint64_t Size) { - // Check for an 'out-of-band' error, e.g. from an MM destructor. - if (ExistingError) - return std::move(ExistingError); - - return callB<ReadMem>(Src, Size); + Expected<std::vector<uint8_t>> readMem(char *Dst, JITTargetAddress Src, + uint64_t Size) { + return callB<mem::ReadMem>(Src, Size); } Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) { - return callB<RegisterEHFrames>(RAddr, Size); + // FIXME: Duplicate error and report it via ReportError too? + return callB<eh::RegisterEHFrames>(RAddr, Size); } - Expected<JITTargetAddress> reserveMem(ResourceIdMgr::ResourceId Id, - uint64_t Size, uint32_t Align) { - // Check for an 'out-of-band' error, e.g. from an MM destructor. - if (ExistingError) - return std::move(ExistingError); - - return callB<ReserveMem>(Id, Size, Align); + JITTargetAddress reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size, + uint32_t Align) { + if (auto AddrOrErr = callB<mem::ReserveMem>(Id, Size, Align)) + return *AddrOrErr; + else { + ReportError(AddrOrErr.takeError()); + return 0; + } } - Error setProtections(ResourceIdMgr::ResourceId Id, - JITTargetAddress RemoteSegAddr, unsigned ProtFlags) { - return callB<SetProtections>(Id, RemoteSegAddr, ProtFlags); + bool setProtections(ResourceIdMgr::ResourceId Id, + JITTargetAddress RemoteSegAddr, unsigned ProtFlags) { + if (auto Err = callB<mem::SetProtections>(Id, RemoteSegAddr, ProtFlags)) { + ReportError(std::move(Err)); + return true; + } else + return false; } - Error writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) { - // Check for an 'out-of-band' error, e.g. from an MM destructor. - if (ExistingError) - return std::move(ExistingError); - - return callB<WriteMem>(DirectBufferWriter(Src, Addr, Size)); + bool writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) { + if (auto Err = callB<mem::WriteMem>(DirectBufferWriter(Src, Addr, Size))) { + ReportError(std::move(Err)); + return true; + } else + return false; } Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) { - // Check for an 'out-of-band' error, e.g. from an MM destructor. - if (ExistingError) - return std::move(ExistingError); - - return callB<WritePtr>(Addr, PtrVal); + return callB<mem::WritePtr>(Addr, PtrVal); } static Error doNothing() { return Error::success(); } - Error ExistingError = Error::success(); + std::function<void(Error)> ReportError; std::string RemoteTargetTriple; uint32_t RemotePointerSize = 0; uint32_t RemotePageSize = 0; uint32_t RemoteTrampolineSize = 0; uint32_t RemoteIndirectStubSize = 0; ResourceIdMgr AllocatorIds, IndirectStubOwnerIds; - Optional<RCCompileCallbackManager> CallbackManager; + Optional<RemoteCompileCallbackManager> CallbackManager; }; } // end namespace remote diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h index 07ae7f04d1a0..bc0da0f9a730 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h @@ -25,6 +25,37 @@ namespace orc { namespace remote { +/// Template error for missing resources. +template <typename ResourceIdT> +class ResourceNotFound + : public ErrorInfo<ResourceNotFound<ResourceIdT>> { +public: + static char ID; + + ResourceNotFound(ResourceIdT ResourceId, + std::string ResourceDescription = "") + : ResourceId(std::move(ResourceId)), + ResourceDescription(std::move(ResourceDescription)) {} + + std::error_code convertToErrorCode() const override { + return orcError(OrcErrorCode::UnknownResourceHandle); + } + + void log(raw_ostream &OS) const override { + OS << (ResourceDescription.empty() + ? "Remote resource with id " + : ResourceDescription) + << " " << ResourceId << " not found"; + } + +private: + ResourceIdT ResourceId; + std::string ResourceDescription; +}; + +template <typename ResourceIdT> +char ResourceNotFound<ResourceIdT>::ID = 0; + class DirectBufferWriter { public: DirectBufferWriter() = default; @@ -45,6 +76,32 @@ private: namespace rpc { +template <> +class RPCTypeName<JITSymbolFlags> { +public: + static const char *getName() { return "JITSymbolFlags"; } +}; + +template <typename ChannelT> +class SerializationTraits<ChannelT, JITSymbolFlags> { +public: + + static Error serialize(ChannelT &C, const JITSymbolFlags &Flags) { + return serializeSeq(C, static_cast<JITSymbolFlags::UnderlyingType>(Flags), + Flags.getTargetFlags()); + } + + static Error deserialize(ChannelT &C, JITSymbolFlags &Flags) { + JITSymbolFlags::UnderlyingType JITFlags; + JITSymbolFlags::TargetFlagsType TargetFlags; + if (auto Err = deserializeSeq(C, JITFlags, TargetFlags)) + return Err; + Flags = JITSymbolFlags(static_cast<JITSymbolFlags::FlagNames>(JITFlags), + TargetFlags); + return Error::success(); + } +}; + template <> class RPCTypeName<remote::DirectBufferWriter> { public: static const char *getName() { return "DirectBufferWriter"; } @@ -83,41 +140,66 @@ public: namespace remote { -class OrcRemoteTargetRPCAPI - : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> { -protected: - class ResourceIdMgr { - public: - using ResourceId = uint64_t; - static const ResourceId InvalidId = ~0U; - - ResourceId getNext() { - if (!FreeIds.empty()) { - ResourceId I = FreeIds.back(); - FreeIds.pop_back(); - return I; - } - return NextId++; +class ResourceIdMgr { +public: + using ResourceId = uint64_t; + static const ResourceId InvalidId = ~0U; + + ResourceIdMgr() = default; + explicit ResourceIdMgr(ResourceId FirstValidId) + : NextId(std::move(FirstValidId)) {} + + ResourceId getNext() { + if (!FreeIds.empty()) { + ResourceId I = FreeIds.back(); + FreeIds.pop_back(); + return I; } + assert(NextId + 1 != ~0ULL && "All ids allocated"); + return NextId++; + } + + void release(ResourceId I) { FreeIds.push_back(I); } + +private: + ResourceId NextId = 1; + std::vector<ResourceId> FreeIds; +}; - void release(ResourceId I) { FreeIds.push_back(I); } +/// Registers EH frames on the remote. +namespace eh { - private: - ResourceId NextId = 0; - std::vector<ResourceId> FreeIds; + /// Registers EH frames on the remote. + class RegisterEHFrames + : public rpc::Function<RegisterEHFrames, + void(JITTargetAddress Addr, uint32_t Size)> { + public: + static const char *getName() { return "RegisterEHFrames"; } }; -public: - // FIXME: Remove constructors once MSVC supports synthesizing move-ops. - OrcRemoteTargetRPCAPI(rpc::RawByteChannel &C) - : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(C, true) {} + /// Deregisters EH frames on the remote. + class DeregisterEHFrames + : public rpc::Function<DeregisterEHFrames, + void(JITTargetAddress Addr, uint32_t Size)> { + public: + static const char *getName() { return "DeregisterEHFrames"; } + }; + +} // end namespace eh + +/// RPC functions for executing remote code. +namespace exec { + /// Call an 'int32_t()'-type function on the remote, returns the called + /// function's return value. class CallIntVoid : public rpc::Function<CallIntVoid, int32_t(JITTargetAddress Addr)> { public: static const char *getName() { return "CallIntVoid"; } }; + /// Call an 'int32_t(int32_t, char**)'-type function on the remote, returns the + /// called function's return value. class CallMain : public rpc::Function<CallMain, int32_t(JITTargetAddress Addr, std::vector<std::string> Args)> { @@ -125,12 +207,20 @@ public: static const char *getName() { return "CallMain"; } }; + /// Calls a 'void()'-type function on the remote, returns when the called + /// function completes. class CallVoidVoid : public rpc::Function<CallVoidVoid, void(JITTargetAddress FnAddr)> { public: static const char *getName() { return "CallVoidVoid"; } }; +} // end namespace exec + +/// RPC functions for remote memory management / inspection / modification. +namespace mem { + + /// Creates a memory allocator on the remote. class CreateRemoteAllocator : public rpc::Function<CreateRemoteAllocator, void(ResourceIdMgr::ResourceId AllocatorID)> { @@ -138,27 +228,68 @@ public: static const char *getName() { return "CreateRemoteAllocator"; } }; - class CreateIndirectStubsOwner - : public rpc::Function<CreateIndirectStubsOwner, - void(ResourceIdMgr::ResourceId StubOwnerID)> { + /// Destroys a remote allocator, freeing any memory allocated by it. + class DestroyRemoteAllocator + : public rpc::Function<DestroyRemoteAllocator, + void(ResourceIdMgr::ResourceId AllocatorID)> { public: - static const char *getName() { return "CreateIndirectStubsOwner"; } + static const char *getName() { return "DestroyRemoteAllocator"; } }; - class DeregisterEHFrames - : public rpc::Function<DeregisterEHFrames, - void(JITTargetAddress Addr, uint32_t Size)> { + /// Read a remote memory block. + class ReadMem + : public rpc::Function<ReadMem, std::vector<uint8_t>(JITTargetAddress Src, + uint64_t Size)> { public: - static const char *getName() { return "DeregisterEHFrames"; } + static const char *getName() { return "ReadMem"; } }; - class DestroyRemoteAllocator - : public rpc::Function<DestroyRemoteAllocator, - void(ResourceIdMgr::ResourceId AllocatorID)> { + /// Reserve a block of memory on the remote via the given allocator. + class ReserveMem + : public rpc::Function<ReserveMem, + JITTargetAddress(ResourceIdMgr::ResourceId AllocID, + uint64_t Size, uint32_t Align)> { public: - static const char *getName() { return "DestroyRemoteAllocator"; } + static const char *getName() { return "ReserveMem"; } + }; + + /// Set the memory protection on a memory block. + class SetProtections + : public rpc::Function<SetProtections, + void(ResourceIdMgr::ResourceId AllocID, + JITTargetAddress Dst, uint32_t ProtFlags)> { + public: + static const char *getName() { return "SetProtections"; } + }; + + /// Write to a remote memory block. + class WriteMem + : public rpc::Function<WriteMem, void(remote::DirectBufferWriter DB)> { + public: + static const char *getName() { return "WriteMem"; } + }; + + /// Write to a remote pointer. + class WritePtr : public rpc::Function<WritePtr, void(JITTargetAddress Dst, + JITTargetAddress Val)> { + public: + static const char *getName() { return "WritePtr"; } + }; + +} // end namespace mem + +/// RPC functions for remote stub and trampoline management. +namespace stubs { + + /// Creates an indirect stub owner on the remote. + class CreateIndirectStubsOwner + : public rpc::Function<CreateIndirectStubsOwner, + void(ResourceIdMgr::ResourceId StubOwnerID)> { + public: + static const char *getName() { return "CreateIndirectStubsOwner"; } }; + /// RPC function for destroying an indirect stubs owner. class DestroyIndirectStubsOwner : public rpc::Function<DestroyIndirectStubsOwner, void(ResourceIdMgr::ResourceId StubsOwnerID)> { @@ -177,6 +308,7 @@ public: static const char *getName() { return "EmitIndirectStubs"; } }; + /// RPC function to emit the resolver block and return its address. class EmitResolverBlock : public rpc::Function<EmitResolverBlock, void()> { public: static const char *getName() { return "EmitResolverBlock"; } @@ -190,12 +322,10 @@ public: static const char *getName() { return "EmitTrampolineBlock"; } }; - class GetSymbolAddress - : public rpc::Function<GetSymbolAddress, - JITTargetAddress(std::string SymbolName)> { - public: - static const char *getName() { return "GetSymbolAddress"; } - }; +} // end namespace stubs + +/// Miscelaneous RPC functions for dealing with remotes. +namespace utils { /// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize, /// IndirectStubsSize). @@ -207,28 +337,15 @@ public: static const char *getName() { return "GetRemoteInfo"; } }; - class ReadMem - : public rpc::Function<ReadMem, std::vector<uint8_t>(JITTargetAddress Src, - uint64_t Size)> { - public: - static const char *getName() { return "ReadMem"; } - }; - - class RegisterEHFrames - : public rpc::Function<RegisterEHFrames, - void(JITTargetAddress Addr, uint32_t Size)> { - public: - static const char *getName() { return "RegisterEHFrames"; } - }; - - class ReserveMem - : public rpc::Function<ReserveMem, - JITTargetAddress(ResourceIdMgr::ResourceId AllocID, - uint64_t Size, uint32_t Align)> { + /// Get the address of a remote symbol. + class GetSymbolAddress + : public rpc::Function<GetSymbolAddress, + JITTargetAddress(std::string SymbolName)> { public: - static const char *getName() { return "ReserveMem"; } + static const char *getName() { return "GetSymbolAddress"; } }; + /// Request that the host execute a compile callback. class RequestCompile : public rpc::Function< RequestCompile, JITTargetAddress(JITTargetAddress TrampolineAddr)> { @@ -236,30 +353,20 @@ public: static const char *getName() { return "RequestCompile"; } }; - class SetProtections - : public rpc::Function<SetProtections, - void(ResourceIdMgr::ResourceId AllocID, - JITTargetAddress Dst, uint32_t ProtFlags)> { - public: - static const char *getName() { return "SetProtections"; } - }; - + /// Notify the remote and terminate the session. class TerminateSession : public rpc::Function<TerminateSession, void()> { public: static const char *getName() { return "TerminateSession"; } }; - class WriteMem - : public rpc::Function<WriteMem, void(remote::DirectBufferWriter DB)> { - public: - static const char *getName() { return "WriteMem"; } - }; +} // namespace utils - class WritePtr : public rpc::Function<WritePtr, void(JITTargetAddress Dst, - JITTargetAddress Val)> { - public: - static const char *getName() { return "WritePtr"; } - }; +class OrcRemoteTargetRPCAPI + : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> { +public: + // FIXME: Remove constructors once MSVC supports synthesizing move-ops. + OrcRemoteTargetRPCAPI(rpc::RawByteChannel &C) + : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(C, true) {} }; } // end namespace remote diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h index e7b6d64931b6..cf419d33004c 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h @@ -45,7 +45,8 @@ namespace orc { namespace remote { template <typename ChannelT, typename TargetT> -class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI { +class OrcRemoteTargetServer + : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> { public: using SymbolLookupFtor = std::function<JITTargetAddress(const std::string &Name)>; @@ -56,34 +57,38 @@ public: OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup, EHFrameRegistrationFtor EHFramesRegister, EHFrameRegistrationFtor EHFramesDeregister) - : OrcRemoteTargetRPCAPI(Channel), SymbolLookup(std::move(SymbolLookup)), + : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(Channel, true), + SymbolLookup(std::move(SymbolLookup)), EHFramesRegister(std::move(EHFramesRegister)), EHFramesDeregister(std::move(EHFramesDeregister)) { using ThisT = typename std::remove_reference<decltype(*this)>::type; - addHandler<CallIntVoid>(*this, &ThisT::handleCallIntVoid); - addHandler<CallMain>(*this, &ThisT::handleCallMain); - addHandler<CallVoidVoid>(*this, &ThisT::handleCallVoidVoid); - addHandler<CreateRemoteAllocator>(*this, - &ThisT::handleCreateRemoteAllocator); - addHandler<CreateIndirectStubsOwner>( + addHandler<exec::CallIntVoid>(*this, &ThisT::handleCallIntVoid); + addHandler<exec::CallMain>(*this, &ThisT::handleCallMain); + addHandler<exec::CallVoidVoid>(*this, &ThisT::handleCallVoidVoid); + addHandler<mem::CreateRemoteAllocator>(*this, + &ThisT::handleCreateRemoteAllocator); + addHandler<mem::DestroyRemoteAllocator>( + *this, &ThisT::handleDestroyRemoteAllocator); + addHandler<mem::ReadMem>(*this, &ThisT::handleReadMem); + addHandler<mem::ReserveMem>(*this, &ThisT::handleReserveMem); + addHandler<mem::SetProtections>(*this, &ThisT::handleSetProtections); + addHandler<mem::WriteMem>(*this, &ThisT::handleWriteMem); + addHandler<mem::WritePtr>(*this, &ThisT::handleWritePtr); + addHandler<eh::RegisterEHFrames>(*this, &ThisT::handleRegisterEHFrames); + addHandler<eh::DeregisterEHFrames>(*this, &ThisT::handleDeregisterEHFrames); + addHandler<stubs::CreateIndirectStubsOwner>( *this, &ThisT::handleCreateIndirectStubsOwner); - addHandler<DeregisterEHFrames>(*this, &ThisT::handleDeregisterEHFrames); - addHandler<DestroyRemoteAllocator>(*this, - &ThisT::handleDestroyRemoteAllocator); - addHandler<DestroyIndirectStubsOwner>( + addHandler<stubs::DestroyIndirectStubsOwner>( *this, &ThisT::handleDestroyIndirectStubsOwner); - addHandler<EmitIndirectStubs>(*this, &ThisT::handleEmitIndirectStubs); - addHandler<EmitResolverBlock>(*this, &ThisT::handleEmitResolverBlock); - addHandler<EmitTrampolineBlock>(*this, &ThisT::handleEmitTrampolineBlock); - addHandler<GetSymbolAddress>(*this, &ThisT::handleGetSymbolAddress); - addHandler<GetRemoteInfo>(*this, &ThisT::handleGetRemoteInfo); - addHandler<ReadMem>(*this, &ThisT::handleReadMem); - addHandler<RegisterEHFrames>(*this, &ThisT::handleRegisterEHFrames); - addHandler<ReserveMem>(*this, &ThisT::handleReserveMem); - addHandler<SetProtections>(*this, &ThisT::handleSetProtections); - addHandler<TerminateSession>(*this, &ThisT::handleTerminateSession); - addHandler<WriteMem>(*this, &ThisT::handleWriteMem); - addHandler<WritePtr>(*this, &ThisT::handleWritePtr); + addHandler<stubs::EmitIndirectStubs>(*this, + &ThisT::handleEmitIndirectStubs); + addHandler<stubs::EmitResolverBlock>(*this, + &ThisT::handleEmitResolverBlock); + addHandler<stubs::EmitTrampolineBlock>(*this, + &ThisT::handleEmitTrampolineBlock); + addHandler<utils::GetSymbolAddress>(*this, &ThisT::handleGetSymbolAddress); + addHandler<utils::GetRemoteInfo>(*this, &ThisT::handleGetRemoteInfo); + addHandler<utils::TerminateSession>(*this, &ThisT::handleTerminateSession); } // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops. @@ -94,7 +99,7 @@ public: OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete; Expected<JITTargetAddress> requestCompile(JITTargetAddress TrampolineAddr) { - return callB<RequestCompile>(TrampolineAddr); + return callB<utils::RequestCompile>(TrampolineAddr); } bool receivedTerminate() const { return TerminateFlag; } diff --git a/include/llvm/ExecutionEngine/Orc/RPCSerialization.h b/include/llvm/ExecutionEngine/Orc/RPCSerialization.h index 1cb2448a3a44..569c50602f3a 100644 --- a/include/llvm/ExecutionEngine/Orc/RPCSerialization.h +++ b/include/llvm/ExecutionEngine/Orc/RPCSerialization.h @@ -361,13 +361,13 @@ public: std::lock_guard<std::recursive_mutex> Lock(SerializersMutex); // FIXME: Move capture Serialize once we have C++14. Serializers[ErrorInfoT::classID()] = - [KeyName, Serialize](ChannelT &C, const ErrorInfoBase &EIB) -> Error { - assert(EIB.dynamicClassID() == ErrorInfoT::classID() && - "Serializer called for wrong error type"); - if (auto Err = serializeSeq(C, *KeyName)) - return Err; - return Serialize(C, static_cast<const ErrorInfoT&>(EIB)); - }; + [KeyName, Serialize](ChannelT &C, const ErrorInfoBase &EIB) -> Error { + assert(EIB.dynamicClassID() == ErrorInfoT::classID() && + "Serializer called for wrong error type"); + if (auto Err = serializeSeq(C, *KeyName)) + return Err; + return Serialize(C, static_cast<const ErrorInfoT &>(EIB)); + }; } } diff --git a/include/llvm/ExecutionEngine/Orc/RPCUtils.h b/include/llvm/ExecutionEngine/Orc/RPCUtils.h index 6212f64ff319..c278cb176853 100644 --- a/include/llvm/ExecutionEngine/Orc/RPCUtils.h +++ b/include/llvm/ExecutionEngine/Orc/RPCUtils.h @@ -534,6 +534,20 @@ public: using ResultType = Error; }; +template <typename... ArgTs> +class AsyncHandlerTraits<ErrorSuccess(std::function<Error(Error)>, ArgTs...)> { +public: + using Type = Error(ArgTs...); + using ResultType = Error; +}; + +template <typename... ArgTs> +class AsyncHandlerTraits<void(std::function<Error(Error)>, ArgTs...)> { +public: + using Type = Error(ArgTs...); + using ResultType = Error; +}; + template <typename ResponseHandlerT, typename... ArgTs> class AsyncHandlerTraits<Error(ResponseHandlerT, ArgTs...)> : public AsyncHandlerTraits<Error(typename std::decay<ResponseHandlerT>::type, diff --git a/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h index e1016ef95f0c..246c57341f35 100644 --- a/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h @@ -41,9 +41,9 @@ public: protected: - /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT. + /// @brief Holds an object to be allocated/linked as a unit in the JIT. /// - /// An instance of this class will be created for each set of objects added + /// An instance of this class will be created for each object added /// via JITObjectLayer::addObject. Deleting the instance (via /// removeObject) frees its memory, removing all symbol definitions that /// had been provided by this instance. Higher level layers are responsible @@ -83,7 +83,7 @@ protected: using LinkedObjectListT = std::list<std::unique_ptr<LinkedObject>>; public: - /// @brief Handle to a set of loaded objects. + /// @brief Handle to a loaded object. using ObjHandleT = LinkedObjectListT::iterator; }; @@ -99,8 +99,9 @@ public: using RTDyldObjectLinkingLayerBase::ObjectPtr; /// @brief Functor for receiving object-loaded notifications. - using NotifyLoadedFtor = std::function<void(ObjHandleT, const ObjectPtr &Obj, - const LoadedObjectInfo &)>; + using NotifyLoadedFtor = + std::function<void(ObjHandleT, const ObjectPtr &Obj, + const RuntimeDyld::LoadedObjectInfo &)>; /// @brief Functor for receiving finalization notifications. using NotifyFinalizedFtor = std::function<void(ObjHandleT)>; @@ -253,10 +254,9 @@ public: this->ProcessAllSections = ProcessAllSections; } - /// @brief Add a set of objects (or archives) that will be treated as a unit - /// for the purposes of symbol lookup and memory management. + /// @brief Add an object to the JIT. /// - /// @return A handle that can be used to refer to the loaded objects (for + /// @return A handle that can be used to refer to the loaded object (for /// symbol searching, finalization, freeing memory, etc.). Expected<ObjHandleT> addObject(ObjectPtr Obj, std::shared_ptr<JITSymbolResolver> Resolver) { @@ -291,10 +291,10 @@ public: return Handle; } - /// @brief Remove the set of objects associated with handle H. + /// @brief Remove the object associated with handle H. /// - /// All memory allocated for the objects will be freed, and the sections and - /// symbols they provided will no longer be available. No attempt is made to + /// All memory allocated for the object will be freed, and the sections and + /// symbols it provided will no longer be available. No attempt is made to /// re-emit the missing symbols, and any use of these symbols (directly or /// indirectly) will result in undefined behavior. If dependence tracking is /// required to detect or resolve such issues it should be added at a higher @@ -318,27 +318,27 @@ public: return nullptr; } - /// @brief Search for the given named symbol in the context of the set of - /// loaded objects represented by the handle H. - /// @param H The handle for the object set to search in. + /// @brief Search for the given named symbol in the context of the loaded + /// object represented by the handle H. + /// @param H The handle for the object to search in. /// @param Name The name of the symbol to search for. /// @param ExportedSymbolsOnly If true, search only for exported symbols. /// @return A handle for the given named symbol, if it is found in the - /// given object set. + /// given object. JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) { return (*H)->getSymbol(Name, ExportedSymbolsOnly); } - /// @brief Map section addresses for the objects associated with the handle H. + /// @brief Map section addresses for the object associated with the handle H. void mapSectionAddress(ObjHandleT H, const void *LocalAddress, JITTargetAddress TargetAddr) { (*H)->mapSectionAddress(LocalAddress, TargetAddr); } - /// @brief Immediately emit and finalize the object set represented by the - /// given handle. - /// @param H Handle for object set to emit/finalize. + /// @brief Immediately emit and finalize the object represented by the given + /// handle. + /// @param H Handle for object to emit/finalize. Error emitAndFinalize(ObjHandleT H) { (*H)->finalize(); return Error::success(); diff --git a/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h b/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h new file mode 100644 index 000000000000..17255954a99f --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h @@ -0,0 +1,538 @@ +//===------ RemoteObjectLayer.h - Forwards objs to a remote -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Forwards objects to a remote object layer via RPC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H +#define LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H + +#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include <map> + +namespace llvm { +namespace orc { + +/// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer. +class RemoteObjectLayerAPI { +public: + + using ObjHandleT = remote::ResourceIdMgr::ResourceId; + +protected: + + using RemoteSymbolId = remote::ResourceIdMgr::ResourceId; + using RemoteSymbol = std::pair<RemoteSymbolId, JITSymbolFlags>; + +public: + + using BadSymbolHandleError = remote::ResourceNotFound<RemoteSymbolId>; + using BadObjectHandleError = remote::ResourceNotFound<ObjHandleT>; + +protected: + + static const ObjHandleT InvalidObjectHandleId = 0; + static const RemoteSymbolId NullSymbolId = 0; + + class AddObject + : public rpc::Function<AddObject, Expected<ObjHandleT>(std::string)> { + public: + static const char *getName() { return "AddObject"; } + }; + + class RemoveObject + : public rpc::Function<RemoveObject, Error(ObjHandleT)> { + public: + static const char *getName() { return "RemoveObject"; } + }; + + class FindSymbol + : public rpc::Function<FindSymbol, Expected<RemoteSymbol>(std::string, + bool)> { + public: + static const char *getName() { return "FindSymbol"; } + }; + + class FindSymbolIn + : public rpc::Function<FindSymbolIn, + Expected<RemoteSymbol>(ObjHandleT, std::string, + bool)> { + public: + static const char *getName() { return "FindSymbolIn"; } + }; + + class EmitAndFinalize + : public rpc::Function<EmitAndFinalize, + Error(ObjHandleT)> { + public: + static const char *getName() { return "EmitAndFinalize"; } + }; + + class Lookup + : public rpc::Function<Lookup, + Expected<RemoteSymbol>(ObjHandleT, std::string)> { + public: + static const char *getName() { return "Lookup"; } + }; + + class LookupInLogicalDylib + : public rpc::Function<LookupInLogicalDylib, + Expected<RemoteSymbol>(ObjHandleT, std::string)> { + public: + static const char *getName() { return "LookupInLogicalDylib"; } + }; + + class ReleaseRemoteSymbol + : public rpc::Function<ReleaseRemoteSymbol, Error(RemoteSymbolId)> { + public: + static const char *getName() { return "ReleaseRemoteSymbol"; } + }; + + class MaterializeRemoteSymbol + : public rpc::Function<MaterializeRemoteSymbol, + Expected<JITTargetAddress>(RemoteSymbolId)> { + public: + static const char *getName() { return "MaterializeRemoteSymbol"; } + }; +}; + +/// Base class containing common utilities for RemoteObjectClientLayer and +/// RemoteObjectServerLayer. +template <typename RPCEndpoint> +class RemoteObjectLayer : public RemoteObjectLayerAPI { +public: + + RemoteObjectLayer(RPCEndpoint &Remote, + std::function<void(Error)> ReportError) + : Remote(Remote), ReportError(std::move(ReportError)), + SymbolIdMgr(NullSymbolId + 1) { + using ThisT = RemoteObjectLayer<RPCEndpoint>; + Remote.template addHandler<ReleaseRemoteSymbol>( + *this, &ThisT::handleReleaseRemoteSymbol); + Remote.template addHandler<MaterializeRemoteSymbol>( + *this, &ThisT::handleMaterializeRemoteSymbol); + } + +protected: + + /// This class is used as the symbol materializer for JITSymbols returned by + /// RemoteObjectLayerClient/RemoteObjectLayerServer -- the materializer knows + /// how to call back to the other RPC endpoint to get the address when + /// requested. + class RemoteSymbolMaterializer { + public: + + /// Construct a RemoteSymbolMaterializer for the given RemoteObjectLayer + /// with the given Id. + RemoteSymbolMaterializer(RemoteObjectLayer &C, + RemoteSymbolId Id) + : C(C), Id(Id) {} + + RemoteSymbolMaterializer(const RemoteSymbolMaterializer &Other) + : C(Other.C), Id(Other.Id) { + // FIXME: This is a horrible, auto_ptr-style, copy-as-move operation. + // It should be removed as soon as LLVM has C++14's generalized + // lambda capture (at which point the materializer can be moved + // into the lambda in remoteToJITSymbol below). + const_cast<RemoteSymbolMaterializer&>(Other).Id = 0; + } + + RemoteSymbolMaterializer& + operator=(const RemoteSymbolMaterializer&) = delete; + + /// Release the remote symbol. + ~RemoteSymbolMaterializer() { + if (Id) + C.releaseRemoteSymbol(Id); + } + + /// Materialize the symbol on the remote and get its address. + Expected<JITTargetAddress> materialize() { + auto Addr = C.materializeRemoteSymbol(Id); + Id = 0; + return Addr; + } + + private: + RemoteObjectLayer &C; + RemoteSymbolId Id; + }; + + /// Convenience function for getting a null remote symbol value. + RemoteSymbol nullRemoteSymbol() { + return RemoteSymbol(0, JITSymbolFlags()); + } + + /// Creates a StringError that contains a copy of Err's log message, then + /// sends that StringError to ReportError. + /// + /// This allows us to locally log error messages for errors that will actually + /// be delivered to the remote. + Error teeLog(Error Err) { + return handleErrors(std::move(Err), + [this](std::unique_ptr<ErrorInfoBase> EIB) { + ReportError(make_error<StringError>( + EIB->message(), + EIB->convertToErrorCode())); + return Error(std::move(EIB)); + }); + } + + Error badRemoteSymbolIdError(RemoteSymbolId Id) { + return make_error<BadSymbolHandleError>(Id, "Remote JIT Symbol"); + } + + Error badObjectHandleError(ObjHandleT H) { + return make_error<RemoteObjectLayerAPI::BadObjectHandleError>( + H, "Bad object handle"); + } + + /// Create a RemoteSymbol wrapping the given JITSymbol. + Expected<RemoteSymbol> jitSymbolToRemote(JITSymbol Sym) { + if (Sym) { + auto Id = SymbolIdMgr.getNext(); + auto Flags = Sym.getFlags(); + assert(!InUseSymbols.count(Id) && "Symbol id already in use"); + InUseSymbols.insert(std::make_pair(Id, std::move(Sym))); + return RemoteSymbol(Id, Flags); + } else if (auto Err = Sym.takeError()) + return teeLog(std::move(Err)); + // else... + return nullRemoteSymbol(); + } + + /// Convert an Expected<RemoteSymbol> to a JITSymbol. + JITSymbol remoteToJITSymbol(Expected<RemoteSymbol> RemoteSymOrErr) { + if (RemoteSymOrErr) { + auto &RemoteSym = *RemoteSymOrErr; + if (RemoteSym == nullRemoteSymbol()) + return nullptr; + // else... + RemoteSymbolMaterializer RSM(*this, RemoteSym.first); + auto Sym = + JITSymbol([RSM]() mutable { return RSM.materialize(); }, + RemoteSym.second); + return Sym; + } else + return RemoteSymOrErr.takeError(); + } + + RPCEndpoint &Remote; + std::function<void(Error)> ReportError; + +private: + + /// Notify the remote to release the given JITSymbol. + void releaseRemoteSymbol(RemoteSymbolId Id) { + if (auto Err = Remote.template callB<ReleaseRemoteSymbol>(Id)) + ReportError(std::move(Err)); + } + + /// Notify the remote to materialize the JITSymbol with the given Id and + /// return its address. + Expected<JITTargetAddress> materializeRemoteSymbol(RemoteSymbolId Id) { + return Remote.template callB<MaterializeRemoteSymbol>(Id); + } + + /// Release the JITSymbol with the given Id. + Error handleReleaseRemoteSymbol(RemoteSymbolId Id) { + auto SI = InUseSymbols.find(Id); + if (SI != InUseSymbols.end()) { + InUseSymbols.erase(SI); + return Error::success(); + } else + return teeLog(badRemoteSymbolIdError(Id)); + } + + /// Run the materializer for the JITSymbol with the given Id and return its + /// address. + Expected<JITTargetAddress> handleMaterializeRemoteSymbol(RemoteSymbolId Id) { + auto SI = InUseSymbols.find(Id); + if (SI != InUseSymbols.end()) { + auto AddrOrErr = SI->second.getAddress(); + InUseSymbols.erase(SI); + SymbolIdMgr.release(Id); + if (AddrOrErr) + return *AddrOrErr; + else + return teeLog(AddrOrErr.takeError()); + } else { + return teeLog(badRemoteSymbolIdError(Id)); + } + } + + remote::ResourceIdMgr SymbolIdMgr; + std::map<RemoteSymbolId, JITSymbol> InUseSymbols; +}; + +/// RemoteObjectClientLayer forwards the ORC Object Layer API over an RPC +/// connection. +/// +/// This class can be used as the base layer of a JIT stack on the client and +/// will forward operations to a corresponding RemoteObjectServerLayer on the +/// server (which can be composed on top of a "real" object layer like +/// RTDyldObjectLinkingLayer to actually carry out the operations). +/// +/// Sending relocatable objects to the server (rather than fully relocated +/// bits) allows JIT'd code to be cached on the server side and re-used in +/// subsequent JIT sessions. +template <typename RPCEndpoint> +class RemoteObjectClientLayer : public RemoteObjectLayer<RPCEndpoint> { +private: + + using AddObject = RemoteObjectLayerAPI::AddObject; + using RemoveObject = RemoteObjectLayerAPI::RemoveObject; + using FindSymbol = RemoteObjectLayerAPI::FindSymbol; + using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn; + using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize; + using Lookup = RemoteObjectLayerAPI::Lookup; + using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib; + + using RemoteObjectLayer<RPCEndpoint>::teeLog; + using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError; + using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol; + +public: + + using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT; + using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol; + + using ObjectPtr = + std::shared_ptr<object::OwningBinary<object::ObjectFile>>; + + /// Create a RemoteObjectClientLayer that communicates with a + /// RemoteObjectServerLayer instance via the given RPCEndpoint. + /// + /// The ReportError functor can be used locally log errors that are intended + /// to be sent sent + RemoteObjectClientLayer(RPCEndpoint &Remote, + std::function<void(Error)> ReportError) + : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)) { + using ThisT = RemoteObjectClientLayer<RPCEndpoint>; + Remote.template addHandler<Lookup>(*this, &ThisT::lookup); + Remote.template addHandler<LookupInLogicalDylib>( + *this, &ThisT::lookupInLogicalDylib); + } + + /// @brief Add an object to the JIT. + /// + /// @return A handle that can be used to refer to the loaded object (for + /// symbol searching, finalization, freeing memory, etc.). + Expected<ObjHandleT> + addObject(ObjectPtr Object, std::shared_ptr<JITSymbolResolver> Resolver) { + StringRef ObjBuffer = Object->getBinary()->getData(); + if (auto HandleOrErr = + this->Remote.template callB<AddObject>(ObjBuffer)) { + auto &Handle = *HandleOrErr; + // FIXME: Return an error for this: + assert(!Resolvers.count(Handle) && "Handle already in use?"); + Resolvers[Handle] = std::move(Resolver); + return Handle; + } else + return HandleOrErr.takeError(); + } + + /// @brief Remove the given object from the JIT. + Error removeObject(ObjHandleT H) { + return this->Remote.template callB<RemoveObject>(H); + } + + /// @brief Search for the given named symbol. + JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { + return remoteToJITSymbol( + this->Remote.template callB<FindSymbol>(Name, + ExportedSymbolsOnly)); + } + + /// @brief Search for the given named symbol within the given context. + JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) { + return remoteToJITSymbol( + this->Remote.template callB<FindSymbolIn>(H, Name, + ExportedSymbolsOnly)); + } + + /// @brief Immediately emit and finalize the object with the given handle. + Error emitAndFinalize(ObjHandleT H) { + return this->Remote.template callB<EmitAndFinalize>(H); + } + +private: + + Expected<RemoteSymbol> lookup(ObjHandleT H, const std::string &Name) { + auto RI = Resolvers.find(H); + if (RI != Resolvers.end()) { + return this->jitSymbolToRemote(RI->second->findSymbol(Name)); + } else + return teeLog(badObjectHandleError(H)); + } + + Expected<RemoteSymbol> lookupInLogicalDylib(ObjHandleT H, + const std::string &Name) { + auto RI = Resolvers.find(H); + if (RI != Resolvers.end()) + return this->jitSymbolToRemote( + RI->second->findSymbolInLogicalDylib(Name)); + else + return teeLog(badObjectHandleError(H)); + } + + std::map<remote::ResourceIdMgr::ResourceId, + std::shared_ptr<JITSymbolResolver>> Resolvers; +}; + +/// RemoteObjectServerLayer acts as a server and handling RPC calls for the +/// object layer API from the given RPC connection. +/// +/// This class can be composed on top of a 'real' object layer (e.g. +/// RTDyldObjectLinkingLayer) to do the actual work of relocating objects +/// and making them executable. +template <typename BaseLayerT, typename RPCEndpoint> +class RemoteObjectServerLayer : public RemoteObjectLayer<RPCEndpoint> { +private: + + using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT; + using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol; + + using AddObject = RemoteObjectLayerAPI::AddObject; + using RemoveObject = RemoteObjectLayerAPI::RemoveObject; + using FindSymbol = RemoteObjectLayerAPI::FindSymbol; + using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn; + using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize; + using Lookup = RemoteObjectLayerAPI::Lookup; + using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib; + + using RemoteObjectLayer<RPCEndpoint>::teeLog; + using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError; + using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol; + +public: + + /// Create a RemoteObjectServerLayer with the given base layer (which must be + /// an object layer), RPC endpoint, and error reporter function. + RemoteObjectServerLayer(BaseLayerT &BaseLayer, + RPCEndpoint &Remote, + std::function<void(Error)> ReportError) + : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)), + BaseLayer(BaseLayer), HandleIdMgr(1) { + using ThisT = RemoteObjectServerLayer<BaseLayerT, RPCEndpoint>; + + Remote.template addHandler<AddObject>(*this, &ThisT::addObject); + Remote.template addHandler<RemoveObject>(*this, &ThisT::removeObject); + Remote.template addHandler<FindSymbol>(*this, &ThisT::findSymbol); + Remote.template addHandler<FindSymbolIn>(*this, &ThisT::findSymbolIn); + Remote.template addHandler<EmitAndFinalize>(*this, &ThisT::emitAndFinalize); + } + +private: + + class StringMemoryBuffer : public MemoryBuffer { + public: + StringMemoryBuffer(std::string Buffer) + : Buffer(std::move(Buffer)) { + init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(), + false); + } + + BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; } + private: + std::string Buffer; + }; + + JITSymbol lookup(ObjHandleT Id, const std::string &Name) { + return remoteToJITSymbol( + this->Remote.template callB<Lookup>(Id, Name)); + } + + JITSymbol lookupInLogicalDylib(ObjHandleT Id, const std::string &Name) { + return remoteToJITSymbol( + this->Remote.template callB<LookupInLogicalDylib>(Id, Name)); + } + + Expected<ObjHandleT> addObject(std::string ObjBuffer) { + auto Buffer = llvm::make_unique<StringMemoryBuffer>(std::move(ObjBuffer)); + if (auto ObjectOrErr = + object::ObjectFile::createObjectFile(Buffer->getMemBufferRef())) { + auto Object = + std::make_shared<object::OwningBinary<object::ObjectFile>>( + std::move(*ObjectOrErr), std::move(Buffer)); + + auto Id = HandleIdMgr.getNext(); + assert(!BaseLayerHandles.count(Id) && "Id already in use?"); + + auto Resolver = + createLambdaResolver( + [this, Id](const std::string &Name) { return lookup(Id, Name); }, + [this, Id](const std::string &Name) { + return lookupInLogicalDylib(Id, Name); + }); + + if (auto HandleOrErr = + BaseLayer.addObject(std::move(Object), std::move(Resolver))) { + BaseLayerHandles[Id] = std::move(*HandleOrErr); + return Id; + } else + return teeLog(HandleOrErr.takeError()); + } else + return teeLog(ObjectOrErr.takeError()); + } + + Error removeObject(ObjHandleT H) { + auto HI = BaseLayerHandles.find(H); + if (HI != BaseLayerHandles.end()) { + if (auto Err = BaseLayer.removeObject(HI->second)) + return teeLog(std::move(Err)); + return Error::success(); + } else + return teeLog(badObjectHandleError(H)); + } + + Expected<RemoteSymbol> findSymbol(const std::string &Name, + bool ExportedSymbolsOnly) { + if (auto Sym = BaseLayer.findSymbol(Name, ExportedSymbolsOnly)) + return this->jitSymbolToRemote(std::move(Sym)); + else if (auto Err = Sym.takeError()) + return teeLog(std::move(Err)); + return this->nullRemoteSymbol(); + } + + Expected<RemoteSymbol> findSymbolIn(ObjHandleT H, const std::string &Name, + bool ExportedSymbolsOnly) { + auto HI = BaseLayerHandles.find(H); + if (HI != BaseLayerHandles.end()) { + if (auto Sym = BaseLayer.findSymbolIn(HI->second, Name, ExportedSymbolsOnly)) + return this->jitSymbolToRemote(std::move(Sym)); + else if (auto Err = Sym.takeError()) + return teeLog(std::move(Err)); + return this->nullRemoteSymbol(); + } else + return teeLog(badObjectHandleError(H)); + } + + Error emitAndFinalize(ObjHandleT H) { + auto HI = BaseLayerHandles.find(H); + if (HI != BaseLayerHandles.end()) { + if (auto Err = BaseLayer.emitAndFinalize(HI->second)) + return teeLog(std::move(Err)); + return Error::success(); + } else + return teeLog(badObjectHandleError(H)); + } + + BaseLayerT &BaseLayer; + remote::ResourceIdMgr HandleIdMgr; + std::map<ObjHandleT, typename BaseLayerT::ObjHandleT> BaseLayerHandles; +}; + +} // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H diff --git a/include/llvm/ExecutionEngine/Orc/SymbolStringPool.h b/include/llvm/ExecutionEngine/Orc/SymbolStringPool.h new file mode 100644 index 000000000000..b01fbd44bacd --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/SymbolStringPool.h @@ -0,0 +1,136 @@ +//===- SymbolStringPool.h - Multi-threaded pool for JIT symbols -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Contains a multi-threaded string pool suitable for use with ORC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H +#define LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H + +#include "llvm/ADT/StringMap.h" +#include <atomic> +#include <mutex> + +namespace llvm { +namespace orc { + +class SymbolStringPtr; + +/// @brief String pool for symbol names used by the JIT. +class SymbolStringPool { + friend class SymbolStringPtr; +public: + /// @brief Create a symbol string pointer from the given string. + SymbolStringPtr intern(StringRef S); + + /// @brief Remove from the pool any entries that are no longer referenced. + void clearDeadEntries(); + + /// @brief Returns true if the pool is empty. + bool empty() const; +private: + using RefCountType = std::atomic<uint64_t>; + using PoolMap = StringMap<RefCountType>; + using PoolMapEntry = StringMapEntry<RefCountType>; + mutable std::mutex PoolMutex; + PoolMap Pool; +}; + +/// @brief Pointer to a pooled string representing a symbol name. +class SymbolStringPtr { + friend class SymbolStringPool; +public: + SymbolStringPtr() = default; + SymbolStringPtr(const SymbolStringPtr &Other) + : S(Other.S) { + if (S) + ++S->getValue(); + } + + SymbolStringPtr& operator=(const SymbolStringPtr &Other) { + if (S) + --S->getValue(); + S = Other.S; + if (S) + ++S->getValue(); + return *this; + } + + SymbolStringPtr(SymbolStringPtr &&Other) : S(nullptr) { + std::swap(S, Other.S); + } + + SymbolStringPtr& operator=(SymbolStringPtr &&Other) { + if (S) + --S->getValue(); + S = nullptr; + std::swap(S, Other.S); + return *this; + } + + ~SymbolStringPtr() { + if (S) + --S->getValue(); + } + + bool operator==(const SymbolStringPtr &Other) const { + return S == Other.S; + } + + bool operator!=(const SymbolStringPtr &Other) const { + return !(*this == Other); + } + + bool operator<(const SymbolStringPtr &Other) const { + return S->getValue() < Other.S->getValue(); + } + +private: + + SymbolStringPtr(SymbolStringPool::PoolMapEntry *S) + : S(S) { + if (S) + ++S->getValue(); + } + + SymbolStringPool::PoolMapEntry *S = nullptr; +}; + +inline SymbolStringPtr SymbolStringPool::intern(StringRef S) { + std::lock_guard<std::mutex> Lock(PoolMutex); + auto I = Pool.find(S); + if (I != Pool.end()) + return SymbolStringPtr(&*I); + + bool Added; + std::tie(I, Added) = Pool.try_emplace(S, 0); + assert(Added && "Insert should always succeed here"); + return SymbolStringPtr(&*I); +} + +inline void SymbolStringPool::clearDeadEntries() { + std::lock_guard<std::mutex> Lock(PoolMutex); + for (auto I = Pool.begin(), E = Pool.end(); I != E;) { + auto Tmp = std::next(I); + if (I->second == 0) + Pool.erase(I); + I = Tmp; + } +} + +inline bool SymbolStringPool::empty() const { + std::lock_guard<std::mutex> Lock(PoolMutex); + return Pool.empty(); +} + +} // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H |
