diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/CMakeLists.txt | 2 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/LinkGraphLayer.cpp | 105 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/LinkGraphLinkingLayer.cpp | 681 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp | 773 |
4 files changed, 795 insertions, 766 deletions
diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt index 5615ad9..93d253e 100644 --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -33,6 +33,8 @@ add_llvm_component_library(LLVMOrcJIT LazyObjectLinkingLayer.cpp LazyReexports.cpp Layer.cpp + LinkGraphLayer.cpp + LinkGraphLinkingLayer.cpp LoadLinkableFile.cpp LookupAndRecordAddrs.cpp LLJIT.cpp diff --git a/llvm/lib/ExecutionEngine/Orc/LinkGraphLayer.cpp b/llvm/lib/ExecutionEngine/Orc/LinkGraphLayer.cpp new file mode 100644 index 0000000..5789079 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/LinkGraphLayer.cpp @@ -0,0 +1,105 @@ +//===----- LinkGraphLayer.cpp - Add LinkGraphs to an ExecutionSession -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/LinkGraphLayer.h" + +#include "llvm/ExecutionEngine/JITLink/JITLink.h" +#include "llvm/ExecutionEngine/Orc/Shared/MachOObjectFormat.h" +#include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h" + +#define DEBUG_TYPE "orc" + +using namespace llvm; +using namespace llvm::jitlink; +using namespace llvm::orc; + +namespace { + +bool hasInitializerSection(LinkGraph &G) { + bool IsMachO = G.getTargetTriple().isOSBinFormatMachO(); + bool IsElf = G.getTargetTriple().isOSBinFormatELF(); + if (!IsMachO && !IsElf) + return false; + + for (auto &Sec : G.sections()) { + if (IsMachO && isMachOInitializerSection(Sec.getName())) + return true; + if (IsElf && isELFInitializerSection(Sec.getName())) + return true; + } + + return false; +} + +} // end anonymous namespace + +namespace llvm::orc { + +LinkGraphLayer::~LinkGraphLayer() = default; + +MaterializationUnit::Interface LinkGraphLayer::getInterface(LinkGraph &G) { + + MaterializationUnit::Interface LGI; + + auto AddSymbol = [&](Symbol *Sym) { + // Skip local symbols. + if (Sym->getScope() == Scope::Local) + return; + assert(Sym->hasName() && "Anonymous non-local symbol?"); + + LGI.SymbolFlags[Sym->getName()] = getJITSymbolFlagsForSymbol(*Sym); + }; + + for (auto *Sym : G.defined_symbols()) + AddSymbol(Sym); + for (auto *Sym : G.absolute_symbols()) + AddSymbol(Sym); + + if (hasInitializerSection(G)) { + std::string InitSymString; + { + raw_string_ostream(InitSymString) + << "$." << G.getName() << ".__inits" << Counter++; + } + LGI.InitSymbol = ES.intern(InitSymString); + } + + return LGI; +} + +JITSymbolFlags LinkGraphLayer::getJITSymbolFlagsForSymbol(Symbol &Sym) { + JITSymbolFlags Flags; + + if (Sym.getLinkage() == Linkage::Weak) + Flags |= JITSymbolFlags::Weak; + + if (Sym.getScope() == Scope::Default) + Flags |= JITSymbolFlags::Exported; + else if (Sym.getScope() == Scope::SideEffectsOnly) + Flags |= JITSymbolFlags::MaterializationSideEffectsOnly; + + if (Sym.isCallable()) + Flags |= JITSymbolFlags::Callable; + + return Flags; +} + +StringRef LinkGraphMaterializationUnit::getName() const { return G->getName(); } + +void LinkGraphMaterializationUnit::discard(const JITDylib &JD, + const SymbolStringPtr &Name) { + for (auto *Sym : G->defined_symbols()) + if (Sym->getName() == Name) { + assert(Sym->getLinkage() == Linkage::Weak && + "Discarding non-weak definition"); + G->makeExternal(*Sym); + break; + } +} + +} // namespace llvm::orc diff --git a/llvm/lib/ExecutionEngine/Orc/LinkGraphLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/LinkGraphLinkingLayer.cpp new file mode 100644 index 0000000..fc5a11b --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/LinkGraphLinkingLayer.cpp @@ -0,0 +1,681 @@ +//===----- LinkGraphLinkingLayer.cpp - JITLink backed ORC ObjectLayer -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/LinkGraphLinkingLayer.h" +#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" +#include "llvm/ExecutionEngine/JITLink/aarch32.h" +#include "llvm/ExecutionEngine/Orc/DebugUtils.h" +#include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h" +#include "llvm/Support/MemoryBuffer.h" + +#define DEBUG_TYPE "orc" + +using namespace llvm; +using namespace llvm::jitlink; +using namespace llvm::orc; + +namespace { + +ExecutorAddr getJITSymbolPtrForSymbol(Symbol &Sym, const Triple &TT) { + switch (TT.getArch()) { + case Triple::arm: + case Triple::armeb: + case Triple::thumb: + case Triple::thumbeb: + if (hasTargetFlags(Sym, aarch32::ThumbSymbol)) { + // Set LSB to indicate thumb target + assert(Sym.isCallable() && "Only callable symbols can have thumb flag"); + assert((Sym.getAddress().getValue() & 0x01) == 0 && "LSB is clear"); + return Sym.getAddress() + 0x01; + } + return Sym.getAddress(); + default: + return Sym.getAddress(); + } +} + +} // end anonymous namespace + +namespace llvm { +namespace orc { + +class LinkGraphLinkingLayer::JITLinkCtx final : public JITLinkContext { +public: + JITLinkCtx(LinkGraphLinkingLayer &Layer, + std::unique_ptr<MaterializationResponsibility> MR, + std::unique_ptr<MemoryBuffer> ObjBuffer) + : JITLinkContext(&MR->getTargetJITDylib()), Layer(Layer), + MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) { + std::lock_guard<std::mutex> Lock(Layer.LayerMutex); + Plugins = Layer.Plugins; + } + + ~JITLinkCtx() { + // If there is an object buffer return function then use it to + // return ownership of the buffer. + if (Layer.ReturnObjectBuffer && ObjBuffer) + Layer.ReturnObjectBuffer(std::move(ObjBuffer)); + } + + JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; } + + void notifyMaterializing(LinkGraph &G) { + for (auto &P : Plugins) + P->notifyMaterializing(*MR, G, *this, + ObjBuffer ? ObjBuffer->getMemBufferRef() + : MemoryBufferRef()); + } + + void notifyFailed(Error Err) override { + for (auto &P : Plugins) + Err = joinErrors(std::move(Err), P->notifyFailed(*MR)); + Layer.getExecutionSession().reportError(std::move(Err)); + MR->failMaterialization(); + } + + void lookup(const LookupMap &Symbols, + std::unique_ptr<JITLinkAsyncLookupContinuation> LC) override { + + JITDylibSearchOrder LinkOrder; + MR->getTargetJITDylib().withLinkOrderDo( + [&](const JITDylibSearchOrder &LO) { LinkOrder = LO; }); + + auto &ES = Layer.getExecutionSession(); + + SymbolLookupSet LookupSet; + for (auto &KV : Symbols) { + orc::SymbolLookupFlags LookupFlags; + switch (KV.second) { + case jitlink::SymbolLookupFlags::RequiredSymbol: + LookupFlags = orc::SymbolLookupFlags::RequiredSymbol; + break; + case jitlink::SymbolLookupFlags::WeaklyReferencedSymbol: + LookupFlags = orc::SymbolLookupFlags::WeaklyReferencedSymbol; + break; + } + LookupSet.add(KV.first, LookupFlags); + } + + // OnResolve -- De-intern the symbols and pass the result to the linker. + auto OnResolve = [LookupContinuation = + std::move(LC)](Expected<SymbolMap> Result) mutable { + if (!Result) + LookupContinuation->run(Result.takeError()); + else { + AsyncLookupResult LR; + for (auto &KV : *Result) + LR[KV.first] = KV.second; + LookupContinuation->run(std::move(LR)); + } + }; + + ES.lookup(LookupKind::Static, LinkOrder, std::move(LookupSet), + SymbolState::Resolved, std::move(OnResolve), + [this](const SymbolDependenceMap &Deps) { + // Translate LookupDeps map to SymbolSourceJD. + for (auto &[DepJD, Deps] : Deps) + for (auto &DepSym : Deps) + SymbolSourceJDs[NonOwningSymbolStringPtr(DepSym)] = DepJD; + }); + } + + Error notifyResolved(LinkGraph &G) override { + + SymbolFlagsMap ExtraSymbolsToClaim; + bool AutoClaim = Layer.AutoClaimObjectSymbols; + + SymbolMap InternedResult; + for (auto *Sym : G.defined_symbols()) + if (Sym->getScope() < Scope::SideEffectsOnly) { + auto Ptr = getJITSymbolPtrForSymbol(*Sym, G.getTargetTriple()); + auto Flags = getJITSymbolFlagsForSymbol(*Sym); + InternedResult[Sym->getName()] = {Ptr, Flags}; + if (AutoClaim && !MR->getSymbols().count(Sym->getName())) { + assert(!ExtraSymbolsToClaim.count(Sym->getName()) && + "Duplicate symbol to claim?"); + ExtraSymbolsToClaim[Sym->getName()] = Flags; + } + } + + for (auto *Sym : G.absolute_symbols()) + if (Sym->getScope() < Scope::SideEffectsOnly) { + auto Ptr = getJITSymbolPtrForSymbol(*Sym, G.getTargetTriple()); + auto Flags = getJITSymbolFlagsForSymbol(*Sym); + InternedResult[Sym->getName()] = {Ptr, Flags}; + if (AutoClaim && !MR->getSymbols().count(Sym->getName())) { + assert(!ExtraSymbolsToClaim.count(Sym->getName()) && + "Duplicate symbol to claim?"); + ExtraSymbolsToClaim[Sym->getName()] = Flags; + } + } + + if (!ExtraSymbolsToClaim.empty()) + if (auto Err = MR->defineMaterializing(ExtraSymbolsToClaim)) + return Err; + + { + + // Check that InternedResult matches up with MR->getSymbols(), overriding + // flags if requested. + // This guards against faulty transformations / compilers / object caches. + + // First check that there aren't any missing symbols. + size_t NumMaterializationSideEffectsOnlySymbols = 0; + SymbolNameVector MissingSymbols; + for (auto &[Sym, Flags] : MR->getSymbols()) { + + auto I = InternedResult.find(Sym); + + // If this is a materialization-side-effects only symbol then bump + // the counter and remove in from the result, otherwise make sure that + // it's defined. + if (Flags.hasMaterializationSideEffectsOnly()) + ++NumMaterializationSideEffectsOnlySymbols; + else if (I == InternedResult.end()) + MissingSymbols.push_back(Sym); + else if (Layer.OverrideObjectFlags) + I->second.setFlags(Flags); + } + + // If there were missing symbols then report the error. + if (!MissingSymbols.empty()) + return make_error<MissingSymbolDefinitions>( + Layer.getExecutionSession().getSymbolStringPool(), G.getName(), + std::move(MissingSymbols)); + + // If there are more definitions than expected, add them to the + // ExtraSymbols vector. + SymbolNameVector ExtraSymbols; + if (InternedResult.size() > + MR->getSymbols().size() - NumMaterializationSideEffectsOnlySymbols) { + for (auto &KV : InternedResult) + if (!MR->getSymbols().count(KV.first)) + ExtraSymbols.push_back(KV.first); + } + + // If there were extra definitions then report the error. + if (!ExtraSymbols.empty()) + return make_error<UnexpectedSymbolDefinitions>( + Layer.getExecutionSession().getSymbolStringPool(), G.getName(), + std::move(ExtraSymbols)); + } + + if (auto Err = MR->notifyResolved(InternedResult)) + return Err; + + notifyLoaded(); + return Error::success(); + } + + void notifyFinalized(JITLinkMemoryManager::FinalizedAlloc A) override { + if (auto Err = notifyEmitted(std::move(A))) { + Layer.getExecutionSession().reportError(std::move(Err)); + MR->failMaterialization(); + return; + } + + if (auto Err = MR->notifyEmitted(SymbolDepGroups)) { + Layer.getExecutionSession().reportError(std::move(Err)); + MR->failMaterialization(); + } + } + + LinkGraphPassFunction getMarkLivePass(const Triple &TT) const override { + return [this](LinkGraph &G) { return markResponsibilitySymbolsLive(G); }; + } + + Error modifyPassConfig(LinkGraph &LG, PassConfiguration &Config) override { + // Add passes to mark duplicate defs as should-discard, and to walk the + // link graph to build the symbol dependence graph. + Config.PrePrunePasses.push_back([this](LinkGraph &G) { + return claimOrExternalizeWeakAndCommonSymbols(G); + }); + + for (auto &P : Plugins) + P->modifyPassConfig(*MR, LG, Config); + + Config.PreFixupPasses.push_back( + [this](LinkGraph &G) { return registerDependencies(G); }); + + return Error::success(); + } + + void notifyLoaded() { + for (auto &P : Plugins) + P->notifyLoaded(*MR); + } + + Error notifyEmitted(jitlink::JITLinkMemoryManager::FinalizedAlloc FA) { + Error Err = Error::success(); + for (auto &P : Plugins) + Err = joinErrors(std::move(Err), P->notifyEmitted(*MR)); + + if (Err) { + if (FA) + Err = + joinErrors(std::move(Err), Layer.MemMgr.deallocate(std::move(FA))); + return Err; + } + + if (FA) + return Layer.recordFinalizedAlloc(*MR, std::move(FA)); + + return Error::success(); + } + +private: + Error claimOrExternalizeWeakAndCommonSymbols(LinkGraph &G) { + SymbolFlagsMap NewSymbolsToClaim; + std::vector<std::pair<SymbolStringPtr, Symbol *>> NameToSym; + + auto ProcessSymbol = [&](Symbol *Sym) { + if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak && + Sym->getScope() != Scope::Local) { + if (!MR->getSymbols().count(Sym->getName())) { + NewSymbolsToClaim[Sym->getName()] = + getJITSymbolFlagsForSymbol(*Sym) | JITSymbolFlags::Weak; + NameToSym.push_back(std::make_pair(Sym->getName(), Sym)); + } + } + }; + + for (auto *Sym : G.defined_symbols()) + ProcessSymbol(Sym); + for (auto *Sym : G.absolute_symbols()) + ProcessSymbol(Sym); + + // Attempt to claim all weak defs that we're not already responsible for. + // This may fail if the resource tracker has become defunct, but should + // always succeed otherwise. + if (auto Err = MR->defineMaterializing(std::move(NewSymbolsToClaim))) + return Err; + + // Walk the list of symbols that we just tried to claim. Symbols that we're + // responsible for are marked live. Symbols that we're not responsible for + // are turned into external references. + for (auto &KV : NameToSym) { + if (MR->getSymbols().count(KV.first)) + KV.second->setLive(true); + else + G.makeExternal(*KV.second); + } + + return Error::success(); + } + + Error markResponsibilitySymbolsLive(LinkGraph &G) const { + for (auto *Sym : G.defined_symbols()) + if (Sym->hasName() && MR->getSymbols().count(Sym->getName())) + Sym->setLive(true); + return Error::success(); + } + + Error registerDependencies(LinkGraph &G) { + + struct BlockInfo { + bool InWorklist = false; + DenseSet<Symbol *> Defs; + DenseSet<Symbol *> SymbolDeps; + DenseSet<Block *> AnonEdges, AnonBackEdges; + }; + + DenseMap<Block *, BlockInfo> BlockInfos; + + // Reserve space so that BlockInfos doesn't need to resize. This is + // essential to avoid invalidating pointers to entries below. + { + size_t NumBlocks = 0; + for (auto &Sec : G.sections()) + NumBlocks += Sec.blocks_size(); + BlockInfos.reserve(NumBlocks); + } + + // Identify non-locally-scoped symbols defined by each block. + for (auto *Sym : G.defined_symbols()) { + if (Sym->getScope() != Scope::Local) + BlockInfos[&Sym->getBlock()].Defs.insert(Sym); + } + + // Identify the symbolic and anonymous-block dependencies for each block. + for (auto *B : G.blocks()) { + auto &BI = BlockInfos[B]; + + for (auto &E : B->edges()) { + + // External symbols are trivially depended on. + if (E.getTarget().isExternal()) { + BI.SymbolDeps.insert(&E.getTarget()); + continue; + } + + // Anonymous symbols aren't depended on at all (they're assumed to be + // already available). + if (E.getTarget().isAbsolute()) + continue; + + // If we get here then we depend on a symbol defined by some other + // block. + auto &TgtBI = BlockInfos[&E.getTarget().getBlock()]; + + // If that block has any definitions then use the first one as the + // "effective" dependence here (all symbols in TgtBI will become + // ready at the same time, and chosing a single symbol to represent + // the block keeps the SymbolDepGroup size small). + if (!TgtBI.Defs.empty()) { + BI.SymbolDeps.insert(*TgtBI.Defs.begin()); + continue; + } + + // Otherwise we've got a dependence on an anonymous block. Record it + // here for back-propagating symbol dependencies below. + BI.AnonEdges.insert(&E.getTarget().getBlock()); + TgtBI.AnonBackEdges.insert(B); + } + } + + // Prune anonymous blocks. + { + std::vector<Block *> BlocksToRemove; + for (auto &[B, BI] : BlockInfos) { + // Skip blocks with defs. We only care about anonyous blocks. + if (!BI.Defs.empty()) + continue; + + BlocksToRemove.push_back(B); + + for (auto *FB : BI.AnonEdges) + BlockInfos[FB].AnonBackEdges.erase(B); + + for (auto *BB : BI.AnonBackEdges) + BlockInfos[BB].AnonEdges.erase(B); + + for (auto *FB : BI.AnonEdges) { + auto &FBI = BlockInfos[FB]; + for (auto *BB : BI.AnonBackEdges) + FBI.AnonBackEdges.insert(BB); + } + + for (auto *BB : BI.AnonBackEdges) { + auto &BBI = BlockInfos[BB]; + for (auto *SD : BI.SymbolDeps) + BBI.SymbolDeps.insert(SD); + for (auto *FB : BI.AnonEdges) + BBI.AnonEdges.insert(FB); + } + } + + for (auto *B : BlocksToRemove) + BlockInfos.erase(B); + } + + // Build the initial dependence propagation worklist. + std::deque<Block *> Worklist; + for (auto &[B, BI] : BlockInfos) { + if (!BI.SymbolDeps.empty() && !BI.AnonBackEdges.empty()) { + Worklist.push_back(B); + BI.InWorklist = true; + } + } + + // Propagate symbol deps through the graph. + while (!Worklist.empty()) { + auto *B = Worklist.front(); + Worklist.pop_front(); + + auto &BI = BlockInfos[B]; + BI.InWorklist = false; + + for (auto *DB : BI.AnonBackEdges) { + auto &DBI = BlockInfos[DB]; + for (auto *Sym : BI.SymbolDeps) { + if (DBI.SymbolDeps.insert(Sym).second && !DBI.InWorklist) { + Worklist.push_back(DB); + DBI.InWorklist = true; + } + } + } + } + + // Transform our local dependence information into a list of + // SymbolDependenceGroups (in the SymbolDepGroups member), ready for use in + // the upcoming notifyFinalized call. + auto &TargetJD = MR->getTargetJITDylib(); + + for (auto &[B, BI] : BlockInfos) { + if (!BI.Defs.empty()) { + SymbolDepGroups.push_back(SymbolDependenceGroup()); + auto &SDG = SymbolDepGroups.back(); + + for (auto *Def : BI.Defs) + SDG.Symbols.insert(Def->getName()); + + for (auto *Dep : BI.SymbolDeps) { + auto DepName = Dep->getName(); + if (Dep->isDefined()) + SDG.Dependencies[&TargetJD].insert(std::move(DepName)); + else { + auto SourceJDItr = + SymbolSourceJDs.find(NonOwningSymbolStringPtr(DepName)); + if (SourceJDItr != SymbolSourceJDs.end()) + SDG.Dependencies[SourceJDItr->second].insert(std::move(DepName)); + } + } + } + } + + return Error::success(); + } + + LinkGraphLinkingLayer &Layer; + std::vector<std::shared_ptr<LinkGraphLinkingLayer::Plugin>> Plugins; + std::unique_ptr<MaterializationResponsibility> MR; + std::unique_ptr<MemoryBuffer> ObjBuffer; + DenseMap<NonOwningSymbolStringPtr, JITDylib *> SymbolSourceJDs; + std::vector<SymbolDependenceGroup> SymbolDepGroups; +}; + +LinkGraphLinkingLayer::Plugin::~Plugin() = default; + +LinkGraphLinkingLayer::LinkGraphLinkingLayer(ExecutionSession &ES) + : LinkGraphLayer(ES), MemMgr(ES.getExecutorProcessControl().getMemMgr()) { + ES.registerResourceManager(*this); +} + +LinkGraphLinkingLayer::LinkGraphLinkingLayer(ExecutionSession &ES, + JITLinkMemoryManager &MemMgr) + : LinkGraphLayer(ES), MemMgr(MemMgr) { + ES.registerResourceManager(*this); +} + +LinkGraphLinkingLayer::LinkGraphLinkingLayer( + ExecutionSession &ES, std::unique_ptr<JITLinkMemoryManager> MemMgr) + : LinkGraphLayer(ES), MemMgr(*MemMgr), MemMgrOwnership(std::move(MemMgr)) { + ES.registerResourceManager(*this); +} + +LinkGraphLinkingLayer::~LinkGraphLinkingLayer() { + assert(Allocs.empty() && "Layer destroyed with resources still attached"); + getExecutionSession().deregisterResourceManager(*this); +} + +void LinkGraphLinkingLayer::emit( + std::unique_ptr<MaterializationResponsibility> R, + std::unique_ptr<LinkGraph> G) { + assert(R && "R must not be null"); + assert(G && "G must not be null"); + auto Ctx = std::make_unique<JITLinkCtx>(*this, std::move(R), nullptr); + Ctx->notifyMaterializing(*G); + link(std::move(G), std::move(Ctx)); +} + +void LinkGraphLinkingLayer::emit( + std::unique_ptr<MaterializationResponsibility> R, + std::unique_ptr<LinkGraph> G, std::unique_ptr<MemoryBuffer> ObjBuf) { + assert(R && "R must not be null"); + assert(G && "G must not be null"); + assert(ObjBuf && "Object must not be null"); + auto Ctx = + std::make_unique<JITLinkCtx>(*this, std::move(R), std::move(ObjBuf)); + Ctx->notifyMaterializing(*G); + link(std::move(G), std::move(Ctx)); +} + +Error LinkGraphLinkingLayer::recordFinalizedAlloc( + MaterializationResponsibility &MR, FinalizedAlloc FA) { + auto Err = MR.withResourceKeyDo( + [&](ResourceKey K) { Allocs[K].push_back(std::move(FA)); }); + + if (Err) + Err = joinErrors(std::move(Err), MemMgr.deallocate(std::move(FA))); + + return Err; +} + +Error LinkGraphLinkingLayer::handleRemoveResources(JITDylib &JD, + ResourceKey K) { + + { + Error Err = Error::success(); + for (auto &P : Plugins) + Err = joinErrors(std::move(Err), P->notifyRemovingResources(JD, K)); + if (Err) + return Err; + } + + std::vector<FinalizedAlloc> AllocsToRemove; + getExecutionSession().runSessionLocked([&] { + auto I = Allocs.find(K); + if (I != Allocs.end()) { + std::swap(AllocsToRemove, I->second); + Allocs.erase(I); + } + }); + + if (AllocsToRemove.empty()) + return Error::success(); + + return MemMgr.deallocate(std::move(AllocsToRemove)); +} + +void LinkGraphLinkingLayer::handleTransferResources(JITDylib &JD, + ResourceKey DstKey, + ResourceKey SrcKey) { + if (Allocs.contains(SrcKey)) { + // DstKey may not be in the DenseMap yet, so the following line may resize + // the container and invalidate iterators and value references. + auto &DstAllocs = Allocs[DstKey]; + auto &SrcAllocs = Allocs[SrcKey]; + DstAllocs.reserve(DstAllocs.size() + SrcAllocs.size()); + for (auto &Alloc : SrcAllocs) + DstAllocs.push_back(std::move(Alloc)); + + Allocs.erase(SrcKey); + } + + for (auto &P : Plugins) + P->notifyTransferringResources(JD, DstKey, SrcKey); +} + +EHFrameRegistrationPlugin::EHFrameRegistrationPlugin( + ExecutionSession &ES, std::unique_ptr<EHFrameRegistrar> Registrar) + : ES(ES), Registrar(std::move(Registrar)) {} + +void EHFrameRegistrationPlugin::modifyPassConfig( + MaterializationResponsibility &MR, LinkGraph &G, + PassConfiguration &PassConfig) { + + PassConfig.PostFixupPasses.push_back(createEHFrameRecorderPass( + G.getTargetTriple(), [this, &MR](ExecutorAddr Addr, size_t Size) { + if (Addr) { + std::lock_guard<std::mutex> Lock(EHFramePluginMutex); + assert(!InProcessLinks.count(&MR) && + "Link for MR already being tracked?"); + InProcessLinks[&MR] = {Addr, Size}; + } + })); +} + +Error EHFrameRegistrationPlugin::notifyEmitted( + MaterializationResponsibility &MR) { + + ExecutorAddrRange EmittedRange; + { + std::lock_guard<std::mutex> Lock(EHFramePluginMutex); + + auto EHFrameRangeItr = InProcessLinks.find(&MR); + if (EHFrameRangeItr == InProcessLinks.end()) + return Error::success(); + + EmittedRange = EHFrameRangeItr->second; + assert(EmittedRange.Start && "eh-frame addr to register can not be null"); + InProcessLinks.erase(EHFrameRangeItr); + } + + if (auto Err = MR.withResourceKeyDo( + [&](ResourceKey K) { EHFrameRanges[K].push_back(EmittedRange); })) + return Err; + + return Registrar->registerEHFrames(EmittedRange); +} + +Error EHFrameRegistrationPlugin::notifyFailed( + MaterializationResponsibility &MR) { + std::lock_guard<std::mutex> Lock(EHFramePluginMutex); + InProcessLinks.erase(&MR); + return Error::success(); +} + +Error EHFrameRegistrationPlugin::notifyRemovingResources(JITDylib &JD, + ResourceKey K) { + std::vector<ExecutorAddrRange> RangesToRemove; + + ES.runSessionLocked([&] { + auto I = EHFrameRanges.find(K); + if (I != EHFrameRanges.end()) { + RangesToRemove = std::move(I->second); + EHFrameRanges.erase(I); + } + }); + + Error Err = Error::success(); + while (!RangesToRemove.empty()) { + auto RangeToRemove = RangesToRemove.back(); + RangesToRemove.pop_back(); + assert(RangeToRemove.Start && "Untracked eh-frame range must not be null"); + Err = joinErrors(std::move(Err), + Registrar->deregisterEHFrames(RangeToRemove)); + } + + return Err; +} + +void EHFrameRegistrationPlugin::notifyTransferringResources( + JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) { + auto SI = EHFrameRanges.find(SrcKey); + if (SI == EHFrameRanges.end()) + return; + + auto DI = EHFrameRanges.find(DstKey); + if (DI != EHFrameRanges.end()) { + auto &SrcRanges = SI->second; + auto &DstRanges = DI->second; + DstRanges.reserve(DstRanges.size() + SrcRanges.size()); + for (auto &SrcRange : SrcRanges) + DstRanges.push_back(std::move(SrcRange)); + EHFrameRanges.erase(SI); + } else { + // We need to move SrcKey's ranges over without invalidating the SI + // iterator. + auto Tmp = std::move(SI->second); + EHFrameRanges.erase(SI); + EHFrameRanges[DstKey] = std::move(Tmp); + } +} + +} // End namespace orc. +} // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index 4630e62..6688b09 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -7,789 +7,30 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" -#include "llvm/ExecutionEngine/JITLink/aarch32.h" #include "llvm/ExecutionEngine/Orc/DebugUtils.h" -#include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h" #include "llvm/Support/MemoryBuffer.h" -#include <string> - #define DEBUG_TYPE "orc" -using namespace llvm; -using namespace llvm::jitlink; -using namespace llvm::orc; - -namespace { - -bool hasInitializerSection(jitlink::LinkGraph &G) { - bool IsMachO = G.getTargetTriple().isOSBinFormatMachO(); - bool IsElf = G.getTargetTriple().isOSBinFormatELF(); - if (!IsMachO && !IsElf) - return false; - - for (auto &Sec : G.sections()) { - if (IsMachO && isMachOInitializerSection(Sec.getName())) - return true; - if (IsElf && isELFInitializerSection(Sec.getName())) - return true; - } - - return false; -} - -ExecutorAddr getJITSymbolPtrForSymbol(Symbol &Sym, const Triple &TT) { - switch (TT.getArch()) { - case Triple::arm: - case Triple::armeb: - case Triple::thumb: - case Triple::thumbeb: - if (hasTargetFlags(Sym, aarch32::ThumbSymbol)) { - // Set LSB to indicate thumb target - assert(Sym.isCallable() && "Only callable symbols can have thumb flag"); - assert((Sym.getAddress().getValue() & 0x01) == 0 && "LSB is clear"); - return Sym.getAddress() + 0x01; - } - return Sym.getAddress(); - default: - return Sym.getAddress(); - } -} - -JITSymbolFlags getJITSymbolFlagsForSymbol(Symbol &Sym) { - JITSymbolFlags Flags; - - if (Sym.getLinkage() == Linkage::Weak) - Flags |= JITSymbolFlags::Weak; - - if (Sym.getScope() == Scope::Default) - Flags |= JITSymbolFlags::Exported; - else if (Sym.getScope() == Scope::SideEffectsOnly) - Flags |= JITSymbolFlags::MaterializationSideEffectsOnly; - - if (Sym.isCallable()) - Flags |= JITSymbolFlags::Callable; - - return Flags; -} - -class LinkGraphMaterializationUnit : public MaterializationUnit { -public: - static std::unique_ptr<LinkGraphMaterializationUnit> - Create(ObjectLinkingLayer &ObjLinkingLayer, std::unique_ptr<LinkGraph> G) { - auto LGI = scanLinkGraph(ObjLinkingLayer.getExecutionSession(), *G); - return std::unique_ptr<LinkGraphMaterializationUnit>( - new LinkGraphMaterializationUnit(ObjLinkingLayer, std::move(G), - std::move(LGI))); - } - - StringRef getName() const override { return G->getName(); } - void materialize(std::unique_ptr<MaterializationResponsibility> MR) override { - ObjLinkingLayer.emit(std::move(MR), std::move(G)); - } - -private: - static Interface scanLinkGraph(ExecutionSession &ES, LinkGraph &G) { - - Interface LGI; - - auto AddSymbol = [&](Symbol *Sym) { - // Skip local symbols. - if (Sym->getScope() == Scope::Local) - return; - assert(Sym->hasName() && "Anonymous non-local symbol?"); - - LGI.SymbolFlags[Sym->getName()] = getJITSymbolFlagsForSymbol(*Sym); - }; - - for (auto *Sym : G.defined_symbols()) - AddSymbol(Sym); - for (auto *Sym : G.absolute_symbols()) - AddSymbol(Sym); - - if (hasInitializerSection(G)) - LGI.InitSymbol = makeInitSymbol(ES, G); - - return LGI; - } - - static SymbolStringPtr makeInitSymbol(ExecutionSession &ES, LinkGraph &G) { - std::string InitSymString; - raw_string_ostream(InitSymString) - << "$." << G.getName() << ".__inits" << Counter++; - return ES.intern(InitSymString); - } - - LinkGraphMaterializationUnit(ObjectLinkingLayer &ObjLinkingLayer, - std::unique_ptr<LinkGraph> G, Interface LGI) - : MaterializationUnit(std::move(LGI)), ObjLinkingLayer(ObjLinkingLayer), - G(std::move(G)) {} - - void discard(const JITDylib &JD, const SymbolStringPtr &Name) override { - for (auto *Sym : G->defined_symbols()) - if (Sym->getName() == Name) { - assert(Sym->getLinkage() == Linkage::Weak && - "Discarding non-weak definition"); - G->makeExternal(*Sym); - break; - } - } - - ObjectLinkingLayer &ObjLinkingLayer; - std::unique_ptr<LinkGraph> G; - static std::atomic<uint64_t> Counter; -}; - -std::atomic<uint64_t> LinkGraphMaterializationUnit::Counter{0}; - -} // end anonymous namespace - -namespace llvm { -namespace orc { - -class ObjectLinkingLayer::JITLinkCtx final : public JITLinkContext { -public: - JITLinkCtx(ObjectLinkingLayer &Layer, - std::unique_ptr<MaterializationResponsibility> MR, - std::unique_ptr<MemoryBuffer> ObjBuffer) - : JITLinkContext(&MR->getTargetJITDylib()), Layer(Layer), - MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) { - std::lock_guard<std::mutex> Lock(Layer.LayerMutex); - Plugins = Layer.Plugins; - } - - ~JITLinkCtx() { - // If there is an object buffer return function then use it to - // return ownership of the buffer. - if (Layer.ReturnObjectBuffer && ObjBuffer) - Layer.ReturnObjectBuffer(std::move(ObjBuffer)); - } - - JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; } - - void notifyMaterializing(LinkGraph &G) { - for (auto &P : Plugins) - P->notifyMaterializing(*MR, G, *this, - ObjBuffer ? ObjBuffer->getMemBufferRef() - : MemoryBufferRef()); - } - - void notifyFailed(Error Err) override { - for (auto &P : Plugins) - Err = joinErrors(std::move(Err), P->notifyFailed(*MR)); - Layer.getExecutionSession().reportError(std::move(Err)); - MR->failMaterialization(); - } - - void lookup(const LookupMap &Symbols, - std::unique_ptr<JITLinkAsyncLookupContinuation> LC) override { - - JITDylibSearchOrder LinkOrder; - MR->getTargetJITDylib().withLinkOrderDo( - [&](const JITDylibSearchOrder &LO) { LinkOrder = LO; }); - - auto &ES = Layer.getExecutionSession(); - - SymbolLookupSet LookupSet; - for (auto &KV : Symbols) { - orc::SymbolLookupFlags LookupFlags; - switch (KV.second) { - case jitlink::SymbolLookupFlags::RequiredSymbol: - LookupFlags = orc::SymbolLookupFlags::RequiredSymbol; - break; - case jitlink::SymbolLookupFlags::WeaklyReferencedSymbol: - LookupFlags = orc::SymbolLookupFlags::WeaklyReferencedSymbol; - break; - } - LookupSet.add(KV.first, LookupFlags); - } - - // OnResolve -- De-intern the symbols and pass the result to the linker. - auto OnResolve = [LookupContinuation = - std::move(LC)](Expected<SymbolMap> Result) mutable { - if (!Result) - LookupContinuation->run(Result.takeError()); - else { - AsyncLookupResult LR; - for (auto &KV : *Result) - LR[KV.first] = KV.second; - LookupContinuation->run(std::move(LR)); - } - }; - - ES.lookup(LookupKind::Static, LinkOrder, std::move(LookupSet), - SymbolState::Resolved, std::move(OnResolve), - [this](const SymbolDependenceMap &Deps) { - // Translate LookupDeps map to SymbolSourceJD. - for (auto &[DepJD, Deps] : Deps) - for (auto &DepSym : Deps) - SymbolSourceJDs[NonOwningSymbolStringPtr(DepSym)] = DepJD; - }); - } - - Error notifyResolved(LinkGraph &G) override { - - SymbolFlagsMap ExtraSymbolsToClaim; - bool AutoClaim = Layer.AutoClaimObjectSymbols; - - SymbolMap InternedResult; - for (auto *Sym : G.defined_symbols()) - if (Sym->getScope() < Scope::SideEffectsOnly) { - auto Ptr = getJITSymbolPtrForSymbol(*Sym, G.getTargetTriple()); - auto Flags = getJITSymbolFlagsForSymbol(*Sym); - InternedResult[Sym->getName()] = {Ptr, Flags}; - if (AutoClaim && !MR->getSymbols().count(Sym->getName())) { - assert(!ExtraSymbolsToClaim.count(Sym->getName()) && - "Duplicate symbol to claim?"); - ExtraSymbolsToClaim[Sym->getName()] = Flags; - } - } - - for (auto *Sym : G.absolute_symbols()) - if (Sym->getScope() < Scope::SideEffectsOnly) { - auto Ptr = getJITSymbolPtrForSymbol(*Sym, G.getTargetTriple()); - auto Flags = getJITSymbolFlagsForSymbol(*Sym); - InternedResult[Sym->getName()] = {Ptr, Flags}; - if (AutoClaim && !MR->getSymbols().count(Sym->getName())) { - assert(!ExtraSymbolsToClaim.count(Sym->getName()) && - "Duplicate symbol to claim?"); - ExtraSymbolsToClaim[Sym->getName()] = Flags; - } - } - - if (!ExtraSymbolsToClaim.empty()) - if (auto Err = MR->defineMaterializing(ExtraSymbolsToClaim)) - return Err; - - { - - // Check that InternedResult matches up with MR->getSymbols(), overriding - // flags if requested. - // This guards against faulty transformations / compilers / object caches. - - // First check that there aren't any missing symbols. - size_t NumMaterializationSideEffectsOnlySymbols = 0; - SymbolNameVector MissingSymbols; - for (auto &[Sym, Flags] : MR->getSymbols()) { - - auto I = InternedResult.find(Sym); - - // If this is a materialization-side-effects only symbol then bump - // the counter and remove in from the result, otherwise make sure that - // it's defined. - if (Flags.hasMaterializationSideEffectsOnly()) - ++NumMaterializationSideEffectsOnlySymbols; - else if (I == InternedResult.end()) - MissingSymbols.push_back(Sym); - else if (Layer.OverrideObjectFlags) - I->second.setFlags(Flags); - } - - // If there were missing symbols then report the error. - if (!MissingSymbols.empty()) - return make_error<MissingSymbolDefinitions>( - Layer.getExecutionSession().getSymbolStringPool(), G.getName(), - std::move(MissingSymbols)); - - // If there are more definitions than expected, add them to the - // ExtraSymbols vector. - SymbolNameVector ExtraSymbols; - if (InternedResult.size() > - MR->getSymbols().size() - NumMaterializationSideEffectsOnlySymbols) { - for (auto &KV : InternedResult) - if (!MR->getSymbols().count(KV.first)) - ExtraSymbols.push_back(KV.first); - } - - // If there were extra definitions then report the error. - if (!ExtraSymbols.empty()) - return make_error<UnexpectedSymbolDefinitions>( - Layer.getExecutionSession().getSymbolStringPool(), G.getName(), - std::move(ExtraSymbols)); - } - - if (auto Err = MR->notifyResolved(InternedResult)) - return Err; - - notifyLoaded(); - return Error::success(); - } - - void notifyFinalized(JITLinkMemoryManager::FinalizedAlloc A) override { - if (auto Err = notifyEmitted(std::move(A))) { - Layer.getExecutionSession().reportError(std::move(Err)); - MR->failMaterialization(); - return; - } - - if (auto Err = MR->notifyEmitted(SymbolDepGroups)) { - Layer.getExecutionSession().reportError(std::move(Err)); - MR->failMaterialization(); - } - } - - LinkGraphPassFunction getMarkLivePass(const Triple &TT) const override { - return [this](LinkGraph &G) { return markResponsibilitySymbolsLive(G); }; - } - - Error modifyPassConfig(LinkGraph &LG, PassConfiguration &Config) override { - // Add passes to mark duplicate defs as should-discard, and to walk the - // link graph to build the symbol dependence graph. - Config.PrePrunePasses.push_back([this](LinkGraph &G) { - return claimOrExternalizeWeakAndCommonSymbols(G); - }); - - for (auto &P : Plugins) - P->modifyPassConfig(*MR, LG, Config); - - Config.PreFixupPasses.push_back( - [this](LinkGraph &G) { return registerDependencies(G); }); - - return Error::success(); - } - - void notifyLoaded() { - for (auto &P : Plugins) - P->notifyLoaded(*MR); - } - - Error notifyEmitted(jitlink::JITLinkMemoryManager::FinalizedAlloc FA) { - Error Err = Error::success(); - for (auto &P : Plugins) - Err = joinErrors(std::move(Err), P->notifyEmitted(*MR)); - - if (Err) { - if (FA) - Err = - joinErrors(std::move(Err), Layer.MemMgr.deallocate(std::move(FA))); - return Err; - } - - if (FA) - return Layer.recordFinalizedAlloc(*MR, std::move(FA)); - - return Error::success(); - } - -private: - Error claimOrExternalizeWeakAndCommonSymbols(LinkGraph &G) { - SymbolFlagsMap NewSymbolsToClaim; - std::vector<std::pair<SymbolStringPtr, Symbol *>> NameToSym; - - auto ProcessSymbol = [&](Symbol *Sym) { - if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak && - Sym->getScope() != Scope::Local) { - if (!MR->getSymbols().count(Sym->getName())) { - NewSymbolsToClaim[Sym->getName()] = - getJITSymbolFlagsForSymbol(*Sym) | JITSymbolFlags::Weak; - NameToSym.push_back(std::make_pair(Sym->getName(), Sym)); - } - } - }; - - for (auto *Sym : G.defined_symbols()) - ProcessSymbol(Sym); - for (auto *Sym : G.absolute_symbols()) - ProcessSymbol(Sym); - - // Attempt to claim all weak defs that we're not already responsible for. - // This may fail if the resource tracker has become defunct, but should - // always succeed otherwise. - if (auto Err = MR->defineMaterializing(std::move(NewSymbolsToClaim))) - return Err; - - // Walk the list of symbols that we just tried to claim. Symbols that we're - // responsible for are marked live. Symbols that we're not responsible for - // are turned into external references. - for (auto &KV : NameToSym) { - if (MR->getSymbols().count(KV.first)) - KV.second->setLive(true); - else - G.makeExternal(*KV.second); - } - - return Error::success(); - } - - Error markResponsibilitySymbolsLive(LinkGraph &G) const { - for (auto *Sym : G.defined_symbols()) - if (Sym->hasName() && MR->getSymbols().count(Sym->getName())) - Sym->setLive(true); - return Error::success(); - } - - Error registerDependencies(LinkGraph &G) { - - struct BlockInfo { - bool InWorklist = false; - DenseSet<Symbol *> Defs; - DenseSet<Symbol *> SymbolDeps; - DenseSet<Block *> AnonEdges, AnonBackEdges; - }; - - DenseMap<Block *, BlockInfo> BlockInfos; - - // Reserve space so that BlockInfos doesn't need to resize. This is - // essential to avoid invalidating pointers to entries below. - { - size_t NumBlocks = 0; - for (auto &Sec : G.sections()) - NumBlocks += Sec.blocks_size(); - BlockInfos.reserve(NumBlocks); - } - - // Identify non-locally-scoped symbols defined by each block. - for (auto *Sym : G.defined_symbols()) { - if (Sym->getScope() != Scope::Local) - BlockInfos[&Sym->getBlock()].Defs.insert(Sym); - } - - // Identify the symbolic and anonymous-block dependencies for each block. - for (auto *B : G.blocks()) { - auto &BI = BlockInfos[B]; - - for (auto &E : B->edges()) { - - // External symbols are trivially depended on. - if (E.getTarget().isExternal()) { - BI.SymbolDeps.insert(&E.getTarget()); - continue; - } - - // Anonymous symbols aren't depended on at all (they're assumed to be - // already available). - if (E.getTarget().isAbsolute()) - continue; - - // If we get here then we depend on a symbol defined by some other - // block. - auto &TgtBI = BlockInfos[&E.getTarget().getBlock()]; - - // If that block has any definitions then use the first one as the - // "effective" dependence here (all symbols in TgtBI will become - // ready at the same time, and chosing a single symbol to represent - // the block keeps the SymbolDepGroup size small). - if (!TgtBI.Defs.empty()) { - BI.SymbolDeps.insert(*TgtBI.Defs.begin()); - continue; - } - - // Otherwise we've got a dependence on an anonymous block. Record it - // here for back-propagating symbol dependencies below. - BI.AnonEdges.insert(&E.getTarget().getBlock()); - TgtBI.AnonBackEdges.insert(B); - } - } - - // Prune anonymous blocks. - { - std::vector<Block *> BlocksToRemove; - for (auto &[B, BI] : BlockInfos) { - // Skip blocks with defs. We only care about anonyous blocks. - if (!BI.Defs.empty()) - continue; - - BlocksToRemove.push_back(B); - - for (auto *FB : BI.AnonEdges) - BlockInfos[FB].AnonBackEdges.erase(B); - - for (auto *BB : BI.AnonBackEdges) - BlockInfos[BB].AnonEdges.erase(B); - - for (auto *FB : BI.AnonEdges) { - auto &FBI = BlockInfos[FB]; - for (auto *BB : BI.AnonBackEdges) - FBI.AnonBackEdges.insert(BB); - } - - for (auto *BB : BI.AnonBackEdges) { - auto &BBI = BlockInfos[BB]; - for (auto *SD : BI.SymbolDeps) - BBI.SymbolDeps.insert(SD); - for (auto *FB : BI.AnonEdges) - BBI.AnonEdges.insert(FB); - } - } - - for (auto *B : BlocksToRemove) - BlockInfos.erase(B); - } - - // Build the initial dependence propagation worklist. - std::deque<Block *> Worklist; - for (auto &[B, BI] : BlockInfos) { - if (!BI.SymbolDeps.empty() && !BI.AnonBackEdges.empty()) { - Worklist.push_back(B); - BI.InWorklist = true; - } - } - - // Propagate symbol deps through the graph. - while (!Worklist.empty()) { - auto *B = Worklist.front(); - Worklist.pop_front(); - - auto &BI = BlockInfos[B]; - BI.InWorklist = false; - - for (auto *DB : BI.AnonBackEdges) { - auto &DBI = BlockInfos[DB]; - for (auto *Sym : BI.SymbolDeps) { - if (DBI.SymbolDeps.insert(Sym).second && !DBI.InWorklist) { - Worklist.push_back(DB); - DBI.InWorklist = true; - } - } - } - } - - // Transform our local dependence information into a list of - // SymbolDependenceGroups (in the SymbolDepGroups member), ready for use in - // the upcoming notifyFinalized call. - auto &TargetJD = MR->getTargetJITDylib(); - - for (auto &[B, BI] : BlockInfos) { - if (!BI.Defs.empty()) { - SymbolDepGroups.push_back(SymbolDependenceGroup()); - auto &SDG = SymbolDepGroups.back(); - - for (auto *Def : BI.Defs) - SDG.Symbols.insert(Def->getName()); - - for (auto *Dep : BI.SymbolDeps) { - auto DepName = Dep->getName(); - if (Dep->isDefined()) - SDG.Dependencies[&TargetJD].insert(std::move(DepName)); - else { - auto SourceJDItr = - SymbolSourceJDs.find(NonOwningSymbolStringPtr(DepName)); - if (SourceJDItr != SymbolSourceJDs.end()) - SDG.Dependencies[SourceJDItr->second].insert(std::move(DepName)); - } - } - } - } - - return Error::success(); - } - - ObjectLinkingLayer &Layer; - std::vector<std::shared_ptr<ObjectLinkingLayer::Plugin>> Plugins; - std::unique_ptr<MaterializationResponsibility> MR; - std::unique_ptr<MemoryBuffer> ObjBuffer; - DenseMap<NonOwningSymbolStringPtr, JITDylib *> SymbolSourceJDs; - std::vector<SymbolDependenceGroup> SymbolDepGroups; -}; - -ObjectLinkingLayer::Plugin::~Plugin() = default; +namespace llvm::orc { char ObjectLinkingLayer::ID; -using BaseT = RTTIExtends<ObjectLinkingLayer, ObjectLayer>; - -ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES) - : BaseT(ES), MemMgr(ES.getExecutorProcessControl().getMemMgr()) { - ES.registerResourceManager(*this); -} - -ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES, - JITLinkMemoryManager &MemMgr) - : BaseT(ES), MemMgr(MemMgr) { - ES.registerResourceManager(*this); -} - -ObjectLinkingLayer::ObjectLinkingLayer( - ExecutionSession &ES, std::unique_ptr<JITLinkMemoryManager> MemMgr) - : BaseT(ES), MemMgr(*MemMgr), MemMgrOwnership(std::move(MemMgr)) { - ES.registerResourceManager(*this); -} - -ObjectLinkingLayer::~ObjectLinkingLayer() { - assert(Allocs.empty() && "Layer destroyed with resources still attached"); - getExecutionSession().deregisterResourceManager(*this); -} - -Error ObjectLinkingLayer::add(ResourceTrackerSP RT, - std::unique_ptr<LinkGraph> G) { - auto &JD = RT->getJITDylib(); - return JD.define(LinkGraphMaterializationUnit::Create(*this, std::move(G)), - std::move(RT)); -} +using BaseObjectLayer = RTTIExtends<ObjectLinkingLayer, ObjectLayer>; void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R, std::unique_ptr<MemoryBuffer> O) { assert(O && "Object must not be null"); MemoryBufferRef ObjBuffer = O->getMemBufferRef(); - auto Ctx = std::make_unique<JITLinkCtx>(*this, std::move(R), std::move(O)); - if (auto G = createLinkGraphFromObject( + if (auto G = jitlink::createLinkGraphFromObject( ObjBuffer, getExecutionSession().getSymbolStringPool())) { - Ctx->notifyMaterializing(**G); - link(std::move(*G), std::move(Ctx)); + emit(std::move(R), std::move(*G), std::move(O)); } else { - Ctx->notifyFailed(G.takeError()); - } -} - -void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R, - std::unique_ptr<LinkGraph> G) { - auto Ctx = std::make_unique<JITLinkCtx>(*this, std::move(R), nullptr); - Ctx->notifyMaterializing(*G); - link(std::move(G), std::move(Ctx)); -} - -Error ObjectLinkingLayer::recordFinalizedAlloc( - MaterializationResponsibility &MR, FinalizedAlloc FA) { - auto Err = MR.withResourceKeyDo( - [&](ResourceKey K) { Allocs[K].push_back(std::move(FA)); }); - - if (Err) - Err = joinErrors(std::move(Err), MemMgr.deallocate(std::move(FA))); - - return Err; -} - -Error ObjectLinkingLayer::handleRemoveResources(JITDylib &JD, ResourceKey K) { - - { - Error Err = Error::success(); - for (auto &P : Plugins) - Err = joinErrors(std::move(Err), P->notifyRemovingResources(JD, K)); - if (Err) - return Err; - } - - std::vector<FinalizedAlloc> AllocsToRemove; - getExecutionSession().runSessionLocked([&] { - auto I = Allocs.find(K); - if (I != Allocs.end()) { - std::swap(AllocsToRemove, I->second); - Allocs.erase(I); - } - }); - - if (AllocsToRemove.empty()) - return Error::success(); - - return MemMgr.deallocate(std::move(AllocsToRemove)); -} - -void ObjectLinkingLayer::handleTransferResources(JITDylib &JD, - ResourceKey DstKey, - ResourceKey SrcKey) { - if (Allocs.contains(SrcKey)) { - // DstKey may not be in the DenseMap yet, so the following line may resize - // the container and invalidate iterators and value references. - auto &DstAllocs = Allocs[DstKey]; - auto &SrcAllocs = Allocs[SrcKey]; - DstAllocs.reserve(DstAllocs.size() + SrcAllocs.size()); - for (auto &Alloc : SrcAllocs) - DstAllocs.push_back(std::move(Alloc)); - - Allocs.erase(SrcKey); - } - - for (auto &P : Plugins) - P->notifyTransferringResources(JD, DstKey, SrcKey); -} - -EHFrameRegistrationPlugin::EHFrameRegistrationPlugin( - ExecutionSession &ES, std::unique_ptr<EHFrameRegistrar> Registrar) - : ES(ES), Registrar(std::move(Registrar)) {} - -void EHFrameRegistrationPlugin::modifyPassConfig( - MaterializationResponsibility &MR, LinkGraph &G, - PassConfiguration &PassConfig) { - - PassConfig.PostFixupPasses.push_back(createEHFrameRecorderPass( - G.getTargetTriple(), [this, &MR](ExecutorAddr Addr, size_t Size) { - if (Addr) { - std::lock_guard<std::mutex> Lock(EHFramePluginMutex); - assert(!InProcessLinks.count(&MR) && - "Link for MR already being tracked?"); - InProcessLinks[&MR] = {Addr, Size}; - } - })); -} - -Error EHFrameRegistrationPlugin::notifyEmitted( - MaterializationResponsibility &MR) { - - ExecutorAddrRange EmittedRange; - { - std::lock_guard<std::mutex> Lock(EHFramePluginMutex); - - auto EHFrameRangeItr = InProcessLinks.find(&MR); - if (EHFrameRangeItr == InProcessLinks.end()) - return Error::success(); - - EmittedRange = EHFrameRangeItr->second; - assert(EmittedRange.Start && "eh-frame addr to register can not be null"); - InProcessLinks.erase(EHFrameRangeItr); - } - - if (auto Err = MR.withResourceKeyDo( - [&](ResourceKey K) { EHFrameRanges[K].push_back(EmittedRange); })) - return Err; - - return Registrar->registerEHFrames(EmittedRange); -} - -Error EHFrameRegistrationPlugin::notifyFailed( - MaterializationResponsibility &MR) { - std::lock_guard<std::mutex> Lock(EHFramePluginMutex); - InProcessLinks.erase(&MR); - return Error::success(); -} - -Error EHFrameRegistrationPlugin::notifyRemovingResources(JITDylib &JD, - ResourceKey K) { - std::vector<ExecutorAddrRange> RangesToRemove; - - ES.runSessionLocked([&] { - auto I = EHFrameRanges.find(K); - if (I != EHFrameRanges.end()) { - RangesToRemove = std::move(I->second); - EHFrameRanges.erase(I); - } - }); - - Error Err = Error::success(); - while (!RangesToRemove.empty()) { - auto RangeToRemove = RangesToRemove.back(); - RangesToRemove.pop_back(); - assert(RangeToRemove.Start && "Untracked eh-frame range must not be null"); - Err = joinErrors(std::move(Err), - Registrar->deregisterEHFrames(RangeToRemove)); - } - - return Err; -} - -void EHFrameRegistrationPlugin::notifyTransferringResources( - JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) { - auto SI = EHFrameRanges.find(SrcKey); - if (SI == EHFrameRanges.end()) + R->getExecutionSession().reportError(G.takeError()); + R->failMaterialization(); return; - - auto DI = EHFrameRanges.find(DstKey); - if (DI != EHFrameRanges.end()) { - auto &SrcRanges = SI->second; - auto &DstRanges = DI->second; - DstRanges.reserve(DstRanges.size() + SrcRanges.size()); - for (auto &SrcRange : SrcRanges) - DstRanges.push_back(std::move(SrcRange)); - EHFrameRanges.erase(SI); - } else { - // We need to move SrcKey's ranges over without invalidating the SI - // iterator. - auto Tmp = std::move(SI->second); - EHFrameRanges.erase(SI); - EHFrameRanges[DstKey] = std::move(Tmp); } } -} // End namespace orc. -} // End namespace llvm. +} // namespace llvm::orc |