mirror of
https://github.com/RPCS3/llvm.git
synced 2026-07-19 23:23:38 -04:00
[ORC] Add a 'plugin' interface to ObjectLinkingLayer for events/configuration.
ObjectLinkingLayer::Plugin provides event notifications when objects are loaded, emitted, and removed. It also provides a modifyPassConfig callback that allows plugins to modify the JITLink pass configuration. This patch moves eh-frame registration into its own plugin, and teaches llvm-jitlink to only add that plugin when performing execution runs on non-Windows platforms. This should allow us to re-enable the test case that was removed in r359198. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@359357 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -27,14 +27,17 @@ Error registerEHFrameSection(const void *EHFrameSectionAddr);
|
||||
/// Deregisters all FDEs in the given eh-frame section with the current process.
|
||||
Error deregisterEHFrameSection(const void *EHFrameSectionAddr);
|
||||
|
||||
using StoreFrameAddressFunction = std::function<void(JITTargetAddress)>;
|
||||
|
||||
/// Creates a pass that records the address of the EH frame section. If no
|
||||
/// eh-frame section is found, it will set EHFrameAddr to zero.
|
||||
///
|
||||
/// Authors of JITLinkContexts can use this function to register a post-fixup
|
||||
/// pass that records the address of the eh-frame section. This address can
|
||||
/// be used after finalization to register and deregister the frame.
|
||||
AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
|
||||
JITTargetAddress &EHFrameAddr);
|
||||
AtomGraphPassFunction
|
||||
createEHFrameRecorderPass(const Triple &TT,
|
||||
StoreFrameAddressFunction StoreFrameAddress);
|
||||
|
||||
} // end namespace jitlink
|
||||
} // end namespace llvm
|
||||
|
||||
@@ -41,27 +41,48 @@ namespace orc {
|
||||
|
||||
class ObjectLinkingLayerJITLinkContext;
|
||||
|
||||
/// An ObjectLayer implementation built on JITLink.
|
||||
///
|
||||
/// Clients can use this class to add relocatable object files to an
|
||||
/// ExecutionSession, and it typically serves as the base layer (underneath
|
||||
/// a compiling layer like IRCompileLayer) for the rest of the JIT.
|
||||
class ObjectLinkingLayer : public ObjectLayer {
|
||||
friend class ObjectLinkingLayerJITLinkContext;
|
||||
|
||||
public:
|
||||
/// Function object for receiving object-loaded notifications.
|
||||
using NotifyLoadedFunction = std::function<void(VModuleKey)>;
|
||||
|
||||
/// Function object for receiving finalization notifications.
|
||||
using NotifyEmittedFunction = std::function<void(VModuleKey)>;
|
||||
|
||||
/// Function object for modifying PassConfiguration objects.
|
||||
using ModifyPassConfigFunction =
|
||||
std::function<void(const Triple &TT, jitlink::PassConfiguration &Config)>;
|
||||
/// Plugin instances can be added to the ObjectLinkingLayer to receive
|
||||
/// callbacks when code is loaded or emitted, and when JITLink is being
|
||||
/// configured.
|
||||
class Plugin {
|
||||
public:
|
||||
virtual ~Plugin();
|
||||
virtual void modifyPassConfig(MaterializationResponsibility &MR,
|
||||
const Triple &TT,
|
||||
jitlink::PassConfiguration &Config) {}
|
||||
virtual void notifyLoaded(MaterializationResponsibility &MR) {}
|
||||
virtual Error notifyEmitted(MaterializationResponsibility &MR) {
|
||||
return Error::success();
|
||||
}
|
||||
virtual Error notifyRemovingModule(VModuleKey K) {
|
||||
return Error::success();
|
||||
}
|
||||
virtual Error notifyRemovingAllModules() { return Error::success(); }
|
||||
};
|
||||
|
||||
/// Construct an ObjectLinkingLayer with the given NotifyLoaded,
|
||||
/// and NotifyEmitted functors.
|
||||
ObjectLinkingLayer(
|
||||
ExecutionSession &ES, jitlink::JITLinkMemoryManager &MemMgr,
|
||||
NotifyLoadedFunction NotifyLoaded = NotifyLoadedFunction(),
|
||||
NotifyEmittedFunction NotifyEmitted = NotifyEmittedFunction(),
|
||||
ModifyPassConfigFunction ModifyPassConfig = ModifyPassConfigFunction());
|
||||
/// and NotifyEmitted functors.
|
||||
ObjectLinkingLayer(ExecutionSession &ES,
|
||||
jitlink::JITLinkMemoryManager &MemMgr);
|
||||
|
||||
/// Destruct an ObjectLinkingLayer.
|
||||
~ObjectLinkingLayer();
|
||||
|
||||
/// Add a pass-config modifier.
|
||||
ObjectLinkingLayer &addPlugin(std::unique_ptr<Plugin> P) {
|
||||
std::lock_guard<std::mutex> Lock(LayerMutex);
|
||||
Plugins.push_back(std::move(P));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Emit the object.
|
||||
void emit(MaterializationResponsibility R,
|
||||
@@ -101,31 +122,35 @@ public:
|
||||
private:
|
||||
using AllocPtr = std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>;
|
||||
|
||||
class ObjectResources {
|
||||
public:
|
||||
ObjectResources() = default;
|
||||
ObjectResources(AllocPtr Alloc, JITTargetAddress EHFrameAddr);
|
||||
ObjectResources(ObjectResources &&Other);
|
||||
ObjectResources &operator=(ObjectResources &&Other);
|
||||
~ObjectResources();
|
||||
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
|
||||
jitlink::PassConfiguration &PassConfig);
|
||||
void notifyLoaded(MaterializationResponsibility &MR);
|
||||
Error notifyEmitted(MaterializationResponsibility &MR, AllocPtr Alloc);
|
||||
|
||||
private:
|
||||
AllocPtr Alloc;
|
||||
JITTargetAddress EHFrameAddr = 0;
|
||||
};
|
||||
|
||||
void notifyFinalized(ObjectResources OR) {
|
||||
ObjResources.push_back(std::move(OR));
|
||||
}
|
||||
Error removeModule(VModuleKey K);
|
||||
Error removeAllModules();
|
||||
|
||||
mutable std::mutex LayerMutex;
|
||||
jitlink::JITLinkMemoryManager &MemMgr;
|
||||
NotifyLoadedFunction NotifyLoaded;
|
||||
NotifyEmittedFunction NotifyEmitted;
|
||||
ModifyPassConfigFunction ModifyPassConfig;
|
||||
bool OverrideObjectFlags = false;
|
||||
bool AutoClaimObjectSymbols = false;
|
||||
std::vector<ObjectResources> ObjResources;
|
||||
DenseMap<VModuleKey, AllocPtr> TrackedAllocs;
|
||||
std::vector<AllocPtr> UntrackedAllocs;
|
||||
std::vector<std::unique_ptr<Plugin>> Plugins;
|
||||
};
|
||||
|
||||
class LocalEHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin {
|
||||
public:
|
||||
Error notifyEmitted(MaterializationResponsibility &MR) override;
|
||||
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
|
||||
jitlink::PassConfiguration &PassConfig) override;
|
||||
Error notifyRemovingModule(VModuleKey K) override;
|
||||
Error notifyRemovingAllModules() override;
|
||||
|
||||
private:
|
||||
DenseMap<MaterializationResponsibility *, const void *> InProcessLinks;
|
||||
DenseMap<VModuleKey, const void *> TrackedEHFrameAddrs;
|
||||
std::vector<const void *> UntrackedEHFrameAddrs;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
|
||||
@@ -507,8 +507,9 @@ Error deregisterEHFrameSection(const void *EHFrameSectionAddr) {
|
||||
#endif
|
||||
}
|
||||
|
||||
AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
|
||||
JITTargetAddress &EHFrameAddr) {
|
||||
AtomGraphPassFunction
|
||||
createEHFrameRecorderPass(const Triple &TT,
|
||||
StoreFrameAddressFunction StoreFrameAddress) {
|
||||
const char *EHFrameSectionName = nullptr;
|
||||
if (TT.getObjectFormat() == Triple::MachO)
|
||||
EHFrameSectionName = "__eh_frame";
|
||||
@@ -516,7 +517,7 @@ AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
|
||||
EHFrameSectionName = ".eh_frame";
|
||||
|
||||
auto RecordEHFrame = [EHFrameSectionName,
|
||||
&EHFrameAddr](AtomGraph &G) -> Error {
|
||||
StoreFrameAddress](AtomGraph &G) -> Error {
|
||||
// Search for a non-empty eh-frame and record the address of the first atom
|
||||
// in it.
|
||||
JITTargetAddress Addr = 0;
|
||||
@@ -529,7 +530,7 @@ AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
|
||||
break;
|
||||
}
|
||||
|
||||
EHFrameAddr = Addr;
|
||||
StoreFrameAddress(Addr);
|
||||
return Error::success();
|
||||
};
|
||||
|
||||
|
||||
@@ -133,25 +133,19 @@ public:
|
||||
|
||||
MR.resolve(InternedResult);
|
||||
|
||||
if (Layer.NotifyLoaded)
|
||||
Layer.NotifyLoaded(MR.getVModuleKey());
|
||||
Layer.notifyLoaded(MR);
|
||||
}
|
||||
|
||||
void notifyFinalized(
|
||||
std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
|
||||
|
||||
if (EHFrameAddr) {
|
||||
// If there is an eh-frame then try to register it.
|
||||
if (auto Err = registerEHFrameSection((void *)EHFrameAddr)) {
|
||||
Layer.getExecutionSession().reportError(std::move(Err));
|
||||
MR.failMaterialization();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
|
||||
Layer.getExecutionSession().reportError(std::move(Err));
|
||||
MR.failMaterialization();
|
||||
|
||||
return;
|
||||
}
|
||||
MR.emit();
|
||||
Layer.notifyFinalized(
|
||||
ObjectLinkingLayer::ObjectResources(std::move(A), EHFrameAddr));
|
||||
}
|
||||
|
||||
AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override {
|
||||
@@ -166,11 +160,7 @@ public:
|
||||
Config.PostPrunePasses.push_back(
|
||||
[this](AtomGraph &G) { return computeNamedSymbolDependencies(G); });
|
||||
|
||||
Config.PostFixupPasses.push_back(
|
||||
createEHFrameRecorderPass(TT, EHFrameAddr));
|
||||
|
||||
if (Layer.ModifyPassConfig)
|
||||
Layer.ModifyPassConfig(TT, Config);
|
||||
Layer.modifyPassConfig(MR, TT, Config);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
@@ -328,16 +318,18 @@ private:
|
||||
MaterializationResponsibility MR;
|
||||
std::unique_ptr<MemoryBuffer> ObjBuffer;
|
||||
DenseMap<SymbolStringPtr, SymbolNameSet> NamedSymbolDeps;
|
||||
JITTargetAddress EHFrameAddr = 0;
|
||||
};
|
||||
|
||||
ObjectLinkingLayer::ObjectLinkingLayer(
|
||||
ExecutionSession &ES, JITLinkMemoryManager &MemMgr,
|
||||
NotifyLoadedFunction NotifyLoaded, NotifyEmittedFunction NotifyEmitted,
|
||||
ModifyPassConfigFunction ModifyPassConfig)
|
||||
: ObjectLayer(ES), MemMgr(MemMgr), NotifyLoaded(std::move(NotifyLoaded)),
|
||||
NotifyEmitted(std::move(NotifyEmitted)),
|
||||
ModifyPassConfig(std::move(ModifyPassConfig)) {}
|
||||
ObjectLinkingLayer::Plugin::~Plugin() {}
|
||||
|
||||
ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES,
|
||||
JITLinkMemoryManager &MemMgr)
|
||||
: ObjectLayer(ES), MemMgr(MemMgr) {}
|
||||
|
||||
ObjectLinkingLayer::~ObjectLinkingLayer() {
|
||||
if (auto Err = removeAllModules())
|
||||
getExecutionSession().reportError(std::move(Err));
|
||||
}
|
||||
|
||||
void ObjectLinkingLayer::emit(MaterializationResponsibility R,
|
||||
std::unique_ptr<MemoryBuffer> O) {
|
||||
@@ -346,36 +338,145 @@ void ObjectLinkingLayer::emit(MaterializationResponsibility R,
|
||||
*this, std::move(R), std::move(O)));
|
||||
}
|
||||
|
||||
ObjectLinkingLayer::ObjectResources::ObjectResources(
|
||||
AllocPtr Alloc, JITTargetAddress EHFrameAddr)
|
||||
: Alloc(std::move(Alloc)), EHFrameAddr(EHFrameAddr) {}
|
||||
|
||||
ObjectLinkingLayer::ObjectResources::ObjectResources(ObjectResources &&Other)
|
||||
: Alloc(std::move(Other.Alloc)), EHFrameAddr(Other.EHFrameAddr) {
|
||||
Other.EHFrameAddr = 0;
|
||||
void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
|
||||
const Triple &TT,
|
||||
PassConfiguration &PassConfig) {
|
||||
for (auto &P : Plugins)
|
||||
P->modifyPassConfig(MR, TT, PassConfig);
|
||||
}
|
||||
|
||||
ObjectLinkingLayer::ObjectResources &
|
||||
ObjectLinkingLayer::ObjectResources::operator=(ObjectResources &&Other) {
|
||||
std::swap(Alloc, Other.Alloc);
|
||||
std::swap(EHFrameAddr, Other.EHFrameAddr);
|
||||
return *this;
|
||||
void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
|
||||
for (auto &P : Plugins)
|
||||
P->notifyLoaded(MR);
|
||||
}
|
||||
|
||||
ObjectLinkingLayer::ObjectResources::~ObjectResources() {
|
||||
const char *ErrBanner =
|
||||
"ObjectLinkingLayer received error deallocating object resources:";
|
||||
Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR,
|
||||
AllocPtr Alloc) {
|
||||
Error Err = Error::success();
|
||||
for (auto &P : Plugins)
|
||||
Err = joinErrors(std::move(Err), P->notifyEmitted(MR));
|
||||
|
||||
assert((EHFrameAddr == 0 || Alloc) &&
|
||||
"Non-null EHFrameAddr must have an associated allocation");
|
||||
if (Err)
|
||||
return Err;
|
||||
|
||||
if (EHFrameAddr)
|
||||
if (auto Err = deregisterEHFrameSection((void *)EHFrameAddr))
|
||||
logAllUnhandledErrors(std::move(Err), llvm::errs(), ErrBanner);
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(LayerMutex);
|
||||
UntrackedAllocs.push_back(std::move(Alloc));
|
||||
}
|
||||
|
||||
if (Alloc)
|
||||
if (auto Err = Alloc->deallocate())
|
||||
logAllUnhandledErrors(std::move(Err), llvm::errs(), ErrBanner);
|
||||
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;
|
||||
}
|
||||
|
||||
void LocalEHFrameRegistrationPlugin::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) {
|
||||
if (Addr)
|
||||
InProcessLinks[&MR] = jitTargetAddressToPointer<void *>(Addr);
|
||||
}));
|
||||
}
|
||||
|
||||
Error LocalEHFrameRegistrationPlugin::notifyEmitted(
|
||||
MaterializationResponsibility &MR) {
|
||||
|
||||
auto EHFrameAddrItr = InProcessLinks.find(&MR);
|
||||
if (EHFrameAddrItr == InProcessLinks.end())
|
||||
return Error::success();
|
||||
|
||||
const void *EHFrameAddr = EHFrameAddrItr->second;
|
||||
assert(EHFrameAddr && "eh-frame addr to register can not be null");
|
||||
|
||||
InProcessLinks.erase(EHFrameAddrItr);
|
||||
if (auto Key = MR.getVModuleKey())
|
||||
TrackedEHFrameAddrs[Key] = EHFrameAddr;
|
||||
else
|
||||
UntrackedEHFrameAddrs.push_back(EHFrameAddr);
|
||||
|
||||
return registerEHFrameSection(EHFrameAddr);
|
||||
}
|
||||
|
||||
Error LocalEHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) {
|
||||
auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K);
|
||||
if (EHFrameAddrItr == TrackedEHFrameAddrs.end())
|
||||
return Error::success();
|
||||
|
||||
const void *EHFrameAddr = EHFrameAddrItr->second;
|
||||
assert(EHFrameAddr && "Tracked eh-frame addr must not be null");
|
||||
|
||||
TrackedEHFrameAddrs.erase(EHFrameAddrItr);
|
||||
|
||||
return deregisterEHFrameSection(EHFrameAddr);
|
||||
}
|
||||
|
||||
Error LocalEHFrameRegistrationPlugin::notifyRemovingAllModules() {
|
||||
|
||||
std::vector<const void *> EHFrameAddrs = std::move(UntrackedEHFrameAddrs);
|
||||
EHFrameAddrs.reserve(EHFrameAddrs.size() + TrackedEHFrameAddrs.size());
|
||||
|
||||
for (auto &KV : TrackedEHFrameAddrs)
|
||||
EHFrameAddrs.push_back(KV.second);
|
||||
|
||||
TrackedEHFrameAddrs.clear();
|
||||
|
||||
Error Err = Error::success();
|
||||
|
||||
while (!EHFrameAddrs.empty()) {
|
||||
const void *EHFrameAddr = EHFrameAddrs.back();
|
||||
assert(EHFrameAddr && "Untracked eh-frame addr must not be null");
|
||||
EHFrameAddrs.pop_back();
|
||||
Err = joinErrors(std::move(Err), deregisterEHFrameSection(EHFrameAddr));
|
||||
}
|
||||
|
||||
return Err;
|
||||
}
|
||||
|
||||
} // End namespace orc.
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
# RUN: llvm-jitlink -noexec %S/Inputs/MachO_x86-64_ehframe.o
|
||||
#
|
||||
# FIXME: Produces these errors:
|
||||
# JIT session error: Symbols not found: { __ZTIi, ___gxx_personality_v0 }
|
||||
# llvm-jitlink.exe: Failed to materialize symbols: { biz, _main, baz }
|
||||
# XFAIL: windows-msvc
|
||||
# RUN: llvm-jitlink -noexec -define-abs __ZTIi=0x1 -define-abs ___gxx_personality_v0=0x2 %S/Inputs/MachO_x86-64_ehframe.o
|
||||
#
|
||||
# Perform a no-exec link of MachO_x86-64_ehframe and verify that it does not
|
||||
# generate any errors despite the last FDE referring to the first CIE (rather
|
||||
|
||||
@@ -214,13 +214,27 @@ static void dumpSectionContents(raw_ostream &OS, AtomGraph &G) {
|
||||
}
|
||||
}
|
||||
|
||||
Session::Session(Triple TT)
|
||||
: ObjLayer(ES, MemMgr, ObjectLinkingLayer::NotifyLoadedFunction(),
|
||||
ObjectLinkingLayer::NotifyEmittedFunction(),
|
||||
[this](const Triple &TT, PassConfiguration &PassConfig) {
|
||||
modifyPassConfig(TT, PassConfig);
|
||||
}),
|
||||
TT(std::move(TT)) {}
|
||||
Session::Session(Triple TT) : ObjLayer(ES, MemMgr), TT(std::move(TT)) {
|
||||
|
||||
/// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
|
||||
/// Session.
|
||||
class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin {
|
||||
public:
|
||||
JITLinkSessionPlugin(Session &S) : S(S) {}
|
||||
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
|
||||
PassConfiguration &PassConfig) {
|
||||
S.modifyPassConfig(TT, PassConfig);
|
||||
}
|
||||
|
||||
private:
|
||||
Session &S;
|
||||
};
|
||||
|
||||
if (!NoExec && !TT.isOSWindows())
|
||||
ObjLayer.addPlugin(llvm::make_unique<LocalEHFrameRegistrationPlugin>());
|
||||
|
||||
ObjLayer.addPlugin(llvm::make_unique<JITLinkSessionPlugin>(*this));
|
||||
}
|
||||
|
||||
void Session::dumpSessionInfo(raw_ostream &OS) {
|
||||
OS << "Registered addresses:\n" << SymbolInfos << FileInfos;
|
||||
|
||||
Reference in New Issue
Block a user