From a9fdf375b3769a1df18d72aa6eb1e627a22a29e7 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 26 Apr 2019 22:58:39 +0000 Subject: [PATCH] [ORC] Add a 'plugin' interface to ObjectLinkingLayer for events/configuration. ObjectLinkingLayer::Plugin provides event notifications when objects are loaded, emitted, and removed. It also provides a modifyPassConfig callback that allows plugins to modify the JITLink pass configuration. This patch moves eh-frame registration into its own plugin, and teaches llvm-jitlink to only add that plugin when performing execution runs on non-Windows platforms. This should allow us to re-enable the test case that was removed in r359198. llvm-svn: 359357 --- .../llvm/ExecutionEngine/JITLink/EHFrameSupport.h | 7 +- .../llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h | 91 ++++++---- .../lib/ExecutionEngine/JITLink/EHFrameSupport.cpp | 9 +- .../lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp | 195 ++++++++++++++++----- .../JITLink/X86/MachO_x86-64_ehframe.test | 7 +- llvm/tools/llvm-jitlink/llvm-jitlink.cpp | 28 ++- 6 files changed, 238 insertions(+), 99 deletions(-) diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h index 5c1c276..1563e97 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h @@ -27,14 +27,17 @@ Error registerEHFrameSection(const void *EHFrameSectionAddr); /// Deregisters all FDEs in the given eh-frame section with the current process. Error deregisterEHFrameSection(const void *EHFrameSectionAddr); +using StoreFrameAddressFunction = std::function; + /// Creates a pass that records the address of the EH frame section. If no /// eh-frame section is found, it will set EHFrameAddr to zero. /// /// Authors of JITLinkContexts can use this function to register a post-fixup /// pass that records the address of the eh-frame section. This address can /// be used after finalization to register and deregister the frame. -AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT, - JITTargetAddress &EHFrameAddr); +AtomGraphPassFunction +createEHFrameRecorderPass(const Triple &TT, + StoreFrameAddressFunction StoreFrameAddress); } // end namespace jitlink } // end namespace llvm diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h index f4cafb5..4a45ad2 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -41,27 +41,48 @@ namespace orc { class ObjectLinkingLayerJITLinkContext; +/// An ObjectLayer implementation built on JITLink. +/// +/// Clients can use this class to add relocatable object files to an +/// ExecutionSession, and it typically serves as the base layer (underneath +/// a compiling layer like IRCompileLayer) for the rest of the JIT. class ObjectLinkingLayer : public ObjectLayer { friend class ObjectLinkingLayerJITLinkContext; public: - /// Function object for receiving object-loaded notifications. - using NotifyLoadedFunction = std::function; + /// Plugin instances can be added to the ObjectLinkingLayer to receive + /// callbacks when code is loaded or emitted, and when JITLink is being + /// configured. + class Plugin { + public: + virtual ~Plugin(); + virtual void modifyPassConfig(MaterializationResponsibility &MR, + const Triple &TT, + jitlink::PassConfiguration &Config) {} + virtual void notifyLoaded(MaterializationResponsibility &MR) {} + virtual Error notifyEmitted(MaterializationResponsibility &MR) { + return Error::success(); + } + virtual Error notifyRemovingModule(VModuleKey K) { + return Error::success(); + } + virtual Error notifyRemovingAllModules() { return Error::success(); } + }; - /// Function object for receiving finalization notifications. - using NotifyEmittedFunction = std::function; + /// Construct an ObjectLinkingLayer with the given NotifyLoaded, + /// and NotifyEmitted functors. + ObjectLinkingLayer(ExecutionSession &ES, + jitlink::JITLinkMemoryManager &MemMgr); - /// Function object for modifying PassConfiguration objects. - using ModifyPassConfigFunction = - std::function; + /// Destruct an ObjectLinkingLayer. + ~ObjectLinkingLayer(); - /// Construct an ObjectLinkingLayer with the given NotifyLoaded, - /// and NotifyEmitted functors. - ObjectLinkingLayer( - ExecutionSession &ES, jitlink::JITLinkMemoryManager &MemMgr, - NotifyLoadedFunction NotifyLoaded = NotifyLoadedFunction(), - NotifyEmittedFunction NotifyEmitted = NotifyEmittedFunction(), - ModifyPassConfigFunction ModifyPassConfig = ModifyPassConfigFunction()); + /// Add a pass-config modifier. + ObjectLinkingLayer &addPlugin(std::unique_ptr P) { + std::lock_guard Lock(LayerMutex); + Plugins.push_back(std::move(P)); + return *this; + } /// Emit the object. void emit(MaterializationResponsibility R, @@ -101,31 +122,35 @@ public: private: using AllocPtr = std::unique_ptr; - class ObjectResources { - public: - ObjectResources() = default; - ObjectResources(AllocPtr Alloc, JITTargetAddress EHFrameAddr); - ObjectResources(ObjectResources &&Other); - ObjectResources &operator=(ObjectResources &&Other); - ~ObjectResources(); - - private: - AllocPtr Alloc; - JITTargetAddress EHFrameAddr = 0; - }; + void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, + jitlink::PassConfiguration &PassConfig); + void notifyLoaded(MaterializationResponsibility &MR); + Error notifyEmitted(MaterializationResponsibility &MR, AllocPtr Alloc); - void notifyFinalized(ObjectResources OR) { - ObjResources.push_back(std::move(OR)); - } + Error removeModule(VModuleKey K); + Error removeAllModules(); mutable std::mutex LayerMutex; jitlink::JITLinkMemoryManager &MemMgr; - NotifyLoadedFunction NotifyLoaded; - NotifyEmittedFunction NotifyEmitted; - ModifyPassConfigFunction ModifyPassConfig; bool OverrideObjectFlags = false; bool AutoClaimObjectSymbols = false; - std::vector ObjResources; + DenseMap TrackedAllocs; + std::vector UntrackedAllocs; + std::vector> Plugins; +}; + +class LocalEHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin { +public: + Error notifyEmitted(MaterializationResponsibility &MR) override; + void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, + jitlink::PassConfiguration &PassConfig) override; + Error notifyRemovingModule(VModuleKey K) override; + Error notifyRemovingAllModules() override; + +private: + DenseMap InProcessLinks; + DenseMap TrackedEHFrameAddrs; + std::vector UntrackedEHFrameAddrs; }; } // end namespace orc diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp index c531df8..b54fd37 100644 --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp @@ -507,8 +507,9 @@ Error deregisterEHFrameSection(const void *EHFrameSectionAddr) { #endif } -AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT, - JITTargetAddress &EHFrameAddr) { +AtomGraphPassFunction +createEHFrameRecorderPass(const Triple &TT, + StoreFrameAddressFunction StoreFrameAddress) { const char *EHFrameSectionName = nullptr; if (TT.getObjectFormat() == Triple::MachO) EHFrameSectionName = "__eh_frame"; @@ -516,7 +517,7 @@ AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT, EHFrameSectionName = ".eh_frame"; auto RecordEHFrame = [EHFrameSectionName, - &EHFrameAddr](AtomGraph &G) -> Error { + StoreFrameAddress](AtomGraph &G) -> Error { // Search for a non-empty eh-frame and record the address of the first atom // in it. JITTargetAddress Addr = 0; @@ -529,7 +530,7 @@ AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT, break; } - EHFrameAddr = Addr; + StoreFrameAddress(Addr); return Error::success(); }; diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index 154d704..eb0ea47 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -133,25 +133,19 @@ public: MR.resolve(InternedResult); - if (Layer.NotifyLoaded) - Layer.NotifyLoaded(MR.getVModuleKey()); + Layer.notifyLoaded(MR); } void notifyFinalized( std::unique_ptr A) override { - if (EHFrameAddr) { - // If there is an eh-frame then try to register it. - if (auto Err = registerEHFrameSection((void *)EHFrameAddr)) { - Layer.getExecutionSession().reportError(std::move(Err)); - MR.failMaterialization(); - return; - } - } + if (auto Err = Layer.notifyEmitted(MR, std::move(A))) { + Layer.getExecutionSession().reportError(std::move(Err)); + MR.failMaterialization(); + return; + } MR.emit(); - Layer.notifyFinalized( - ObjectLinkingLayer::ObjectResources(std::move(A), EHFrameAddr)); } AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override { @@ -166,11 +160,7 @@ public: Config.PostPrunePasses.push_back( [this](AtomGraph &G) { return computeNamedSymbolDependencies(G); }); - Config.PostFixupPasses.push_back( - createEHFrameRecorderPass(TT, EHFrameAddr)); - - if (Layer.ModifyPassConfig) - Layer.ModifyPassConfig(TT, Config); + Layer.modifyPassConfig(MR, TT, Config); return Error::success(); } @@ -328,16 +318,18 @@ private: MaterializationResponsibility MR; std::unique_ptr ObjBuffer; DenseMap NamedSymbolDeps; - JITTargetAddress EHFrameAddr = 0; }; -ObjectLinkingLayer::ObjectLinkingLayer( - ExecutionSession &ES, JITLinkMemoryManager &MemMgr, - NotifyLoadedFunction NotifyLoaded, NotifyEmittedFunction NotifyEmitted, - ModifyPassConfigFunction ModifyPassConfig) - : ObjectLayer(ES), MemMgr(MemMgr), NotifyLoaded(std::move(NotifyLoaded)), - NotifyEmitted(std::move(NotifyEmitted)), - ModifyPassConfig(std::move(ModifyPassConfig)) {} +ObjectLinkingLayer::Plugin::~Plugin() {} + +ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES, + JITLinkMemoryManager &MemMgr) + : ObjectLayer(ES), MemMgr(MemMgr) {} + +ObjectLinkingLayer::~ObjectLinkingLayer() { + if (auto Err = removeAllModules()) + getExecutionSession().reportError(std::move(Err)); +} void ObjectLinkingLayer::emit(MaterializationResponsibility R, std::unique_ptr O) { @@ -346,36 +338,145 @@ void ObjectLinkingLayer::emit(MaterializationResponsibility R, *this, std::move(R), std::move(O))); } -ObjectLinkingLayer::ObjectResources::ObjectResources( - AllocPtr Alloc, JITTargetAddress EHFrameAddr) - : Alloc(std::move(Alloc)), EHFrameAddr(EHFrameAddr) {} +void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR, + const Triple &TT, + PassConfiguration &PassConfig) { + for (auto &P : Plugins) + P->modifyPassConfig(MR, TT, PassConfig); +} + +void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) { + for (auto &P : Plugins) + P->notifyLoaded(MR); +} + +Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR, + AllocPtr Alloc) { + Error Err = Error::success(); + for (auto &P : Plugins) + Err = joinErrors(std::move(Err), P->notifyEmitted(MR)); + + if (Err) + return Err; + + { + std::lock_guard Lock(LayerMutex); + UntrackedAllocs.push_back(std::move(Alloc)); + } -ObjectLinkingLayer::ObjectResources::ObjectResources(ObjectResources &&Other) - : Alloc(std::move(Other.Alloc)), EHFrameAddr(Other.EHFrameAddr) { - Other.EHFrameAddr = 0; + return Error::success(); } -ObjectLinkingLayer::ObjectResources & -ObjectLinkingLayer::ObjectResources::operator=(ObjectResources &&Other) { - std::swap(Alloc, Other.Alloc); - std::swap(EHFrameAddr, Other.EHFrameAddr); - return *this; +Error ObjectLinkingLayer::removeModule(VModuleKey K) { + Error Err = Error::success(); + + for (auto &P : Plugins) + Err = joinErrors(std::move(Err), P->notifyRemovingModule(K)); + + AllocPtr Alloc; + + { + std::lock_guard Lock(LayerMutex); + auto AllocItr = TrackedAllocs.find(K); + Alloc = std::move(AllocItr->second); + TrackedAllocs.erase(AllocItr); + } + + assert(Alloc && "No allocation for key K"); + + return joinErrors(std::move(Err), Alloc->deallocate()); } -ObjectLinkingLayer::ObjectResources::~ObjectResources() { - const char *ErrBanner = - "ObjectLinkingLayer received error deallocating object resources:"; +Error ObjectLinkingLayer::removeAllModules() { - assert((EHFrameAddr == 0 || Alloc) && - "Non-null EHFrameAddr must have an associated allocation"); + Error Err = Error::success(); - if (EHFrameAddr) - if (auto Err = deregisterEHFrameSection((void *)EHFrameAddr)) - logAllUnhandledErrors(std::move(Err), llvm::errs(), ErrBanner); + for (auto &P : Plugins) + Err = joinErrors(std::move(Err), P->notifyRemovingAllModules()); + + std::vector Allocs; + { + std::lock_guard Lock(LayerMutex); + Allocs = std::move(UntrackedAllocs); + + for (auto &KV : TrackedAllocs) + Allocs.push_back(std::move(KV.second)); + + TrackedAllocs.clear(); + } + + while (!Allocs.empty()) { + Err = joinErrors(std::move(Err), Allocs.back()->deallocate()); + Allocs.pop_back(); + } + + return Err; +} + +void LocalEHFrameRegistrationPlugin::modifyPassConfig( + MaterializationResponsibility &MR, const Triple &TT, + PassConfiguration &PassConfig) { + assert(!InProcessLinks.count(&MR) && "Link for MR already being tracked?"); + + PassConfig.PostFixupPasses.push_back( + createEHFrameRecorderPass(TT, [this, &MR](JITTargetAddress Addr) { + if (Addr) + InProcessLinks[&MR] = jitTargetAddressToPointer(Addr); + })); +} + +Error LocalEHFrameRegistrationPlugin::notifyEmitted( + MaterializationResponsibility &MR) { + + auto EHFrameAddrItr = InProcessLinks.find(&MR); + if (EHFrameAddrItr == InProcessLinks.end()) + return Error::success(); + + const void *EHFrameAddr = EHFrameAddrItr->second; + assert(EHFrameAddr && "eh-frame addr to register can not be null"); + + InProcessLinks.erase(EHFrameAddrItr); + if (auto Key = MR.getVModuleKey()) + TrackedEHFrameAddrs[Key] = EHFrameAddr; + else + UntrackedEHFrameAddrs.push_back(EHFrameAddr); + + return registerEHFrameSection(EHFrameAddr); +} + +Error LocalEHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) { + auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K); + if (EHFrameAddrItr == TrackedEHFrameAddrs.end()) + return Error::success(); + + const void *EHFrameAddr = EHFrameAddrItr->second; + assert(EHFrameAddr && "Tracked eh-frame addr must not be null"); + + TrackedEHFrameAddrs.erase(EHFrameAddrItr); + + return deregisterEHFrameSection(EHFrameAddr); +} + +Error LocalEHFrameRegistrationPlugin::notifyRemovingAllModules() { + + std::vector EHFrameAddrs = std::move(UntrackedEHFrameAddrs); + EHFrameAddrs.reserve(EHFrameAddrs.size() + TrackedEHFrameAddrs.size()); + + for (auto &KV : TrackedEHFrameAddrs) + EHFrameAddrs.push_back(KV.second); + + TrackedEHFrameAddrs.clear(); + + Error Err = Error::success(); + + while (!EHFrameAddrs.empty()) { + const void *EHFrameAddr = EHFrameAddrs.back(); + assert(EHFrameAddr && "Untracked eh-frame addr must not be null"); + EHFrameAddrs.pop_back(); + Err = joinErrors(std::move(Err), deregisterEHFrameSection(EHFrameAddr)); + } - if (Alloc) - if (auto Err = Alloc->deallocate()) - logAllUnhandledErrors(std::move(Err), llvm::errs(), ErrBanner); + return Err; } } // End namespace orc. diff --git a/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_ehframe.test b/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_ehframe.test index 5b01d03..08c616f 100644 --- a/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_ehframe.test +++ b/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_ehframe.test @@ -1,9 +1,4 @@ -# RUN: llvm-jitlink -noexec %S/Inputs/MachO_x86-64_ehframe.o -# -# FIXME: Produces these errors: -# JIT session error: Symbols not found: { __ZTIi, ___gxx_personality_v0 } -# llvm-jitlink.exe: Failed to materialize symbols: { biz, _main, baz } -# XFAIL: windows-msvc +# RUN: llvm-jitlink -noexec -define-abs __ZTIi=0x1 -define-abs ___gxx_personality_v0=0x2 %S/Inputs/MachO_x86-64_ehframe.o # # Perform a no-exec link of MachO_x86-64_ehframe and verify that it does not # generate any errors despite the last FDE referring to the first CIE (rather diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp index 383442f..5ecf66a 100644 --- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp @@ -214,13 +214,27 @@ static void dumpSectionContents(raw_ostream &OS, AtomGraph &G) { } } -Session::Session(Triple TT) - : ObjLayer(ES, MemMgr, ObjectLinkingLayer::NotifyLoadedFunction(), - ObjectLinkingLayer::NotifyEmittedFunction(), - [this](const Triple &TT, PassConfiguration &PassConfig) { - modifyPassConfig(TT, PassConfig); - }), - TT(std::move(TT)) {} +Session::Session(Triple TT) : ObjLayer(ES, MemMgr), TT(std::move(TT)) { + + /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the + /// Session. + class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin { + public: + JITLinkSessionPlugin(Session &S) : S(S) {} + void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, + PassConfiguration &PassConfig) { + S.modifyPassConfig(TT, PassConfig); + } + + private: + Session &S; + }; + + if (!NoExec && !TT.isOSWindows()) + ObjLayer.addPlugin(llvm::make_unique()); + + ObjLayer.addPlugin(llvm::make_unique(*this)); +} void Session::dumpSessionInfo(raw_ostream &OS) { OS << "Registered addresses:\n" << SymbolInfos << FileInfos; -- 2.7.4