From 6784638299d535de46969417df916c074e5c220a Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 19 Jan 2018 01:12:40 +0000 Subject: [PATCH] [ORC] Redesign the JITSymbolResolver interface to support bulk queries. Bulk queries reduce IPC/RPC overhead for cross-process JITing and expose opportunities for parallel compilation. The two new query methods are lookupFlags, which finds the flags for each of a set of symbols; and lookup, which finds the address and flags for each of a set of symbols. (See doxygen comments for more details.) The existing JITSymbolResolver class is renamed LegacyJITSymbolResolver, and modified to extend the new JITSymbolResolver class using the following scheme: - lookupFlags is implemented by calling findSymbolInLogicalDylib for each of the symbols, then returning the result of calling getFlags() on each of these symbols. (Importantly: lookupFlags does NOT call getAddress on the returned symbols, so lookupFlags will never trigger materialization, and lookupFlags will never call findSymbol, so only symbols that are part of the logical dylib will return results.) - lookup is implemented by calling findSymbolInLogicalDylib for each symbol and falling back to findSymbol if findSymbolInLogicalDylib returns a null result. Assuming a symbol is found its getAddress method is called to materialize it and the result (if getAddress succeeds) is stored in the result map, or the error (if getAddress fails) is returned immediately from lookup. If any symbol is not found then lookup returns immediately with an error. This change will break any out-of-tree derivatives of JITSymbolResolver. This can be fixed by updating those classes to derive from LegacyJITSymbolResolver instead. llvm-svn: 322913 --- .../llvm/ExecutionEngine/ExecutionEngine.h | 21 +- include/llvm/ExecutionEngine/JITSymbol.h | 44 ++- .../Orc/CompileOnDemandLayer.h | 4 +- .../llvm/ExecutionEngine/Orc/LambdaResolver.h | 2 +- .../llvm/ExecutionEngine/Orc/NullResolver.h | 2 +- .../ExecutionEngine/Orc/RemoteObjectLayer.h | 6 +- .../ExecutionEngine/RTDyldMemoryManager.h | 2 +- lib/ExecutionEngine/ExecutionEngine.cpp | 15 +- lib/ExecutionEngine/MCJIT/MCJIT.cpp | 9 +- lib/ExecutionEngine/MCJIT/MCJIT.h | 17 +- lib/ExecutionEngine/Orc/OrcCBindingsStack.h | 2 +- lib/ExecutionEngine/Orc/OrcMCJITReplacement.h | 17 +- lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp | 50 +++ .../RuntimeDyld/RuntimeDyld.cpp | 302 +++++++++--------- .../RuntimeDyld/RuntimeDyldChecker.cpp | 20 +- .../RuntimeDyld/RuntimeDyldImpl.h | 3 +- tools/lli/RemoteJITUtils.h | 4 +- 17 files changed, 319 insertions(+), 201 deletions(-) diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index 77c23b46d32..7932688290e 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -137,17 +137,15 @@ protected: virtual char *getMemoryForGV(const GlobalVariable *GV); static ExecutionEngine *(*MCJITCtor)( - std::unique_ptr M, - std::string *ErrorStr, - std::shared_ptr MM, - std::shared_ptr SR, - std::unique_ptr TM); + std::unique_ptr M, std::string *ErrorStr, + std::shared_ptr MM, + std::shared_ptr SR, + std::unique_ptr TM); static ExecutionEngine *(*OrcMCJITReplacementCtor)( - std::string *ErrorStr, - std::shared_ptr MM, - std::shared_ptr SR, - std::unique_ptr TM); + std::string *ErrorStr, std::shared_ptr MM, + std::shared_ptr SR, + std::unique_ptr TM); static ExecutionEngine *(*InterpCtor)(std::unique_ptr M, std::string *ErrorStr); @@ -532,7 +530,7 @@ private: std::string *ErrorStr; CodeGenOpt::Level OptLevel; std::shared_ptr MemMgr; - std::shared_ptr Resolver; + std::shared_ptr Resolver; TargetOptions Options; Optional RelocModel; Optional CMModel; @@ -571,8 +569,7 @@ public: EngineBuilder& setMemoryManager(std::unique_ptr MM); - EngineBuilder& - setSymbolResolver(std::unique_ptr SR); + EngineBuilder &setSymbolResolver(std::unique_ptr SR); /// setErrorStr - Set the error string to write to on error. This option /// defaults to NULL. diff --git a/include/llvm/ExecutionEngine/JITSymbol.h b/include/llvm/ExecutionEngine/JITSymbol.h index d171f998e6f..6aba236b619 100644 --- a/include/llvm/ExecutionEngine/JITSymbol.h +++ b/include/llvm/ExecutionEngine/JITSymbol.h @@ -19,8 +19,11 @@ #include #include #include +#include +#include #include +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" namespace llvm { @@ -269,11 +272,50 @@ private: JITSymbolFlags Flags; }; -/// \brief Symbol resolution. +/// @brief Symbol resolution interface. +/// +/// Allows symbol flags and addresses to be looked up by name. +/// Symbol queries are done in bulk (i.e. you request resolution of a set of +/// symbols, rather than a single one) to reduce IPC overhead in the case of +/// remote JITing, and expose opportunities for parallel compilation. class JITSymbolResolver { public: + using SymbolNameSet = std::set; + using LookupResult = std::map; + using LookupFlagsResult = std::map; + virtual ~JITSymbolResolver() = default; + /// @brief Returns the fully resolved address and flags for each of the given + /// symbols. + /// + /// This method will return an error if any of the given symbols can not be + /// resolved, or if the resolution process itself triggers an error. + virtual Expected lookup(const SymbolNameSet &Symbols) = 0; + + /// @brief Returns the symbol flags for each of the given symbols. + /// + /// This method does NOT return an error if any of the given symbols is + /// missing. Instead, that symbol will be left out of the result map. + virtual Expected + lookupFlags(const SymbolNameSet &Symbols) = 0; + +private: + virtual void anchor(); +}; + +/// \brief Legacy symbol resolution interface. +class LegacyJITSymbolResolver : public JITSymbolResolver { +public: + /// @brief Performs lookup by, for each symbol, first calling + /// findSymbolInLogicalDylib and if that fails calling + /// findSymbol. + Expected lookup(const SymbolNameSet &Symbols) final; + + /// @brief Performs flags lookup by calling findSymbolInLogicalDylib and + /// returning the flags value for that symbol. + Expected lookupFlags(const SymbolNameSet &Symbols) final; + /// This method returns the address of the specified symbol if it exists /// within the logical dynamic library represented by this JITSymbolResolver. /// Unlike findSymbol, queries through this interface should return addresses diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index a961992c214..3281c354676 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -183,7 +183,7 @@ private: return Error::success(); } - std::shared_ptr ExternalSymbolResolver; + std::shared_ptr ExternalSymbolResolver; std::unique_ptr StubsMgr; StaticGlobalRenamer StaticRenamer; SourceModulesList SourceModules; @@ -223,7 +223,7 @@ public: /// @brief Add a module to the compile-on-demand layer. Expected addModule(std::shared_ptr M, - std::shared_ptr Resolver) { + std::shared_ptr Resolver) { LogicalDylibs.push_back(LogicalDylib()); auto &LD = LogicalDylibs.back(); diff --git a/include/llvm/ExecutionEngine/Orc/LambdaResolver.h b/include/llvm/ExecutionEngine/Orc/LambdaResolver.h index 228392ae0d4..7b6f3d2f92a 100644 --- a/include/llvm/ExecutionEngine/Orc/LambdaResolver.h +++ b/include/llvm/ExecutionEngine/Orc/LambdaResolver.h @@ -23,7 +23,7 @@ namespace llvm { namespace orc { template -class LambdaResolver : public JITSymbolResolver { +class LambdaResolver : public LegacyJITSymbolResolver { public: LambdaResolver(DylibLookupFtorT DylibLookupFtor, ExternalLookupFtorT ExternalLookupFtor) diff --git a/include/llvm/ExecutionEngine/Orc/NullResolver.h b/include/llvm/ExecutionEngine/Orc/NullResolver.h index 957b94912b3..fc5cb3e7c71 100644 --- a/include/llvm/ExecutionEngine/Orc/NullResolver.h +++ b/include/llvm/ExecutionEngine/Orc/NullResolver.h @@ -22,7 +22,7 @@ namespace orc { /// SymbolResolver impliementation that rejects all resolution requests. /// Useful for clients that have no cross-object fixups. -class NullResolver : public JITSymbolResolver { +class NullResolver : public LegacyJITSymbolResolver { public: JITSymbol findSymbol(const std::string &Name) final; diff --git a/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h b/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h index 17255954a99..21d0b68a771 100644 --- a/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h +++ b/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h @@ -328,7 +328,8 @@ public: /// @return A handle that can be used to refer to the loaded object (for /// symbol searching, finalization, freeing memory, etc.). Expected - addObject(ObjectPtr Object, std::shared_ptr Resolver) { + addObject(ObjectPtr Object, + std::shared_ptr Resolver) { StringRef ObjBuffer = Object->getBinary()->getData(); if (auto HandleOrErr = this->Remote.template callB(ObjBuffer)) { @@ -386,7 +387,8 @@ private: } std::map> Resolvers; + std::shared_ptr> + Resolvers; }; /// RemoteObjectServerLayer acts as a server and handling RPC calls for the diff --git a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h index 0c1862c5c3e..ee75202d2b6 100644 --- a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h +++ b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h @@ -56,7 +56,7 @@ public: // FIXME: As the RuntimeDyld fills out, additional routines will be needed // for the varying types of objects to be allocated. class RTDyldMemoryManager : public MCJITMemoryManager, - public JITSymbolResolver { + public LegacyJITSymbolResolver { public: RTDyldMemoryManager() = default; RTDyldMemoryManager(const RTDyldMemoryManager&) = delete; diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index 233ece29422..e4efc15f2ae 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -49,14 +49,13 @@ STATISTIC(NumGlobals , "Number of global vars initialized"); ExecutionEngine *(*ExecutionEngine::MCJITCtor)( std::unique_ptr M, std::string *ErrorStr, std::shared_ptr MemMgr, - - std::shared_ptr Resolver, + std::shared_ptr Resolver, std::unique_ptr TM) = nullptr; ExecutionEngine *(*ExecutionEngine::OrcMCJITReplacementCtor)( - std::string *ErrorStr, std::shared_ptr MemMgr, - std::shared_ptr Resolver, - std::unique_ptr TM) = nullptr; + std::string *ErrorStr, std::shared_ptr MemMgr, + std::shared_ptr Resolver, + std::unique_ptr TM) = nullptr; ExecutionEngine *(*ExecutionEngine::InterpCtor)(std::unique_ptr M, std::string *ErrorStr) =nullptr; @@ -502,9 +501,9 @@ EngineBuilder::setMemoryManager(std::unique_ptr MM) { return *this; } -EngineBuilder& -EngineBuilder::setSymbolResolver(std::unique_ptr SR) { - Resolver = std::shared_ptr(std::move(SR)); +EngineBuilder & +EngineBuilder::setSymbolResolver(std::unique_ptr SR) { + Resolver = std::shared_ptr(std::move(SR)); return *this; } diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp index f7b8a3b657e..438e656b60f 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -39,11 +39,10 @@ static struct RegisterJIT { extern "C" void LLVMLinkInMCJIT() { } -ExecutionEngine* -MCJIT::createJIT(std::unique_ptr M, - std::string *ErrorStr, +ExecutionEngine * +MCJIT::createJIT(std::unique_ptr M, std::string *ErrorStr, std::shared_ptr MemMgr, - std::shared_ptr Resolver, + std::shared_ptr Resolver, std::unique_ptr TM) { // Try to register the program as a source of symbols to resolve against. // @@ -64,7 +63,7 @@ MCJIT::createJIT(std::unique_ptr M, MCJIT::MCJIT(std::unique_ptr M, std::unique_ptr TM, std::shared_ptr MemMgr, - std::shared_ptr Resolver) + std::shared_ptr Resolver) : ExecutionEngine(TM->createDataLayout(), std::move(M)), TM(std::move(TM)), Ctx(nullptr), MemMgr(std::move(MemMgr)), Resolver(*this, std::move(Resolver)), Dyld(*this->MemMgr, this->Resolver), diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.h b/lib/ExecutionEngine/MCJIT/MCJIT.h index daf578f5daa..110cfa675cf 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -26,11 +26,11 @@ class MCJIT; // functions across modules that it owns. It aggregates the memory manager // that is passed in to the MCJIT constructor and defers most functionality // to that object. -class LinkingSymbolResolver : public JITSymbolResolver { +class LinkingSymbolResolver : public LegacyJITSymbolResolver { public: LinkingSymbolResolver(MCJIT &Parent, - std::shared_ptr Resolver) - : ParentEngine(Parent), ClientResolver(std::move(Resolver)) {} + std::shared_ptr Resolver) + : ParentEngine(Parent), ClientResolver(std::move(Resolver)) {} JITSymbol findSymbol(const std::string &Name) override; @@ -41,7 +41,7 @@ public: private: MCJIT &ParentEngine; - std::shared_ptr ClientResolver; + std::shared_ptr ClientResolver; }; // About Module states: added->loaded->finalized. @@ -67,7 +67,7 @@ private: class MCJIT : public ExecutionEngine { MCJIT(std::unique_ptr M, std::unique_ptr tm, std::shared_ptr MemMgr, - std::shared_ptr Resolver); + std::shared_ptr Resolver); typedef llvm::SmallPtrSet ModulePtrSet; @@ -300,11 +300,10 @@ public: MCJITCtor = createJIT; } - static ExecutionEngine* - createJIT(std::unique_ptr M, - std::string *ErrorStr, + static ExecutionEngine * + createJIT(std::unique_ptr M, std::string *ErrorStr, std::shared_ptr MemMgr, - std::shared_ptr Resolver, + std::shared_ptr Resolver, std::unique_ptr TM); // @} diff --git a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h index 405970e063d..05b1f47eb5b 100644 --- a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h +++ b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h @@ -196,7 +196,7 @@ public: return mapError(IndirectStubsMgr->updatePointer(Name, Addr)); } - std::shared_ptr + std::shared_ptr createResolver(LLVMOrcSymbolResolverFn ExternalResolver, void *ExternalResolverCtx) { return orc::createLambdaResolver( diff --git a/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h index 1dc8d4ac7bc..166d1369c72 100644 --- a/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h +++ b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h @@ -138,7 +138,7 @@ class OrcMCJITReplacement : public ExecutionEngine { std::shared_ptr ClientMM; }; - class LinkingResolver : public JITSymbolResolver { + class LinkingResolver : public LegacyJITSymbolResolver { public: LinkingResolver(OrcMCJITReplacement &M) : M(M) {} @@ -160,20 +160,19 @@ private: static ExecutionEngine * createOrcMCJITReplacement(std::string *ErrorMsg, std::shared_ptr MemMgr, - std::shared_ptr Resolver, + std::shared_ptr Resolver, std::unique_ptr TM) { return new OrcMCJITReplacement(std::move(MemMgr), std::move(Resolver), std::move(TM)); } public: - OrcMCJITReplacement( - std::shared_ptr MemMgr, - std::shared_ptr ClientResolver, - std::unique_ptr TM) + OrcMCJITReplacement(std::shared_ptr MemMgr, + std::shared_ptr ClientResolver, + std::unique_ptr TM) : ExecutionEngine(TM->createDataLayout()), TM(std::move(TM)), - MemMgr(std::make_shared(*this, - std::move(MemMgr))), + MemMgr( + std::make_shared(*this, std::move(MemMgr))), Resolver(std::make_shared(*this)), ClientResolver(std::move(ClientResolver)), NotifyObjectLoaded(*this), NotifyFinalized(*this), @@ -378,7 +377,7 @@ private: std::unique_ptr TM; std::shared_ptr MemMgr; std::shared_ptr Resolver; - std::shared_ptr ClientResolver; + std::shared_ptr ClientResolver; Mangler Mang; // IMPORTANT: ShouldDelete *must* come before LocalModules: The shared_ptr diff --git a/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp b/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp index 87059ef2b88..670c6d2fa3f 100644 --- a/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp @@ -47,3 +47,53 @@ ARMJITSymbolFlags llvm::ARMJITSymbolFlags::fromObjectSymbol( Flags |= ARMJITSymbolFlags::Thumb; return Flags; } + +/// @brief Performs lookup by, for each symbol, first calling +/// findSymbolInLogicalDylib and if that fails calling +/// findSymbol. +Expected +LegacyJITSymbolResolver::lookup(const SymbolNameSet &Symbols) { + JITSymbolResolver::LookupResult Result; + for (auto &Symbol : Symbols) { + std::string SymName = Symbol.str(); + if (auto Sym = findSymbolInLogicalDylib(SymName)) { + if (auto AddrOrErr = Sym.getAddress()) + Result[Symbol] = JITEvaluatedSymbol(*AddrOrErr, Sym.getFlags()); + else + return AddrOrErr.takeError(); + } else if (auto Err = Sym.takeError()) + return std::move(Err); + else { + // findSymbolInLogicalDylib failed. Lets try findSymbol. + if (auto Sym = findSymbol(SymName)) { + if (auto AddrOrErr = Sym.getAddress()) + Result[Symbol] = JITEvaluatedSymbol(*AddrOrErr, Sym.getFlags()); + else + return AddrOrErr.takeError(); + } else if (auto Err = Sym.takeError()) + return std::move(Err); + else + return make_error("Symbol not found: " + Symbol, + inconvertibleErrorCode()); + } + } + + return std::move(Result); +} + +/// @brief Performs flags lookup by calling findSymbolInLogicalDylib and +/// returning the flags value for that symbol. +Expected +LegacyJITSymbolResolver::lookupFlags(const SymbolNameSet &Symbols) { + JITSymbolResolver::LookupFlagsResult Result; + + for (auto &Symbol : Symbols) { + std::string SymName = Symbol.str(); + if (auto Sym = findSymbolInLogicalDylib(SymName)) + Result[Symbol] = Sym.getFlags(); + else if (auto Err = Sym.takeError()) + return std::move(Err); + } + + return std::move(Result); +} diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 3a025f4c026..ce8d480a408 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -202,7 +202,33 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) { ObjSectionToIDMap LocalSections; // Common symbols requiring allocation, with their sizes and alignments - CommonSymbolList CommonSymbols; + CommonSymbolList CommonSymbolsToAllocate; + + uint64_t CommonSize = 0; + uint32_t CommonAlign = 0; + + // First, collect all weak and common symbols. We need to know if stronger + // definitions occur elsewhere. + JITSymbolResolver::LookupFlagsResult SymbolFlags; + { + JITSymbolResolver::SymbolNameSet Symbols; + for (auto &Sym : Obj.symbols()) { + uint32_t Flags = Sym.getFlags(); + if ((Flags & SymbolRef::SF_Common) || (Flags & SymbolRef::SF_Weak)) { + // Get symbol name. + StringRef Name; + if (auto NameOrErr = Sym.getName()) + Symbols.insert(*NameOrErr); + else + return NameOrErr.takeError(); + } + } + + if (auto FlagsResultOrErr = Resolver.lookupFlags(Symbols)) + SymbolFlags = std::move(*FlagsResultOrErr); + else + return FlagsResultOrErr.takeError(); + } // Parse symbols DEBUG(dbgs() << "Parse symbols:\n"); @@ -214,102 +240,108 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) { if (Flags & SymbolRef::SF_Undefined) continue; - if (Flags & SymbolRef::SF_Common) - CommonSymbols.push_back(*I); - else { + // Get the symbol type. + object::SymbolRef::Type SymType; + if (auto SymTypeOrErr = I->getType()) + SymType = *SymTypeOrErr; + else + return SymTypeOrErr.takeError(); - // Get the symbol type. - object::SymbolRef::Type SymType; - if (auto SymTypeOrErr = I->getType()) - SymType = *SymTypeOrErr; + // Get symbol name. + StringRef Name; + if (auto NameOrErr = I->getName()) + Name = *NameOrErr; + else + return NameOrErr.takeError(); + + // Compute JIT symbol flags. + JITSymbolFlags JITSymFlags = getJITSymbolFlags(*I); + + // If this is a weak definition, check to see if there's a strong one. + // If there is, skip this symbol (we won't be providing it: the strong + // definition will). If there's no strong definition, make this definition + // strong. + if (JITSymFlags.isWeak() || JITSymFlags.isCommon()) { + // First check whether there's already a definition in this instance. + // FIXME: Override existing weak definitions with strong ones. + if (GlobalSymbolTable.count(Name)) + continue; + + // Then check whether we found flags for an existing symbol during the + // flags lookup earlier. + auto FlagsI = SymbolFlags.find(Name); + if (FlagsI == SymbolFlags.end() || + (JITSymFlags.isWeak() && !FlagsI->second.isStrong()) || + (JITSymFlags.isCommon() && FlagsI->second.isCommon())) { + if (JITSymFlags.isWeak()) + JITSymFlags &= ~JITSymbolFlags::Weak; + if (JITSymFlags.isCommon()) { + JITSymFlags &= ~JITSymbolFlags::Common; + uint32_t Align = I->getAlignment(); + uint64_t Size = I->getCommonSize(); + if (!CommonAlign) + CommonAlign = Align; + CommonSize += alignTo(CommonSize, Align) + Size; + CommonSymbolsToAllocate.push_back(*I); + } + } else + continue; + } + + if (Flags & SymbolRef::SF_Absolute && + SymType != object::SymbolRef::ST_File) { + uint64_t Addr = 0; + if (auto AddrOrErr = I->getAddress()) + Addr = *AddrOrErr; else - return SymTypeOrErr.takeError(); + return AddrOrErr.takeError(); - // Get symbol name. - StringRef Name; - if (auto NameOrErr = I->getName()) - Name = *NameOrErr; + unsigned SectionID = AbsoluteSymbolSection; + + DEBUG(dbgs() << "\tType: " << SymType << " (absolute) Name: " << Name + << " SID: " << SectionID + << " Offset: " << format("%p", (uintptr_t)Addr) + << " flags: " << Flags << "\n"); + GlobalSymbolTable[Name] = SymbolTableEntry(SectionID, Addr, JITSymFlags); + } else if (SymType == object::SymbolRef::ST_Function || + SymType == object::SymbolRef::ST_Data || + SymType == object::SymbolRef::ST_Unknown || + SymType == object::SymbolRef::ST_Other) { + + section_iterator SI = Obj.section_end(); + if (auto SIOrErr = I->getSection()) + SI = *SIOrErr; else - return NameOrErr.takeError(); + return SIOrErr.takeError(); - // Compute JIT symbol flags. - JITSymbolFlags JITSymFlags = getJITSymbolFlags(*I); + if (SI == Obj.section_end()) + continue; - // If this is a weak definition, check to see if there's a strong one. - // If there is, skip this symbol (we won't be providing it: the strong - // definition will). If there's no strong definition, make this definition - // strong. - if (JITSymFlags.isWeak()) { - // First check whether there's already a definition in this instance. - // FIXME: Override existing weak definitions with strong ones. - if (GlobalSymbolTable.count(Name)) - continue; - // Then check the symbol resolver to see if there's a definition - // elsewhere in this logical dylib. - if (auto Sym = Resolver.findSymbolInLogicalDylib(Name)) { - if (Sym.getFlags().isStrong()) - continue; - } else if (auto Err = Sym.takeError()) - return std::move(Err); - // else - JITSymFlags &= ~JITSymbolFlags::Weak; - } + // Get symbol offset. + uint64_t SectOffset; + if (auto Err = getOffset(*I, *SI, SectOffset)) + return std::move(Err); - if (Flags & SymbolRef::SF_Absolute && - SymType != object::SymbolRef::ST_File) { - uint64_t Addr = 0; - if (auto AddrOrErr = I->getAddress()) - Addr = *AddrOrErr; - else - return AddrOrErr.takeError(); + bool IsCode = SI->isText(); + unsigned SectionID; + if (auto SectionIDOrErr = + findOrEmitSection(Obj, *SI, IsCode, LocalSections)) + SectionID = *SectionIDOrErr; + else + return SectionIDOrErr.takeError(); - unsigned SectionID = AbsoluteSymbolSection; - - DEBUG(dbgs() << "\tType: " << SymType << " (absolute) Name: " << Name - << " SID: " << SectionID << " Offset: " - << format("%p", (uintptr_t)Addr) - << " flags: " << Flags << "\n"); - GlobalSymbolTable[Name] = - SymbolTableEntry(SectionID, Addr, JITSymFlags); - } else if (SymType == object::SymbolRef::ST_Function || - SymType == object::SymbolRef::ST_Data || - SymType == object::SymbolRef::ST_Unknown || - SymType == object::SymbolRef::ST_Other) { - - section_iterator SI = Obj.section_end(); - if (auto SIOrErr = I->getSection()) - SI = *SIOrErr; - else - return SIOrErr.takeError(); - - if (SI == Obj.section_end()) - continue; - - // Get symbol offset. - uint64_t SectOffset; - if (auto Err = getOffset(*I, *SI, SectOffset)) - return std::move(Err); - - bool IsCode = SI->isText(); - unsigned SectionID; - if (auto SectionIDOrErr = findOrEmitSection(Obj, *SI, IsCode, - LocalSections)) - SectionID = *SectionIDOrErr; - else - return SectionIDOrErr.takeError(); - - DEBUG(dbgs() << "\tType: " << SymType << " Name: " << Name - << " SID: " << SectionID << " Offset: " - << format("%p", (uintptr_t)SectOffset) - << " flags: " << Flags << "\n"); - GlobalSymbolTable[Name] = + DEBUG(dbgs() << "\tType: " << SymType << " Name: " << Name + << " SID: " << SectionID + << " Offset: " << format("%p", (uintptr_t)SectOffset) + << " flags: " << Flags << "\n"); + GlobalSymbolTable[Name] = SymbolTableEntry(SectionID, SectOffset, JITSymFlags); - } } } // Allocate common symbols - if (auto Err = emitCommonSymbols(Obj, CommonSymbols)) + if (auto Err = emitCommonSymbols(Obj, CommonSymbolsToAllocate, CommonSize, + CommonAlign)) return std::move(Err); // Parse and process relocations @@ -621,45 +653,12 @@ JITSymbolFlags RuntimeDyldImpl::getJITSymbolFlags(const BasicSymbolRef &SR) { } Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj, - CommonSymbolList &CommonSymbols) { - if (CommonSymbols.empty()) + CommonSymbolList &SymbolsToAllocate, + uint64_t CommonSize, + uint32_t CommonAlign) { + if (SymbolsToAllocate.empty()) return Error::success(); - uint64_t CommonSize = 0; - uint32_t CommonAlign = CommonSymbols.begin()->getAlignment(); - CommonSymbolList SymbolsToAllocate; - - DEBUG(dbgs() << "Processing common symbols...\n"); - - for (const auto &Sym : CommonSymbols) { - StringRef Name; - if (auto NameOrErr = Sym.getName()) - Name = *NameOrErr; - else - return NameOrErr.takeError(); - - // Skip common symbols already elsewhere. - if (GlobalSymbolTable.count(Name)) { - DEBUG(dbgs() << "\tSkipping already emitted common symbol '" << Name - << "'\n"); - continue; - } - - if (auto Sym = Resolver.findSymbolInLogicalDylib(Name)) { - if (!Sym.getFlags().isCommon()) { - DEBUG(dbgs() << "\tSkipping common symbol '" << Name - << "' in favor of stronger definition.\n"); - continue; - } - } - uint32_t Align = Sym.getAlignment(); - uint64_t Size = Sym.getCommonSize(); - - CommonSize = alignTo(CommonSize, Align) + Size; - - SymbolsToAllocate.push_back(Sym); - } - // Allocate memory for the section unsigned SectionID = Sections.size(); uint8_t *Addr = MemMgr.allocateDataSection(CommonSize, CommonAlign, SectionID, @@ -997,7 +996,40 @@ void RuntimeDyldImpl::resolveRelocationList(const RelocationList &Relocs, } Error RuntimeDyldImpl::resolveExternalSymbols() { + JITSymbolResolver::LookupResult ExternalSymbolMap; + + // Resolution can trigger emission of more symbols, so iterate until + // we've resolved *everything*. + { + JITSymbolResolver::SymbolNameSet ResolvedSymbols; + + while (true) { + JITSymbolResolver::SymbolNameSet NewSymbols; + + for (auto &RelocKV : ExternalSymbolRelocations) { + StringRef Name = RelocKV.first(); + if (!Name.empty() && !GlobalSymbolTable.count(Name) && + !ResolvedSymbols.count(Name)) + NewSymbols.insert(Name); + } + + if (NewSymbols.empty()) + break; + + auto NewResolverResults = Resolver.lookup(NewSymbols); + if (!NewResolverResults) + return NewResolverResults.takeError(); + + for (auto &RRKV : *NewResolverResults) { + assert(!ResolvedSymbols.count(RRKV.first) && "Redundant resolution?"); + ExternalSymbolMap.insert(RRKV); + ResolvedSymbols.insert(RRKV.first); + } + } + } + while (!ExternalSymbolRelocations.empty()) { + StringMap::iterator i = ExternalSymbolRelocations.begin(); StringRef Name = i->first(); @@ -1012,29 +1044,10 @@ Error RuntimeDyldImpl::resolveExternalSymbols() { JITSymbolFlags Flags; RTDyldSymbolTable::const_iterator Loc = GlobalSymbolTable.find(Name); if (Loc == GlobalSymbolTable.end()) { - // This is an external symbol, try to get its address from the symbol - // resolver. - // First search for the symbol in this logical dylib. - if (auto Sym = Resolver.findSymbolInLogicalDylib(Name.data())) { - if (auto AddrOrErr = Sym.getAddress()) { - Addr = *AddrOrErr; - Flags = Sym.getFlags(); - } else - return AddrOrErr.takeError(); - } else if (auto Err = Sym.takeError()) - return Err; - - // If that fails, try searching for an external symbol. - if (!Addr) { - if (auto Sym = Resolver.findSymbol(Name.data())) { - if (auto AddrOrErr = Sym.getAddress()) { - Addr = *AddrOrErr; - Flags = Sym.getFlags(); - } else - return AddrOrErr.takeError(); - } else if (auto Err = Sym.takeError()) - return Err; - } + auto RRI = ExternalSymbolMap.find(Name); + assert(RRI != ExternalSymbolMap.end() && "No result for symbol"); + Addr = RRI->second.getAddress(); + Flags = RRI->second.getFlags(); // The call to getSymbolAddress may have caused additional modules to // be loaded, which may have added new entries to the // ExternalSymbolRelocations map. Consquently, we need to update our @@ -1095,6 +1108,7 @@ uint64_t RuntimeDyld::LoadedObjectInfo::getSectionLoadAddress( void RuntimeDyld::MemoryManager::anchor() {} void JITSymbolResolver::anchor() {} +void LegacyJITSymbolResolver::anchor() {} RuntimeDyld::RuntimeDyld(RuntimeDyld::MemoryManager &MemMgr, JITSymbolResolver &Resolver) diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp index 5bc7434e703..0f4534f2c9f 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -731,7 +731,14 @@ bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix, bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const { if (getRTDyld().getSymbol(Symbol)) return true; - return !!getRTDyld().Resolver.findSymbol(Symbol); + JITSymbolResolver::SymbolNameSet Symbols({Symbol}); + auto Result = getRTDyld().Resolver.lookup(Symbols); + if (!Result) { + logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: "); + return false; + } + assert(Result->count(Symbol) && "Missing symbol result"); + return true; } uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { @@ -742,7 +749,16 @@ uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const { if (auto InternalSymbol = getRTDyld().getSymbol(Symbol)) return InternalSymbol.getAddress(); - return cantFail(getRTDyld().Resolver.findSymbol(Symbol).getAddress()); + + JITSymbolResolver::SymbolNameSet Symbols({Symbol}); + auto Result = getRTDyld().Resolver.lookup(Symbols); + if (!Result) { + logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: "); + return 0; + } + auto I = Result->find(Symbol); + assert(I != Result->end() && "Missing symbol result"); + return I->second.getAddress(); } uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr, diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index e046a8504e9..e940004bb2e 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -385,7 +385,8 @@ protected: /// new section for them and update the symbol mappings in the object and /// symbol table. Error emitCommonSymbols(const ObjectFile &Obj, - CommonSymbolList &CommonSymbols); + CommonSymbolList &CommonSymbols, uint64_t CommonSize, + uint32_t CommonAlign); /// \brief Emits section data from the object file to the MemoryManager. /// \param IsCode if it's true then allocateCodeSection() will be diff --git a/tools/lli/RemoteJITUtils.h b/tools/lli/RemoteJITUtils.h index 4e948413865..944881070c7 100644 --- a/tools/lli/RemoteJITUtils.h +++ b/tools/lli/RemoteJITUtils.h @@ -84,7 +84,7 @@ public: this->MemMgr = std::move(MemMgr); } - void setResolver(std::shared_ptr Resolver) { + void setResolver(std::shared_ptr Resolver) { this->Resolver = std::move(Resolver); } @@ -145,7 +145,7 @@ public: private: std::unique_ptr MemMgr; - std::shared_ptr Resolver; + std::shared_ptr Resolver; }; }