Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp
35271 views
//===--------- JITLinkGeneric.cpp - Generic JIT linker utilities ----------===//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//===----------------------------------------------------------------------===//7//8// Generic JITLinker utility class.9//10//===----------------------------------------------------------------------===//1112#include "JITLinkGeneric.h"1314#include "llvm/Support/BinaryStreamReader.h"15#include "llvm/Support/MemoryBuffer.h"1617#define DEBUG_TYPE "jitlink"1819namespace llvm {20namespace jitlink {2122JITLinkerBase::~JITLinkerBase() = default;2324void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) {2526LLVM_DEBUG({27dbgs() << "Starting link phase 1 for graph " << G->getName() << "\n";28});2930// Prune and optimize the graph.31if (auto Err = runPasses(Passes.PrePrunePasses))32return Ctx->notifyFailed(std::move(Err));3334LLVM_DEBUG({35dbgs() << "Link graph \"" << G->getName() << "\" pre-pruning:\n";36G->dump(dbgs());37});3839prune(*G);4041LLVM_DEBUG({42dbgs() << "Link graph \"" << G->getName() << "\" post-pruning:\n";43G->dump(dbgs());44});4546// Run post-pruning passes.47if (auto Err = runPasses(Passes.PostPrunePasses))48return Ctx->notifyFailed(std::move(Err));4950// Skip straight to phase 2 if the graph is empty with no associated actions.51if (G->allocActions().empty() && llvm::all_of(G->sections(), [](Section &S) {52return S.getMemLifetime() == orc::MemLifetime::NoAlloc;53})) {54linkPhase2(std::move(Self), nullptr);55return;56}5758Ctx->getMemoryManager().allocate(59Ctx->getJITLinkDylib(), *G,60[S = std::move(Self)](AllocResult AR) mutable {61// FIXME: Once MSVC implements c++17 order of evaluation rules for calls62// this can be simplified to63// S->linkPhase2(std::move(S), std::move(AR));64auto *TmpSelf = S.get();65TmpSelf->linkPhase2(std::move(S), std::move(AR));66});67}6869void JITLinkerBase::linkPhase2(std::unique_ptr<JITLinkerBase> Self,70AllocResult AR) {7172if (AR)73Alloc = std::move(*AR);74else75return Ctx->notifyFailed(AR.takeError());7677LLVM_DEBUG({78dbgs() << "Link graph \"" << G->getName()79<< "\" before post-allocation passes:\n";80G->dump(dbgs());81});8283// Run post-allocation passes.84if (auto Err = runPasses(Passes.PostAllocationPasses))85return abandonAllocAndBailOut(std::move(Self), std::move(Err));8687// Notify client that the defined symbols have been assigned addresses.88LLVM_DEBUG(dbgs() << "Resolving symbols defined in " << G->getName() << "\n");8990if (auto Err = Ctx->notifyResolved(*G))91return abandonAllocAndBailOut(std::move(Self), std::move(Err));9293auto ExternalSymbols = getExternalSymbolNames();9495// If there are no external symbols then proceed immediately with phase 3.96if (ExternalSymbols.empty()) {97LLVM_DEBUG({98dbgs() << "No external symbols for " << G->getName()99<< ". Proceeding immediately with link phase 3.\n";100});101// FIXME: Once MSVC implements c++17 order of evaluation rules for calls102// this can be simplified. See below.103auto &TmpSelf = *Self;104TmpSelf.linkPhase3(std::move(Self), AsyncLookupResult());105return;106}107108// Otherwise look up the externals.109LLVM_DEBUG({110dbgs() << "Issuing lookup for external symbols for " << G->getName()111<< " (may trigger materialization/linking of other graphs)...\n";112});113114// We're about to hand off ownership of ourself to the continuation. Grab a115// pointer to the context so that we can call it to initiate the lookup.116//117// FIXME: Once MSVC implements c++17 order of evaluation rules for calls this118// can be simplified to:119//120// Ctx->lookup(std::move(UnresolvedExternals),121// [Self=std::move(Self)](Expected<AsyncLookupResult> Result) {122// Self->linkPhase3(std::move(Self), std::move(Result));123// });124Ctx->lookup(std::move(ExternalSymbols),125createLookupContinuation(126[S = std::move(Self)](127Expected<AsyncLookupResult> LookupResult) mutable {128auto &TmpSelf = *S;129TmpSelf.linkPhase3(std::move(S), std::move(LookupResult));130}));131}132133void JITLinkerBase::linkPhase3(std::unique_ptr<JITLinkerBase> Self,134Expected<AsyncLookupResult> LR) {135136LLVM_DEBUG({137dbgs() << "Starting link phase 3 for graph " << G->getName() << "\n";138});139140// If the lookup failed, bail out.141if (!LR)142return abandonAllocAndBailOut(std::move(Self), LR.takeError());143144// Assign addresses to external addressables.145applyLookupResult(*LR);146147LLVM_DEBUG({148dbgs() << "Link graph \"" << G->getName()149<< "\" before pre-fixup passes:\n";150G->dump(dbgs());151});152153if (auto Err = runPasses(Passes.PreFixupPasses))154return abandonAllocAndBailOut(std::move(Self), std::move(Err));155156LLVM_DEBUG({157dbgs() << "Link graph \"" << G->getName() << "\" before copy-and-fixup:\n";158G->dump(dbgs());159});160161// Fix up block content.162if (auto Err = fixUpBlocks(*G))163return abandonAllocAndBailOut(std::move(Self), std::move(Err));164165LLVM_DEBUG({166dbgs() << "Link graph \"" << G->getName() << "\" after copy-and-fixup:\n";167G->dump(dbgs());168});169170if (auto Err = runPasses(Passes.PostFixupPasses))171return abandonAllocAndBailOut(std::move(Self), std::move(Err));172173// Skip straight to phase 4 if the graph has no allocation.174if (!Alloc) {175linkPhase4(std::move(Self), JITLinkMemoryManager::FinalizedAlloc{});176return;177}178179Alloc->finalize([S = std::move(Self)](FinalizeResult FR) mutable {180// FIXME: Once MSVC implements c++17 order of evaluation rules for calls181// this can be simplified to182// S->linkPhase2(std::move(S), std::move(AR));183auto *TmpSelf = S.get();184TmpSelf->linkPhase4(std::move(S), std::move(FR));185});186}187188void JITLinkerBase::linkPhase4(std::unique_ptr<JITLinkerBase> Self,189FinalizeResult FR) {190191LLVM_DEBUG({192dbgs() << "Starting link phase 4 for graph " << G->getName() << "\n";193});194195if (!FR)196return Ctx->notifyFailed(FR.takeError());197198Ctx->notifyFinalized(std::move(*FR));199200LLVM_DEBUG({ dbgs() << "Link of graph " << G->getName() << " complete\n"; });201}202203Error JITLinkerBase::runPasses(LinkGraphPassList &Passes) {204for (auto &P : Passes)205if (auto Err = P(*G))206return Err;207return Error::success();208}209210JITLinkContext::LookupMap JITLinkerBase::getExternalSymbolNames() const {211// Identify unresolved external symbols.212JITLinkContext::LookupMap UnresolvedExternals;213for (auto *Sym : G->external_symbols()) {214assert(!Sym->getAddress() &&215"External has already been assigned an address");216assert(Sym->getName() != StringRef() && Sym->getName() != "" &&217"Externals must be named");218SymbolLookupFlags LookupFlags =219Sym->isWeaklyReferenced() ? SymbolLookupFlags::WeaklyReferencedSymbol220: SymbolLookupFlags::RequiredSymbol;221UnresolvedExternals[Sym->getName()] = LookupFlags;222}223return UnresolvedExternals;224}225226void JITLinkerBase::applyLookupResult(AsyncLookupResult Result) {227for (auto *Sym : G->external_symbols()) {228assert(Sym->getOffset() == 0 &&229"External symbol is not at the start of its addressable block");230assert(!Sym->getAddress() && "Symbol already resolved");231assert(!Sym->isDefined() && "Symbol being resolved is already defined");232auto ResultI = Result.find(Sym->getName());233if (ResultI != Result.end()) {234Sym->getAddressable().setAddress(ResultI->second.getAddress());235Sym->setLinkage(ResultI->second.getFlags().isWeak() ? Linkage::Weak236: Linkage::Strong);237Sym->setScope(ResultI->second.getFlags().isExported() ? Scope::Default238: Scope::Hidden);239} else240assert(Sym->isWeaklyReferenced() &&241"Failed to resolve non-weak reference");242}243244LLVM_DEBUG({245dbgs() << "Externals after applying lookup result:\n";246for (auto *Sym : G->external_symbols()) {247dbgs() << " " << Sym->getName() << ": "248<< formatv("{0:x16}", Sym->getAddress().getValue());249switch (Sym->getLinkage()) {250case Linkage::Strong:251break;252case Linkage::Weak:253dbgs() << " (weak)";254break;255}256switch (Sym->getScope()) {257case Scope::Local:258llvm_unreachable("External symbol should not have local linkage");259case Scope::Hidden:260break;261case Scope::Default:262dbgs() << " (exported)";263break;264}265dbgs() << "\n";266}267});268}269270void JITLinkerBase::abandonAllocAndBailOut(std::unique_ptr<JITLinkerBase> Self,271Error Err) {272assert(Err && "Should not be bailing out on success value");273assert(Alloc && "can not call abandonAllocAndBailOut before allocation");274Alloc->abandon([S = std::move(Self), E1 = std::move(Err)](Error E2) mutable {275S->Ctx->notifyFailed(joinErrors(std::move(E1), std::move(E2)));276});277}278279void prune(LinkGraph &G) {280std::vector<Symbol *> Worklist;281DenseSet<Block *> VisitedBlocks;282283// Build the initial worklist from all symbols initially live.284for (auto *Sym : G.defined_symbols())285if (Sym->isLive())286Worklist.push_back(Sym);287288// Propagate live flags to all symbols reachable from the initial live set.289while (!Worklist.empty()) {290auto *Sym = Worklist.back();291Worklist.pop_back();292293auto &B = Sym->getBlock();294295// Skip addressables that we've visited before.296if (VisitedBlocks.count(&B))297continue;298299VisitedBlocks.insert(&B);300301for (auto &E : Sym->getBlock().edges()) {302// If the edge target is a defined symbol that is being newly marked live303// then add it to the worklist.304if (E.getTarget().isDefined() && !E.getTarget().isLive())305Worklist.push_back(&E.getTarget());306307// Mark the target live.308E.getTarget().setLive(true);309}310}311312// Collect all defined symbols to remove, then remove them.313{314LLVM_DEBUG(dbgs() << "Dead-stripping defined symbols:\n");315std::vector<Symbol *> SymbolsToRemove;316for (auto *Sym : G.defined_symbols())317if (!Sym->isLive())318SymbolsToRemove.push_back(Sym);319for (auto *Sym : SymbolsToRemove) {320LLVM_DEBUG(dbgs() << " " << *Sym << "...\n");321G.removeDefinedSymbol(*Sym);322}323}324325// Delete any unused blocks.326{327LLVM_DEBUG(dbgs() << "Dead-stripping blocks:\n");328std::vector<Block *> BlocksToRemove;329for (auto *B : G.blocks())330if (!VisitedBlocks.count(B))331BlocksToRemove.push_back(B);332for (auto *B : BlocksToRemove) {333LLVM_DEBUG(dbgs() << " " << *B << "...\n");334G.removeBlock(*B);335}336}337338// Collect all external symbols to remove, then remove them.339{340LLVM_DEBUG(dbgs() << "Removing unused external symbols:\n");341std::vector<Symbol *> SymbolsToRemove;342for (auto *Sym : G.external_symbols())343if (!Sym->isLive())344SymbolsToRemove.push_back(Sym);345for (auto *Sym : SymbolsToRemove) {346LLVM_DEBUG(dbgs() << " " << *Sym << "...\n");347G.removeExternalSymbol(*Sym);348}349}350}351352} // end namespace jitlink353} // end namespace llvm354355356