llvm-project/llvm/lib/ExecutionEngine/Orc/LazyObjectLinkingLayer.cpp
Lang Hames 224290d448
[ORC] Add LazyObjectLinkingLayer, lazy-linking support to llvm-jitlink (#116002)
LazyObjectLinkingLayer can be used to add object files that will not be linked
into the executor unless some function that they define is called at runtime.
(References to data members defined by these objects will still trigger
immediate linking)

To implement lazy linking, LazyObjectLinkingLayer uses the lazyReexports
utility to construct stubs for each function in a given object file, and an
ObjectLinkingLayer::Plugin to rename the function bodies at link-time. (Data
symbols are not renamed)

The llvm-jitlink utility is extended with a -lazy option that can be
passed before input files or archives to add them using the lazy linking
layer rather than the base ObjectLinkingLayer.
2024-11-18 11:17:36 +11:00

115 lines
3.8 KiB
C++

//===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===//
//
// 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/LazyObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/RedirectionManager.h"
using namespace llvm;
using namespace llvm::jitlink;
namespace {
constexpr StringRef FnBodySuffix = "$orc_fnbody";
} // anonymous namespace
namespace llvm::orc {
class LazyObjectLinkingLayer::RenamerPlugin
: public ObjectLinkingLayer::Plugin {
public:
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &LG,
jitlink::PassConfiguration &Config) override {
// We need to insert this before the mark-live pass to ensure that we don't
// delete the bodies (their names won't match the responsibility set until
// after this pass completes.
Config.PrePrunePasses.insert(
Config.PrePrunePasses.begin(),
[&MR](LinkGraph &G) { return renameFunctionBodies(G, MR); });
}
Error notifyFailed(MaterializationResponsibility &MR) override {
return Error::success();
}
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
return Error::success();
}
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
ResourceKey SrcKey) override {}
private:
static Error renameFunctionBodies(LinkGraph &G,
MaterializationResponsibility &MR) {
DenseMap<StringRef, NonOwningSymbolStringPtr> SymsToRename;
for (auto &[Name, Flags] : MR.getSymbols())
if ((*Name).ends_with(FnBodySuffix))
SymsToRename[(*Name).drop_back(FnBodySuffix.size())] =
NonOwningSymbolStringPtr(Name);
for (auto *Sym : G.defined_symbols()) {
if (!Sym->hasName())
continue;
auto I = SymsToRename.find(Sym->getName());
if (I == SymsToRename.end())
continue;
Sym->setName(G.allocateName(*I->second));
}
return Error::success();
}
};
LazyObjectLinkingLayer::LazyObjectLinkingLayer(ObjectLinkingLayer &BaseLayer,
LazyCallThroughManager &LCTMgr,
RedirectableSymbolManager &RSMgr)
: ObjectLayer(BaseLayer.getExecutionSession()), BaseLayer(BaseLayer),
LCTMgr(LCTMgr), RSMgr(RSMgr) {
BaseLayer.addPlugin(std::make_unique<RenamerPlugin>());
}
Error LazyObjectLinkingLayer::add(ResourceTrackerSP RT,
std::unique_ptr<MemoryBuffer> O,
MaterializationUnit::Interface I) {
// Object files with initializer symbols can't be lazy.
if (I.InitSymbol)
return BaseLayer.add(std::move(RT), std::move(O), std::move(I));
auto &ES = getExecutionSession();
SymbolAliasMap LazySymbols;
for (auto &[Name, Flags] : I.SymbolFlags)
if (Flags.isCallable())
LazySymbols[Name] = {ES.intern((*Name + FnBodySuffix).str()), Flags};
for (auto &[Name, AI] : LazySymbols) {
I.SymbolFlags.erase(Name);
I.SymbolFlags[AI.Aliasee] = AI.AliasFlags;
}
if (auto Err = BaseLayer.add(RT, std::move(O), std::move(I)))
return Err;
auto &JD = RT->getJITDylib();
return JD.define(lazyReexports(LCTMgr, RSMgr, JD, std::move(LazySymbols)),
std::move(RT));
}
void LazyObjectLinkingLayer::emit(
std::unique_ptr<MaterializationResponsibility> MR,
std::unique_ptr<MemoryBuffer> Obj) {
return BaseLayer.emit(std::move(MR), std::move(Obj));
}
} // namespace llvm::orc