
Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
572 lines
18 KiB
C++
572 lines
18 KiB
C++
//===------- ObjectLinkingLayer.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/ObjectLinkingLayer.h"
|
|
|
|
#include "llvm/ADT/Optional.h"
|
|
#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
|
|
|
|
#include <vector>
|
|
|
|
#define DEBUG_TYPE "orc"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::jitlink;
|
|
using namespace llvm::orc;
|
|
|
|
namespace llvm {
|
|
namespace orc {
|
|
|
|
class ObjectLinkingLayerJITLinkContext final : public JITLinkContext {
|
|
public:
|
|
ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer &Layer,
|
|
MaterializationResponsibility MR,
|
|
std::unique_ptr<MemoryBuffer> ObjBuffer)
|
|
: Layer(Layer), MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {}
|
|
|
|
~ObjectLinkingLayerJITLinkContext() {
|
|
// If there is an object buffer return function then use it to
|
|
// return ownership of the buffer.
|
|
if (Layer.ReturnObjectBuffer)
|
|
Layer.ReturnObjectBuffer(std::move(ObjBuffer));
|
|
}
|
|
|
|
JITLinkMemoryManager &getMemoryManager() override { return *Layer.MemMgr; }
|
|
|
|
MemoryBufferRef getObjectBuffer() const override {
|
|
return ObjBuffer->getMemBufferRef();
|
|
}
|
|
|
|
void notifyFailed(Error Err) override {
|
|
Layer.getExecutionSession().reportError(std::move(Err));
|
|
MR.failMaterialization();
|
|
}
|
|
|
|
void lookup(const LookupMap &Symbols,
|
|
std::unique_ptr<JITLinkAsyncLookupContinuation> LC) override {
|
|
|
|
JITDylibSearchOrder SearchOrder;
|
|
MR.getTargetJITDylib().withSearchOrderDo(
|
|
[&](const JITDylibSearchOrder &O) { SearchOrder = O; });
|
|
|
|
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(ES.intern(KV.first), LookupFlags);
|
|
}
|
|
|
|
// OnResolve -- De-intern the symbols and pass the result to the linker.
|
|
auto OnResolve = [this, LookupContinuation = std::move(LC)](
|
|
Expected<SymbolMap> Result) mutable {
|
|
auto Main = Layer.getExecutionSession().intern("_main");
|
|
if (!Result)
|
|
LookupContinuation->run(Result.takeError());
|
|
else {
|
|
AsyncLookupResult LR;
|
|
for (auto &KV : *Result)
|
|
LR[*KV.first] = KV.second;
|
|
LookupContinuation->run(std::move(LR));
|
|
}
|
|
};
|
|
|
|
for (auto &KV : InternalNamedSymbolDeps) {
|
|
SymbolDependenceMap InternalDeps;
|
|
InternalDeps[&MR.getTargetJITDylib()] = std::move(KV.second);
|
|
MR.addDependencies(KV.first, InternalDeps);
|
|
}
|
|
|
|
ES.lookup(LookupKind::Static, SearchOrder, std::move(LookupSet),
|
|
SymbolState::Resolved, std::move(OnResolve),
|
|
[this](const SymbolDependenceMap &Deps) {
|
|
registerDependencies(Deps);
|
|
});
|
|
}
|
|
|
|
void notifyResolved(LinkGraph &G) override {
|
|
auto &ES = Layer.getExecutionSession();
|
|
|
|
SymbolFlagsMap ExtraSymbolsToClaim;
|
|
bool AutoClaim = Layer.AutoClaimObjectSymbols;
|
|
|
|
SymbolMap InternedResult;
|
|
for (auto *Sym : G.defined_symbols())
|
|
if (Sym->hasName() && Sym->getScope() != Scope::Local) {
|
|
auto InternedName = ES.intern(Sym->getName());
|
|
JITSymbolFlags Flags;
|
|
|
|
if (Sym->isCallable())
|
|
Flags |= JITSymbolFlags::Callable;
|
|
if (Sym->getScope() == Scope::Default)
|
|
Flags |= JITSymbolFlags::Exported;
|
|
|
|
InternedResult[InternedName] =
|
|
JITEvaluatedSymbol(Sym->getAddress(), Flags);
|
|
if (AutoClaim && !MR.getSymbols().count(InternedName)) {
|
|
assert(!ExtraSymbolsToClaim.count(InternedName) &&
|
|
"Duplicate symbol to claim?");
|
|
ExtraSymbolsToClaim[InternedName] = Flags;
|
|
}
|
|
}
|
|
|
|
for (auto *Sym : G.absolute_symbols())
|
|
if (Sym->hasName()) {
|
|
auto InternedName = ES.intern(Sym->getName());
|
|
JITSymbolFlags Flags;
|
|
Flags |= JITSymbolFlags::Absolute;
|
|
if (Sym->isCallable())
|
|
Flags |= JITSymbolFlags::Callable;
|
|
if (Sym->getLinkage() == Linkage::Weak)
|
|
Flags |= JITSymbolFlags::Weak;
|
|
InternedResult[InternedName] =
|
|
JITEvaluatedSymbol(Sym->getAddress(), Flags);
|
|
if (AutoClaim && !MR.getSymbols().count(InternedName)) {
|
|
assert(!ExtraSymbolsToClaim.count(InternedName) &&
|
|
"Duplicate symbol to claim?");
|
|
ExtraSymbolsToClaim[InternedName] = Flags;
|
|
}
|
|
}
|
|
|
|
if (!ExtraSymbolsToClaim.empty())
|
|
if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim))
|
|
return notifyFailed(std::move(Err));
|
|
|
|
if (const auto &InitSym = MR.getInitializerSymbol())
|
|
InternedResult[InitSym] = JITEvaluatedSymbol();
|
|
|
|
if (auto Err = MR.notifyResolved(InternedResult)) {
|
|
Layer.getExecutionSession().reportError(std::move(Err));
|
|
MR.failMaterialization();
|
|
return;
|
|
}
|
|
Layer.notifyLoaded(MR);
|
|
}
|
|
|
|
void notifyFinalized(
|
|
std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
|
|
if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
|
|
Layer.getExecutionSession().reportError(std::move(Err));
|
|
MR.failMaterialization();
|
|
return;
|
|
}
|
|
if (auto Err = MR.notifyEmitted()) {
|
|
Layer.getExecutionSession().reportError(std::move(Err));
|
|
MR.failMaterialization();
|
|
}
|
|
}
|
|
|
|
LinkGraphPassFunction getMarkLivePass(const Triple &TT) const override {
|
|
return [this](LinkGraph &G) { return markResponsibilitySymbolsLive(G); };
|
|
}
|
|
|
|
Error modifyPassConfig(const Triple &TT, 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 externalizeWeakAndCommonSymbols(G); });
|
|
|
|
Layer.modifyPassConfig(MR, TT, Config);
|
|
|
|
Config.PostPrunePasses.push_back(
|
|
[this](LinkGraph &G) { return computeNamedSymbolDependencies(G); });
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
private:
|
|
struct LocalSymbolNamedDependencies {
|
|
SymbolNameSet Internal, External;
|
|
};
|
|
|
|
using LocalSymbolNamedDependenciesMap =
|
|
DenseMap<const Symbol *, LocalSymbolNamedDependencies>;
|
|
|
|
Error externalizeWeakAndCommonSymbols(LinkGraph &G) {
|
|
auto &ES = Layer.getExecutionSession();
|
|
for (auto *Sym : G.defined_symbols())
|
|
if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak) {
|
|
if (!MR.getSymbols().count(ES.intern(Sym->getName())))
|
|
G.makeExternal(*Sym);
|
|
}
|
|
|
|
for (auto *Sym : G.absolute_symbols())
|
|
if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak) {
|
|
if (!MR.getSymbols().count(ES.intern(Sym->getName())))
|
|
G.makeExternal(*Sym);
|
|
}
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
Error markResponsibilitySymbolsLive(LinkGraph &G) const {
|
|
auto &ES = Layer.getExecutionSession();
|
|
for (auto *Sym : G.defined_symbols())
|
|
if (Sym->hasName() && MR.getSymbols().count(ES.intern(Sym->getName())))
|
|
Sym->setLive(true);
|
|
return Error::success();
|
|
}
|
|
|
|
Error computeNamedSymbolDependencies(LinkGraph &G) {
|
|
auto &ES = MR.getTargetJITDylib().getExecutionSession();
|
|
auto LocalDeps = computeLocalDeps(G);
|
|
|
|
// Compute dependencies for symbols defined in the JITLink graph.
|
|
for (auto *Sym : G.defined_symbols()) {
|
|
|
|
// Skip local symbols: we do not track dependencies for these.
|
|
if (Sym->getScope() == Scope::Local)
|
|
continue;
|
|
assert(Sym->hasName() &&
|
|
"Defined non-local jitlink::Symbol should have a name");
|
|
|
|
SymbolNameSet ExternalSymDeps, InternalSymDeps;
|
|
|
|
// Find internal and external named symbol dependencies.
|
|
for (auto &E : Sym->getBlock().edges()) {
|
|
auto &TargetSym = E.getTarget();
|
|
|
|
if (TargetSym.getScope() != Scope::Local) {
|
|
if (TargetSym.isExternal())
|
|
ExternalSymDeps.insert(ES.intern(TargetSym.getName()));
|
|
else if (&TargetSym != Sym)
|
|
InternalSymDeps.insert(ES.intern(TargetSym.getName()));
|
|
} else {
|
|
assert(TargetSym.isDefined() &&
|
|
"local symbols must be defined");
|
|
auto I = LocalDeps.find(&TargetSym);
|
|
if (I != LocalDeps.end()) {
|
|
for (auto &S : I->second.External)
|
|
ExternalSymDeps.insert(S);
|
|
for (auto &S : I->second.Internal)
|
|
InternalSymDeps.insert(S);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ExternalSymDeps.empty() && InternalSymDeps.empty())
|
|
continue;
|
|
|
|
auto SymName = ES.intern(Sym->getName());
|
|
if (!ExternalSymDeps.empty())
|
|
ExternalNamedSymbolDeps[SymName] = std::move(ExternalSymDeps);
|
|
if (!InternalSymDeps.empty())
|
|
InternalNamedSymbolDeps[SymName] = std::move(InternalSymDeps);
|
|
}
|
|
|
|
for (auto &P : Layer.Plugins) {
|
|
auto SyntheticLocalDeps = P->getSyntheticSymbolLocalDependencies(MR);
|
|
if (SyntheticLocalDeps.empty())
|
|
continue;
|
|
|
|
for (auto &KV : SyntheticLocalDeps) {
|
|
auto &Name = KV.first;
|
|
auto &LocalDepsForName = KV.second;
|
|
for (auto *Local : LocalDepsForName) {
|
|
assert(Local->getScope() == Scope::Local &&
|
|
"Dependence on non-local symbol");
|
|
auto LocalNamedDepsItr = LocalDeps.find(Local);
|
|
if (LocalNamedDepsItr == LocalDeps.end())
|
|
continue;
|
|
for (auto &S : LocalNamedDepsItr->second.Internal)
|
|
InternalNamedSymbolDeps[Name].insert(S);
|
|
for (auto &S : LocalNamedDepsItr->second.External)
|
|
ExternalNamedSymbolDeps[Name].insert(S);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
LocalSymbolNamedDependenciesMap computeLocalDeps(LinkGraph &G) {
|
|
DenseMap<jitlink::Symbol *, DenseSet<jitlink::Symbol *>> DepMap;
|
|
|
|
// For all local symbols:
|
|
// (1) Add their named dependencies.
|
|
// (2) Add them to the worklist for further iteration if they have any
|
|
// depend on any other local symbols.
|
|
struct WorklistEntry {
|
|
WorklistEntry(Symbol *Sym, DenseSet<Symbol *> LocalDeps)
|
|
: Sym(Sym), LocalDeps(std::move(LocalDeps)) {}
|
|
|
|
Symbol *Sym = nullptr;
|
|
DenseSet<Symbol *> LocalDeps;
|
|
};
|
|
std::vector<WorklistEntry> Worklist;
|
|
for (auto *Sym : G.defined_symbols())
|
|
if (Sym->getScope() == Scope::Local) {
|
|
auto &SymNamedDeps = DepMap[Sym];
|
|
DenseSet<Symbol *> LocalDeps;
|
|
|
|
for (auto &E : Sym->getBlock().edges()) {
|
|
auto &TargetSym = E.getTarget();
|
|
if (TargetSym.getScope() != Scope::Local)
|
|
SymNamedDeps.insert(&TargetSym);
|
|
else {
|
|
assert(TargetSym.isDefined() &&
|
|
"local symbols must be defined");
|
|
LocalDeps.insert(&TargetSym);
|
|
}
|
|
}
|
|
|
|
if (!LocalDeps.empty())
|
|
Worklist.push_back(WorklistEntry(Sym, std::move(LocalDeps)));
|
|
}
|
|
|
|
// Loop over all local symbols with local dependencies, propagating
|
|
// their respective non-local dependencies. Iterate until we hit a stable
|
|
// state.
|
|
bool Changed;
|
|
do {
|
|
Changed = false;
|
|
for (auto &WLEntry : Worklist) {
|
|
auto *Sym = WLEntry.Sym;
|
|
auto &NamedDeps = DepMap[Sym];
|
|
auto &LocalDeps = WLEntry.LocalDeps;
|
|
|
|
for (auto *TargetSym : LocalDeps) {
|
|
auto I = DepMap.find(TargetSym);
|
|
if (I != DepMap.end())
|
|
for (const auto &S : I->second)
|
|
Changed |= NamedDeps.insert(S).second;
|
|
}
|
|
}
|
|
} while (Changed);
|
|
|
|
// Intern the results to produce a mapping of jitlink::Symbol* to internal
|
|
// and external symbol names.
|
|
auto &ES = Layer.getExecutionSession();
|
|
LocalSymbolNamedDependenciesMap Result;
|
|
for (auto &KV : DepMap) {
|
|
auto *Local = KV.first;
|
|
assert(Local->getScope() == Scope::Local &&
|
|
"DepMap keys should all be local symbols");
|
|
auto &LocalNamedDeps = Result[Local];
|
|
for (auto *Named : KV.second) {
|
|
assert(Named->getScope() != Scope::Local &&
|
|
"DepMap values should all be non-local symbol sets");
|
|
if (Named->isExternal())
|
|
LocalNamedDeps.External.insert(ES.intern(Named->getName()));
|
|
else
|
|
LocalNamedDeps.Internal.insert(ES.intern(Named->getName()));
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
void registerDependencies(const SymbolDependenceMap &QueryDeps) {
|
|
for (auto &NamedDepsEntry : ExternalNamedSymbolDeps) {
|
|
auto &Name = NamedDepsEntry.first;
|
|
auto &NameDeps = NamedDepsEntry.second;
|
|
SymbolDependenceMap SymbolDeps;
|
|
|
|
for (const auto &QueryDepsEntry : QueryDeps) {
|
|
JITDylib &SourceJD = *QueryDepsEntry.first;
|
|
const SymbolNameSet &Symbols = QueryDepsEntry.second;
|
|
auto &DepsForJD = SymbolDeps[&SourceJD];
|
|
|
|
for (const auto &S : Symbols)
|
|
if (NameDeps.count(S))
|
|
DepsForJD.insert(S);
|
|
|
|
if (DepsForJD.empty())
|
|
SymbolDeps.erase(&SourceJD);
|
|
}
|
|
|
|
MR.addDependencies(Name, SymbolDeps);
|
|
}
|
|
}
|
|
|
|
ObjectLinkingLayer &Layer;
|
|
MaterializationResponsibility MR;
|
|
std::unique_ptr<MemoryBuffer> ObjBuffer;
|
|
DenseMap<SymbolStringPtr, SymbolNameSet> ExternalNamedSymbolDeps;
|
|
DenseMap<SymbolStringPtr, SymbolNameSet> InternalNamedSymbolDeps;
|
|
};
|
|
|
|
ObjectLinkingLayer::Plugin::~Plugin() {}
|
|
|
|
ObjectLinkingLayer::ObjectLinkingLayer(
|
|
ExecutionSession &ES, std::unique_ptr<JITLinkMemoryManager> MemMgr)
|
|
: ObjectLayer(ES), MemMgr(std::move(MemMgr)) {}
|
|
|
|
ObjectLinkingLayer::~ObjectLinkingLayer() {
|
|
if (auto Err = removeAllModules())
|
|
getExecutionSession().reportError(std::move(Err));
|
|
}
|
|
|
|
void ObjectLinkingLayer::emit(MaterializationResponsibility R,
|
|
std::unique_ptr<MemoryBuffer> O) {
|
|
assert(O && "Object must not be null");
|
|
jitLink(std::make_unique<ObjectLinkingLayerJITLinkContext>(
|
|
*this, std::move(R), std::move(O)));
|
|
}
|
|
|
|
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<std::mutex> Lock(LayerMutex);
|
|
UntrackedAllocs.push_back(std::move(Alloc));
|
|
}
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
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<std::mutex> 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());
|
|
}
|
|
|
|
Error ObjectLinkingLayer::removeAllModules() {
|
|
|
|
Error Err = Error::success();
|
|
|
|
for (auto &P : Plugins)
|
|
Err = joinErrors(std::move(Err), P->notifyRemovingAllModules());
|
|
|
|
std::vector<AllocPtr> Allocs;
|
|
{
|
|
std::lock_guard<std::mutex> 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;
|
|
}
|
|
|
|
EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
|
|
EHFrameRegistrar &Registrar)
|
|
: Registrar(Registrar) {}
|
|
|
|
void EHFrameRegistrationPlugin::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,
|
|
size_t Size) {
|
|
if (Addr)
|
|
InProcessLinks[&MR] = { Addr, Size };
|
|
}));
|
|
}
|
|
|
|
Error EHFrameRegistrationPlugin::notifyEmitted(
|
|
MaterializationResponsibility &MR) {
|
|
|
|
auto EHFrameRangeItr = InProcessLinks.find(&MR);
|
|
if (EHFrameRangeItr == InProcessLinks.end())
|
|
return Error::success();
|
|
|
|
auto EHFrameRange = EHFrameRangeItr->second;
|
|
assert(EHFrameRange.Addr &&
|
|
"eh-frame addr to register can not be null");
|
|
|
|
InProcessLinks.erase(EHFrameRangeItr);
|
|
if (auto Key = MR.getVModuleKey())
|
|
TrackedEHFrameRanges[Key] = EHFrameRange;
|
|
else
|
|
UntrackedEHFrameRanges.push_back(EHFrameRange);
|
|
|
|
return Registrar.registerEHFrames(EHFrameRange.Addr, EHFrameRange.Size);
|
|
}
|
|
|
|
Error EHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) {
|
|
auto EHFrameRangeItr = TrackedEHFrameRanges.find(K);
|
|
if (EHFrameRangeItr == TrackedEHFrameRanges.end())
|
|
return Error::success();
|
|
|
|
auto EHFrameRange = EHFrameRangeItr->second;
|
|
assert(EHFrameRange.Addr && "Tracked eh-frame range must not be null");
|
|
|
|
TrackedEHFrameRanges.erase(EHFrameRangeItr);
|
|
|
|
return Registrar.deregisterEHFrames(EHFrameRange.Addr, EHFrameRange.Size);
|
|
}
|
|
|
|
Error EHFrameRegistrationPlugin::notifyRemovingAllModules() {
|
|
|
|
std::vector<EHFrameRange> EHFrameRanges =
|
|
std::move(UntrackedEHFrameRanges);
|
|
EHFrameRanges.reserve(EHFrameRanges.size() + TrackedEHFrameRanges.size());
|
|
|
|
for (auto &KV : TrackedEHFrameRanges)
|
|
EHFrameRanges.push_back(KV.second);
|
|
|
|
TrackedEHFrameRanges.clear();
|
|
|
|
Error Err = Error::success();
|
|
|
|
while (!EHFrameRanges.empty()) {
|
|
auto EHFrameRange = EHFrameRanges.back();
|
|
assert(EHFrameRange.Addr && "Untracked eh-frame range must not be null");
|
|
EHFrameRanges.pop_back();
|
|
Err = joinErrors(std::move(Err),
|
|
Registrar.deregisterEHFrames(EHFrameRange.Addr,
|
|
EHFrameRange.Size));
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
} // End namespace orc.
|
|
} // End namespace llvm.
|