Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LinkGraphLinkingLayer.cpp
213799 views
//===------ LinkGraphLinkingLayer.cpp - Link LinkGraphs with JITLink ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/ExecutionEngine/Orc/LinkGraphLinkingLayer.h"9#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"10#include "llvm/ExecutionEngine/JITLink/aarch32.h"11#include "llvm/ExecutionEngine/Orc/DebugUtils.h"12#include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"13#include "llvm/Support/MemoryBuffer.h"1415#define DEBUG_TYPE "orc"1617using namespace llvm;18using namespace llvm::jitlink;19using namespace llvm::orc;2021namespace {2223ExecutorAddr getJITSymbolPtrForSymbol(Symbol &Sym, const Triple &TT) {24switch (TT.getArch()) {25case Triple::arm:26case Triple::armeb:27case Triple::thumb:28case Triple::thumbeb:29if (hasTargetFlags(Sym, aarch32::ThumbSymbol)) {30// Set LSB to indicate thumb target31assert(Sym.isCallable() && "Only callable symbols can have thumb flag");32assert((Sym.getAddress().getValue() & 0x01) == 0 && "LSB is clear");33return Sym.getAddress() + 0x01;34}35return Sym.getAddress();36default:37return Sym.getAddress();38}39}4041} // end anonymous namespace4243namespace llvm {44namespace orc {4546class LinkGraphLinkingLayer::JITLinkCtx final : public JITLinkContext {47public:48JITLinkCtx(LinkGraphLinkingLayer &Layer,49std::unique_ptr<MaterializationResponsibility> MR,50std::unique_ptr<MemoryBuffer> ObjBuffer)51: JITLinkContext(&MR->getTargetJITDylib()), Layer(Layer),52MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {53std::lock_guard<std::mutex> Lock(Layer.LayerMutex);54Plugins = Layer.Plugins;55}5657~JITLinkCtx() {58// If there is an object buffer return function then use it to59// return ownership of the buffer.60if (Layer.ReturnObjectBuffer && ObjBuffer)61Layer.ReturnObjectBuffer(std::move(ObjBuffer));62}6364JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }6566void notifyMaterializing(LinkGraph &G) {67for (auto &P : Plugins)68P->notifyMaterializing(*MR, G, *this,69ObjBuffer ? ObjBuffer->getMemBufferRef()70: MemoryBufferRef());71}7273void notifyFailed(Error Err) override {74for (auto &P : Plugins)75Err = joinErrors(std::move(Err), P->notifyFailed(*MR));76Layer.getExecutionSession().reportError(std::move(Err));77MR->failMaterialization();78}7980void lookup(const LookupMap &Symbols,81std::unique_ptr<JITLinkAsyncLookupContinuation> LC) override {8283JITDylibSearchOrder LinkOrder;84MR->getTargetJITDylib().withLinkOrderDo(85[&](const JITDylibSearchOrder &LO) { LinkOrder = LO; });8687auto &ES = Layer.getExecutionSession();8889SymbolLookupSet LookupSet;90for (auto &KV : Symbols) {91orc::SymbolLookupFlags LookupFlags;92switch (KV.second) {93case jitlink::SymbolLookupFlags::RequiredSymbol:94LookupFlags = orc::SymbolLookupFlags::RequiredSymbol;95break;96case jitlink::SymbolLookupFlags::WeaklyReferencedSymbol:97LookupFlags = orc::SymbolLookupFlags::WeaklyReferencedSymbol;98break;99}100LookupSet.add(KV.first, LookupFlags);101}102103// OnResolve -- De-intern the symbols and pass the result to the linker.104auto OnResolve = [LookupContinuation =105std::move(LC)](Expected<SymbolMap> Result) mutable {106if (!Result)107LookupContinuation->run(Result.takeError());108else {109AsyncLookupResult LR;110LR.insert_range(*Result);111LookupContinuation->run(std::move(LR));112}113};114115ES.lookup(LookupKind::Static, LinkOrder, std::move(LookupSet),116SymbolState::Resolved, std::move(OnResolve),117[this](const SymbolDependenceMap &Deps) {118// Translate LookupDeps map to SymbolSourceJD.119for (auto &[DepJD, Deps] : Deps)120for (auto &DepSym : Deps)121SymbolSourceJDs[NonOwningSymbolStringPtr(DepSym)] = DepJD;122});123}124125Error notifyResolved(LinkGraph &G) override {126127SymbolFlagsMap ExtraSymbolsToClaim;128bool AutoClaim = Layer.AutoClaimObjectSymbols;129130SymbolMap InternedResult;131for (auto *Sym : G.defined_symbols())132if (Sym->getScope() < Scope::SideEffectsOnly) {133auto Ptr = getJITSymbolPtrForSymbol(*Sym, G.getTargetTriple());134auto Flags = getJITSymbolFlagsForSymbol(*Sym);135InternedResult[Sym->getName()] = {Ptr, Flags};136if (AutoClaim && !MR->getSymbols().count(Sym->getName())) {137assert(!ExtraSymbolsToClaim.count(Sym->getName()) &&138"Duplicate symbol to claim?");139ExtraSymbolsToClaim[Sym->getName()] = Flags;140}141}142143for (auto *Sym : G.absolute_symbols())144if (Sym->getScope() < Scope::SideEffectsOnly) {145auto Ptr = getJITSymbolPtrForSymbol(*Sym, G.getTargetTriple());146auto Flags = getJITSymbolFlagsForSymbol(*Sym);147InternedResult[Sym->getName()] = {Ptr, Flags};148if (AutoClaim && !MR->getSymbols().count(Sym->getName())) {149assert(!ExtraSymbolsToClaim.count(Sym->getName()) &&150"Duplicate symbol to claim?");151ExtraSymbolsToClaim[Sym->getName()] = Flags;152}153}154155if (!ExtraSymbolsToClaim.empty())156if (auto Err = MR->defineMaterializing(ExtraSymbolsToClaim))157return Err;158159{160161// Check that InternedResult matches up with MR->getSymbols(), overriding162// flags if requested.163// This guards against faulty transformations / compilers / object caches.164165// First check that there aren't any missing symbols.166size_t NumMaterializationSideEffectsOnlySymbols = 0;167SymbolNameVector MissingSymbols;168for (auto &[Sym, Flags] : MR->getSymbols()) {169170auto I = InternedResult.find(Sym);171172// If this is a materialization-side-effects only symbol then bump173// the counter and remove in from the result, otherwise make sure that174// it's defined.175if (Flags.hasMaterializationSideEffectsOnly())176++NumMaterializationSideEffectsOnlySymbols;177else if (I == InternedResult.end())178MissingSymbols.push_back(Sym);179else if (Layer.OverrideObjectFlags)180I->second.setFlags(Flags);181}182183// If there were missing symbols then report the error.184if (!MissingSymbols.empty())185return make_error<MissingSymbolDefinitions>(186Layer.getExecutionSession().getSymbolStringPool(), G.getName(),187std::move(MissingSymbols));188189// If there are more definitions than expected, add them to the190// ExtraSymbols vector.191SymbolNameVector ExtraSymbols;192if (InternedResult.size() >193MR->getSymbols().size() - NumMaterializationSideEffectsOnlySymbols) {194for (auto &KV : InternedResult)195if (!MR->getSymbols().count(KV.first))196ExtraSymbols.push_back(KV.first);197}198199// If there were extra definitions then report the error.200if (!ExtraSymbols.empty())201return make_error<UnexpectedSymbolDefinitions>(202Layer.getExecutionSession().getSymbolStringPool(), G.getName(),203std::move(ExtraSymbols));204}205206if (auto Err = MR->notifyResolved(InternedResult))207return Err;208209return Error::success();210}211212void notifyFinalized(JITLinkMemoryManager::FinalizedAlloc A) override {213if (auto Err = notifyEmitted(std::move(A))) {214Layer.getExecutionSession().reportError(std::move(Err));215MR->failMaterialization();216return;217}218219if (auto Err = MR->notifyEmitted(SymbolDepGroups)) {220Layer.getExecutionSession().reportError(std::move(Err));221MR->failMaterialization();222}223}224225LinkGraphPassFunction getMarkLivePass(const Triple &TT) const override {226return [this](LinkGraph &G) { return markResponsibilitySymbolsLive(G); };227}228229Error modifyPassConfig(LinkGraph &LG, PassConfiguration &Config) override {230// Add passes to mark duplicate defs as should-discard, and to walk the231// link graph to build the symbol dependence graph.232Config.PrePrunePasses.push_back([this](LinkGraph &G) {233return claimOrExternalizeWeakAndCommonSymbols(G);234});235236for (auto &P : Plugins)237P->modifyPassConfig(*MR, LG, Config);238239Config.PreFixupPasses.push_back(240[this](LinkGraph &G) { return registerDependencies(G); });241242return Error::success();243}244245Error notifyEmitted(jitlink::JITLinkMemoryManager::FinalizedAlloc FA) {246Error Err = Error::success();247for (auto &P : Plugins)248Err = joinErrors(std::move(Err), P->notifyEmitted(*MR));249250if (Err) {251if (FA)252Err =253joinErrors(std::move(Err), Layer.MemMgr.deallocate(std::move(FA)));254return Err;255}256257if (FA)258return Layer.recordFinalizedAlloc(*MR, std::move(FA));259260return Error::success();261}262263private:264Error claimOrExternalizeWeakAndCommonSymbols(LinkGraph &G) {265SymbolFlagsMap NewSymbolsToClaim;266std::vector<std::pair<SymbolStringPtr, Symbol *>> NameToSym;267268auto ProcessSymbol = [&](Symbol *Sym) {269if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak &&270Sym->getScope() != Scope::Local) {271if (!MR->getSymbols().count(Sym->getName())) {272NewSymbolsToClaim[Sym->getName()] =273getJITSymbolFlagsForSymbol(*Sym) | JITSymbolFlags::Weak;274NameToSym.push_back(std::make_pair(Sym->getName(), Sym));275}276}277};278279for (auto *Sym : G.defined_symbols())280ProcessSymbol(Sym);281for (auto *Sym : G.absolute_symbols())282ProcessSymbol(Sym);283284// Attempt to claim all weak defs that we're not already responsible for.285// This may fail if the resource tracker has become defunct, but should286// always succeed otherwise.287if (auto Err = MR->defineMaterializing(std::move(NewSymbolsToClaim)))288return Err;289290// Walk the list of symbols that we just tried to claim. Symbols that we're291// responsible for are marked live. Symbols that we're not responsible for292// are turned into external references.293for (auto &KV : NameToSym) {294if (MR->getSymbols().count(KV.first))295KV.second->setLive(true);296else297G.makeExternal(*KV.second);298}299300return Error::success();301}302303Error markResponsibilitySymbolsLive(LinkGraph &G) const {304for (auto *Sym : G.defined_symbols())305if (Sym->hasName() && MR->getSymbols().count(Sym->getName()))306Sym->setLive(true);307return Error::success();308}309310Error registerDependencies(LinkGraph &G) {311312struct BlockInfo {313bool InWorklist = false;314DenseSet<Symbol *> Defs;315DenseSet<Symbol *> SymbolDeps;316DenseSet<Block *> AnonEdges, AnonBackEdges;317};318319DenseMap<Block *, BlockInfo> BlockInfos;320321// Reserve space so that BlockInfos doesn't need to resize. This is322// essential to avoid invalidating pointers to entries below.323{324size_t NumBlocks = 0;325for (auto &Sec : G.sections())326NumBlocks += Sec.blocks_size();327BlockInfos.reserve(NumBlocks);328}329330// Identify non-locally-scoped symbols defined by each block.331for (auto *Sym : G.defined_symbols()) {332if (Sym->getScope() != Scope::Local)333BlockInfos[&Sym->getBlock()].Defs.insert(Sym);334}335336// Identify the symbolic and anonymous-block dependencies for each block.337for (auto *B : G.blocks()) {338auto &BI = BlockInfos[B];339340for (auto &E : B->edges()) {341342// External symbols are trivially depended on.343if (E.getTarget().isExternal()) {344BI.SymbolDeps.insert(&E.getTarget());345continue;346}347348// Anonymous symbols aren't depended on at all (they're assumed to be349// already available).350if (E.getTarget().isAbsolute())351continue;352353// If we get here then we depend on a symbol defined by some other354// block.355auto &TgtBI = BlockInfos[&E.getTarget().getBlock()];356357// If that block has any definitions then use the first one as the358// "effective" dependence here (all symbols in TgtBI will become359// ready at the same time, and chosing a single symbol to represent360// the block keeps the SymbolDepGroup size small).361if (!TgtBI.Defs.empty()) {362BI.SymbolDeps.insert(*TgtBI.Defs.begin());363continue;364}365366// Otherwise we've got a dependence on an anonymous block. Record it367// here for back-propagating symbol dependencies below.368BI.AnonEdges.insert(&E.getTarget().getBlock());369TgtBI.AnonBackEdges.insert(B);370}371}372373// Prune anonymous blocks.374{375std::vector<Block *> BlocksToRemove;376for (auto &[B, BI] : BlockInfos) {377// Skip blocks with defs. We only care about anonyous blocks.378if (!BI.Defs.empty())379continue;380381BlocksToRemove.push_back(B);382383for (auto *FB : BI.AnonEdges)384BlockInfos[FB].AnonBackEdges.erase(B);385386for (auto *BB : BI.AnonBackEdges)387BlockInfos[BB].AnonEdges.erase(B);388389for (auto *FB : BI.AnonEdges) {390auto &FBI = BlockInfos[FB];391FBI.AnonBackEdges.insert_range(BI.AnonBackEdges);392}393394for (auto *BB : BI.AnonBackEdges) {395auto &BBI = BlockInfos[BB];396BBI.SymbolDeps.insert_range(BI.SymbolDeps);397BBI.AnonEdges.insert_range(BI.AnonEdges);398}399}400401for (auto *B : BlocksToRemove)402BlockInfos.erase(B);403}404405// Build the initial dependence propagation worklist.406std::deque<Block *> Worklist;407for (auto &[B, BI] : BlockInfos) {408if (!BI.SymbolDeps.empty() && !BI.AnonBackEdges.empty()) {409Worklist.push_back(B);410BI.InWorklist = true;411}412}413414// Propagate symbol deps through the graph.415while (!Worklist.empty()) {416auto *B = Worklist.front();417Worklist.pop_front();418419auto &BI = BlockInfos[B];420BI.InWorklist = false;421422for (auto *DB : BI.AnonBackEdges) {423auto &DBI = BlockInfos[DB];424for (auto *Sym : BI.SymbolDeps) {425if (DBI.SymbolDeps.insert(Sym).second && !DBI.InWorklist) {426Worklist.push_back(DB);427DBI.InWorklist = true;428}429}430}431}432433// Transform our local dependence information into a list of434// SymbolDependenceGroups (in the SymbolDepGroups member), ready for use in435// the upcoming notifyFinalized call.436auto &TargetJD = MR->getTargetJITDylib();437438for (auto &[B, BI] : BlockInfos) {439if (!BI.Defs.empty()) {440SymbolDepGroups.push_back(SymbolDependenceGroup());441auto &SDG = SymbolDepGroups.back();442443for (auto *Def : BI.Defs)444SDG.Symbols.insert(Def->getName());445446for (auto *Dep : BI.SymbolDeps) {447auto DepName = Dep->getName();448if (Dep->isDefined())449SDG.Dependencies[&TargetJD].insert(std::move(DepName));450else {451auto SourceJDItr =452SymbolSourceJDs.find(NonOwningSymbolStringPtr(DepName));453if (SourceJDItr != SymbolSourceJDs.end())454SDG.Dependencies[SourceJDItr->second].insert(std::move(DepName));455}456}457}458}459460return Error::success();461}462463LinkGraphLinkingLayer &Layer;464std::vector<std::shared_ptr<LinkGraphLinkingLayer::Plugin>> Plugins;465std::unique_ptr<MaterializationResponsibility> MR;466std::unique_ptr<MemoryBuffer> ObjBuffer;467DenseMap<NonOwningSymbolStringPtr, JITDylib *> SymbolSourceJDs;468std::vector<SymbolDependenceGroup> SymbolDepGroups;469};470471LinkGraphLinkingLayer::Plugin::~Plugin() = default;472473LinkGraphLinkingLayer::LinkGraphLinkingLayer(ExecutionSession &ES)474: LinkGraphLayer(ES), MemMgr(ES.getExecutorProcessControl().getMemMgr()) {475ES.registerResourceManager(*this);476}477478LinkGraphLinkingLayer::LinkGraphLinkingLayer(ExecutionSession &ES,479JITLinkMemoryManager &MemMgr)480: LinkGraphLayer(ES), MemMgr(MemMgr) {481ES.registerResourceManager(*this);482}483484LinkGraphLinkingLayer::LinkGraphLinkingLayer(485ExecutionSession &ES, std::unique_ptr<JITLinkMemoryManager> MemMgr)486: LinkGraphLayer(ES), MemMgr(*MemMgr), MemMgrOwnership(std::move(MemMgr)) {487ES.registerResourceManager(*this);488}489490LinkGraphLinkingLayer::~LinkGraphLinkingLayer() {491assert(Allocs.empty() &&492"Layer destroyed with resources still attached "493"(ExecutionSession::endSession() must be called prior to "494"destruction)");495getExecutionSession().deregisterResourceManager(*this);496}497498void LinkGraphLinkingLayer::emit(499std::unique_ptr<MaterializationResponsibility> R,500std::unique_ptr<LinkGraph> G) {501assert(R && "R must not be null");502assert(G && "G must not be null");503auto Ctx = std::make_unique<JITLinkCtx>(*this, std::move(R), nullptr);504Ctx->notifyMaterializing(*G);505link(std::move(G), std::move(Ctx));506}507508void LinkGraphLinkingLayer::emit(509std::unique_ptr<MaterializationResponsibility> R,510std::unique_ptr<LinkGraph> G, std::unique_ptr<MemoryBuffer> ObjBuf) {511assert(R && "R must not be null");512assert(G && "G must not be null");513assert(ObjBuf && "Object must not be null");514auto Ctx =515std::make_unique<JITLinkCtx>(*this, std::move(R), std::move(ObjBuf));516Ctx->notifyMaterializing(*G);517link(std::move(G), std::move(Ctx));518}519520Error LinkGraphLinkingLayer::recordFinalizedAlloc(521MaterializationResponsibility &MR, FinalizedAlloc FA) {522auto Err = MR.withResourceKeyDo(523[&](ResourceKey K) { Allocs[K].push_back(std::move(FA)); });524525if (Err)526Err = joinErrors(std::move(Err), MemMgr.deallocate(std::move(FA)));527528return Err;529}530531Error LinkGraphLinkingLayer::handleRemoveResources(JITDylib &JD,532ResourceKey K) {533534{535Error Err = Error::success();536for (auto &P : Plugins)537Err = joinErrors(std::move(Err), P->notifyRemovingResources(JD, K));538if (Err)539return Err;540}541542std::vector<FinalizedAlloc> AllocsToRemove;543getExecutionSession().runSessionLocked([&] {544auto I = Allocs.find(K);545if (I != Allocs.end()) {546std::swap(AllocsToRemove, I->second);547Allocs.erase(I);548}549});550551if (AllocsToRemove.empty())552return Error::success();553554return MemMgr.deallocate(std::move(AllocsToRemove));555}556557void LinkGraphLinkingLayer::handleTransferResources(JITDylib &JD,558ResourceKey DstKey,559ResourceKey SrcKey) {560if (Allocs.contains(SrcKey)) {561// DstKey may not be in the DenseMap yet, so the following line may resize562// the container and invalidate iterators and value references.563auto &DstAllocs = Allocs[DstKey];564auto &SrcAllocs = Allocs[SrcKey];565DstAllocs.reserve(DstAllocs.size() + SrcAllocs.size());566for (auto &Alloc : SrcAllocs)567DstAllocs.push_back(std::move(Alloc));568569Allocs.erase(SrcKey);570}571572for (auto &P : Plugins)573P->notifyTransferringResources(JD, DstKey, SrcKey);574}575576} // End namespace orc.577} // End namespace llvm.578579580