aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp')
-rw-r--r--llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp435
1 files changed, 305 insertions, 130 deletions
diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
index 26f77acd91fc..fd260089c04b 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
@@ -7,10 +7,11 @@
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
-
#include "llvm/ADT/Optional.h"
#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
-
+#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
#include <vector>
#define DEBUG_TYPE "orc"
@@ -19,6 +20,101 @@ using namespace llvm;
using namespace llvm::jitlink;
using namespace llvm::orc;
+namespace {
+
+class LinkGraphMaterializationUnit : public MaterializationUnit {
+private:
+ struct LinkGraphInterface {
+ SymbolFlagsMap SymbolFlags;
+ SymbolStringPtr InitSymbol;
+ };
+
+public:
+ static std::unique_ptr<LinkGraphMaterializationUnit>
+ Create(ObjectLinkingLayer &ObjLinkingLayer, std::unique_ptr<LinkGraph> G) {
+ auto LGI = scanLinkGraph(ObjLinkingLayer.getExecutionSession(), *G);
+ return std::unique_ptr<LinkGraphMaterializationUnit>(
+ new LinkGraphMaterializationUnit(ObjLinkingLayer, std::move(G),
+ std::move(LGI)));
+ }
+
+ StringRef getName() const override { return G->getName(); }
+ void materialize(std::unique_ptr<MaterializationResponsibility> MR) override {
+ ObjLinkingLayer.emit(std::move(MR), std::move(G));
+ }
+
+private:
+ static LinkGraphInterface scanLinkGraph(ExecutionSession &ES, LinkGraph &G) {
+
+ LinkGraphInterface LGI;
+
+ for (auto *Sym : G.defined_symbols()) {
+ // Skip local symbols.
+ if (Sym->getScope() == Scope::Local)
+ continue;
+ assert(Sym->hasName() && "Anonymous non-local symbol?");
+
+ JITSymbolFlags Flags;
+ if (Sym->getScope() == Scope::Default)
+ Flags |= JITSymbolFlags::Exported;
+
+ if (Sym->isCallable())
+ Flags |= JITSymbolFlags::Callable;
+
+ LGI.SymbolFlags[ES.intern(Sym->getName())] = Flags;
+ }
+
+ if (G.getTargetTriple().isOSBinFormatMachO())
+ if (hasMachOInitSection(G))
+ LGI.InitSymbol = makeInitSymbol(ES, G);
+
+ return LGI;
+ }
+
+ static bool hasMachOInitSection(LinkGraph &G) {
+ for (auto &Sec : G.sections())
+ if (Sec.getName() == "__DATA,__obj_selrefs" ||
+ Sec.getName() == "__DATA,__objc_classlist" ||
+ Sec.getName() == "__TEXT,__swift5_protos" ||
+ Sec.getName() == "__TEXT,__swift5_proto" ||
+ Sec.getName() == "__DATA,__mod_init_func")
+ return true;
+ return false;
+ }
+
+ static SymbolStringPtr makeInitSymbol(ExecutionSession &ES, LinkGraph &G) {
+ std::string InitSymString;
+ raw_string_ostream(InitSymString)
+ << "$." << G.getName() << ".__inits" << Counter++;
+ return ES.intern(InitSymString);
+ }
+
+ LinkGraphMaterializationUnit(ObjectLinkingLayer &ObjLinkingLayer,
+ std::unique_ptr<LinkGraph> G,
+ LinkGraphInterface LGI)
+ : MaterializationUnit(std::move(LGI.SymbolFlags),
+ std::move(LGI.InitSymbol)),
+ ObjLinkingLayer(ObjLinkingLayer), G(std::move(G)) {}
+
+ void discard(const JITDylib &JD, const SymbolStringPtr &Name) override {
+ for (auto *Sym : G->defined_symbols())
+ if (Sym->getName() == *Name) {
+ assert(Sym->getLinkage() == Linkage::Weak &&
+ "Discarding non-weak definition");
+ G->makeExternal(*Sym);
+ break;
+ }
+ }
+
+ ObjectLinkingLayer &ObjLinkingLayer;
+ std::unique_ptr<LinkGraph> G;
+ static std::atomic<uint64_t> Counter;
+};
+
+std::atomic<uint64_t> LinkGraphMaterializationUnit::Counter{0};
+
+} // end anonymous namespace
+
namespace llvm {
namespace orc {
@@ -40,6 +136,13 @@ public:
JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
+ void notifyMaterializing(LinkGraph &G) {
+ for (auto &P : Layer.Plugins)
+ P->notifyMaterializing(*MR, G, *this,
+ ObjBuffer ? ObjBuffer->getMemBufferRef()
+ : MemoryBufferRef());
+ }
+
void notifyFailed(Error Err) override {
for (auto &P : Layer.Plugins)
Err = joinErrors(std::move(Err), P->notifyFailed(*MR));
@@ -211,14 +314,14 @@ public:
return [this](LinkGraph &G) { return markResponsibilitySymbolsLive(G); };
}
- Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override {
+ Error modifyPassConfig(LinkGraph &LG, 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 claimOrExternalizeWeakAndCommonSymbols(G);
});
- Layer.modifyPassConfig(*MR, TT, Config);
+ Layer.modifyPassConfig(*MR, LG, Config);
Config.PostPrunePasses.push_back(
[this](LinkGraph &G) { return computeNamedSymbolDependencies(G); });
@@ -227,12 +330,82 @@ public:
}
private:
- struct LocalSymbolNamedDependencies {
+ // Symbol name dependencies:
+ // Internal: Defined in this graph.
+ // External: Defined externally.
+ struct BlockSymbolDependencies {
SymbolNameSet Internal, External;
};
- using LocalSymbolNamedDependenciesMap =
- DenseMap<const Symbol *, LocalSymbolNamedDependencies>;
+ // Lazily populated map of blocks to BlockSymbolDependencies values.
+ class BlockDependenciesMap {
+ public:
+ BlockDependenciesMap(ExecutionSession &ES,
+ DenseMap<const Block *, DenseSet<Block *>> BlockDeps)
+ : ES(ES), BlockDeps(std::move(BlockDeps)) {}
+
+ const BlockSymbolDependencies &operator[](const Block &B) {
+ // Check the cache first.
+ auto I = BlockTransitiveDepsCache.find(&B);
+ if (I != BlockTransitiveDepsCache.end())
+ return I->second;
+
+ // No value. Populate the cache.
+ BlockSymbolDependencies BTDCacheVal;
+ auto BDI = BlockDeps.find(&B);
+ assert(BDI != BlockDeps.end() && "No block dependencies");
+
+ for (auto *BDep : BDI->second) {
+ auto &BID = getBlockImmediateDeps(*BDep);
+ for (auto &ExternalDep : BID.External)
+ BTDCacheVal.External.insert(ExternalDep);
+ for (auto &InternalDep : BID.Internal)
+ BTDCacheVal.Internal.insert(InternalDep);
+ }
+
+ return BlockTransitiveDepsCache
+ .insert(std::make_pair(&B, std::move(BTDCacheVal)))
+ .first->second;
+ }
+
+ SymbolStringPtr &getInternedName(Symbol &Sym) {
+ auto I = NameCache.find(&Sym);
+ if (I != NameCache.end())
+ return I->second;
+
+ return NameCache.insert(std::make_pair(&Sym, ES.intern(Sym.getName())))
+ .first->second;
+ }
+
+ private:
+ BlockSymbolDependencies &getBlockImmediateDeps(Block &B) {
+ // Check the cache first.
+ auto I = BlockImmediateDepsCache.find(&B);
+ if (I != BlockImmediateDepsCache.end())
+ return I->second;
+
+ BlockSymbolDependencies BIDCacheVal;
+ for (auto &E : B.edges()) {
+ auto &Tgt = E.getTarget();
+ if (Tgt.getScope() != Scope::Local) {
+ if (Tgt.isExternal())
+ BIDCacheVal.External.insert(getInternedName(Tgt));
+ else
+ BIDCacheVal.Internal.insert(getInternedName(Tgt));
+ }
+ }
+
+ return BlockImmediateDepsCache
+ .insert(std::make_pair(&B, std::move(BIDCacheVal)))
+ .first->second;
+ }
+
+ ExecutionSession &ES;
+ DenseMap<const Block *, DenseSet<Block *>> BlockDeps;
+ DenseMap<const Symbol *, SymbolStringPtr> NameCache;
+ DenseMap<const Block *, BlockSymbolDependencies> BlockImmediateDepsCache;
+ DenseMap<const Block *, BlockSymbolDependencies> BlockTransitiveDepsCache;
+ };
Error claimOrExternalizeWeakAndCommonSymbols(LinkGraph &G) {
auto &ES = Layer.getExecutionSession();
@@ -280,7 +453,7 @@ private:
Error computeNamedSymbolDependencies(LinkGraph &G) {
auto &ES = MR->getTargetJITDylib().getExecutionSession();
- auto LocalDeps = computeLocalDeps(G);
+ auto BlockDeps = computeBlockNonLocalDeps(G);
// Compute dependencies for symbols defined in the JITLink graph.
for (auto *Sym : G.defined_symbols()) {
@@ -291,58 +464,41 @@ private:
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())
+ auto &SymDeps = BlockDeps[Sym->getBlock()];
+ if (SymDeps.External.empty() && SymDeps.Internal.empty())
continue;
auto SymName = ES.intern(Sym->getName());
- if (!ExternalSymDeps.empty())
- ExternalNamedSymbolDeps[SymName] = std::move(ExternalSymDeps);
- if (!InternalSymDeps.empty())
- InternalNamedSymbolDeps[SymName] = std::move(InternalSymDeps);
+ if (!SymDeps.External.empty())
+ ExternalNamedSymbolDeps[SymName] = SymDeps.External;
+ if (!SymDeps.Internal.empty())
+ InternalNamedSymbolDeps[SymName] = SymDeps.Internal;
}
for (auto &P : Layer.Plugins) {
- auto SyntheticLocalDeps = P->getSyntheticSymbolLocalDependencies(*MR);
- if (SyntheticLocalDeps.empty())
+ auto SynthDeps = P->getSyntheticSymbolDependencies(*MR);
+ if (SynthDeps.empty())
continue;
- for (auto &KV : SyntheticLocalDeps) {
+ DenseSet<Block *> BlockVisited;
+ for (auto &KV : SynthDeps) {
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);
+ auto &DepsForName = KV.second;
+ for (auto *Sym : DepsForName) {
+ if (Sym->getScope() == Scope::Local) {
+ auto &BDeps = BlockDeps[Sym->getBlock()];
+ for (auto &S : BDeps.Internal)
+ InternalNamedSymbolDeps[Name].insert(S);
+ for (auto &S : BDeps.External)
+ ExternalNamedSymbolDeps[Name].insert(S);
+ } else {
+ if (Sym->isExternal())
+ ExternalNamedSymbolDeps[Name].insert(
+ BlockDeps.getInternedName(*Sym));
+ else
+ InternalNamedSymbolDeps[Name].insert(
+ BlockDeps.getInternedName(*Sym));
+ }
}
}
}
@@ -350,81 +506,69 @@ private:
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;
+ BlockDependenciesMap computeBlockNonLocalDeps(LinkGraph &G) {
+ // First calculate the reachable-via-non-local-symbol blocks for each block.
+ struct BlockInfo {
+ DenseSet<Block *> Dependencies;
+ DenseSet<Block *> Dependants;
+ bool DependenciesChanged = true;
};
- 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);
+ DenseMap<Block *, BlockInfo> BlockInfos;
+ SmallVector<Block *> WorkList;
+
+ // Pre-allocate map entries. This prevents any iterator/reference
+ // invalidation in the next loop.
+ for (auto *B : G.blocks())
+ (void)BlockInfos[B];
+
+ // Build initial worklist, record block dependencies/dependants and
+ // non-local symbol dependencies.
+ for (auto *B : G.blocks()) {
+ auto &BI = BlockInfos[B];
+ for (auto &E : B->edges()) {
+ if (E.getTarget().getScope() == Scope::Local) {
+ auto &TgtB = E.getTarget().getBlock();
+ if (&TgtB != B) {
+ BI.Dependencies.insert(&TgtB);
+ BlockInfos[&TgtB].Dependants.insert(B);
}
}
-
- 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);
+ // If this node has both dependants and dependencies then add it to the
+ // worklist to propagate the dependencies to the dependants.
+ if (!BI.Dependants.empty() && !BI.Dependencies.empty())
+ WorkList.push_back(B);
+ }
- // 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()));
+ // Propagate block-level dependencies through the block-dependence graph.
+ while (!WorkList.empty()) {
+ auto *B = WorkList.back();
+ WorkList.pop_back();
+
+ auto &BI = BlockInfos[B];
+ assert(BI.DependenciesChanged &&
+ "Block in worklist has unchanged dependencies");
+ BI.DependenciesChanged = false;
+ for (auto *Dependant : BI.Dependants) {
+ auto &DependantBI = BlockInfos[Dependant];
+ for (auto *Dependency : BI.Dependencies) {
+ if (Dependant != Dependency &&
+ DependantBI.Dependencies.insert(Dependency).second)
+ if (!DependantBI.DependenciesChanged) {
+ DependantBI.DependenciesChanged = true;
+ WorkList.push_back(Dependant);
+ }
+ }
}
}
- return Result;
+ DenseMap<const Block *, DenseSet<Block *>> BlockDeps;
+ for (auto &KV : BlockInfos)
+ BlockDeps[KV.first] = std::move(KV.second.Dependencies);
+
+ return BlockDependenciesMap(Layer.getExecutionSession(),
+ std::move(BlockDeps));
}
void registerDependencies(const SymbolDependenceMap &QueryDeps) {
@@ -459,15 +603,24 @@ private:
ObjectLinkingLayer::Plugin::~Plugin() {}
+char ObjectLinkingLayer::ID;
+
+using BaseT = RTTIExtends<ObjectLinkingLayer, ObjectLayer>;
+
+ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES)
+ : BaseT(ES), MemMgr(ES.getExecutorProcessControl().getMemMgr()) {
+ ES.registerResourceManager(*this);
+}
+
ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES,
JITLinkMemoryManager &MemMgr)
- : ObjectLayer(ES), MemMgr(MemMgr) {
+ : BaseT(ES), MemMgr(MemMgr) {
ES.registerResourceManager(*this);
}
ObjectLinkingLayer::ObjectLinkingLayer(
ExecutionSession &ES, std::unique_ptr<JITLinkMemoryManager> MemMgr)
- : ObjectLayer(ES), MemMgr(*MemMgr), MemMgrOwnership(std::move(MemMgr)) {
+ : BaseT(ES), MemMgr(*MemMgr), MemMgrOwnership(std::move(MemMgr)) {
ES.registerResourceManager(*this);
}
@@ -476,29 +629,41 @@ ObjectLinkingLayer::~ObjectLinkingLayer() {
getExecutionSession().deregisterResourceManager(*this);
}
+Error ObjectLinkingLayer::add(ResourceTrackerSP RT,
+ std::unique_ptr<LinkGraph> G) {
+ auto &JD = RT->getJITDylib();
+ return JD.define(LinkGraphMaterializationUnit::Create(*this, std::move(G)),
+ std::move(RT));
+}
+
void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
std::unique_ptr<MemoryBuffer> O) {
assert(O && "Object must not be null");
- auto ObjBuffer = O->getMemBufferRef();
+ MemoryBufferRef ObjBuffer = O->getMemBufferRef();
+
auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
*this, std::move(R), std::move(O));
- if (auto G = createLinkGraphFromObject(std::move(ObjBuffer)))
+ if (auto G = createLinkGraphFromObject(ObjBuffer)) {
+ Ctx->notifyMaterializing(**G);
link(std::move(*G), std::move(Ctx));
- else
+ } else {
Ctx->notifyFailed(G.takeError());
+ }
}
void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
std::unique_ptr<LinkGraph> G) {
- link(std::move(G), std::make_unique<ObjectLinkingLayerJITLinkContext>(
- *this, std::move(R), nullptr));
+ auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
+ *this, std::move(R), nullptr);
+ Ctx->notifyMaterializing(*G);
+ link(std::move(G), std::move(Ctx));
}
void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
- const Triple &TT,
+ LinkGraph &G,
PassConfiguration &PassConfig) {
for (auto &P : Plugins)
- P->modifyPassConfig(MR, TT, PassConfig);
+ P->modifyPassConfig(MR, G, PassConfig);
}
void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
@@ -567,11 +732,11 @@ EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
: ES(ES), Registrar(std::move(Registrar)) {}
void EHFrameRegistrationPlugin::modifyPassConfig(
- MaterializationResponsibility &MR, const Triple &TT,
+ MaterializationResponsibility &MR, LinkGraph &G,
PassConfiguration &PassConfig) {
PassConfig.PostFixupPasses.push_back(createEHFrameRecorderPass(
- TT, [this, &MR](JITTargetAddress Addr, size_t Size) {
+ G.getTargetTriple(), [this, &MR](JITTargetAddress Addr, size_t Size) {
if (Addr) {
std::lock_guard<std::mutex> Lock(EHFramePluginMutex);
assert(!InProcessLinks.count(&MR) &&
@@ -638,13 +803,23 @@ Error EHFrameRegistrationPlugin::notifyRemovingResources(ResourceKey K) {
void EHFrameRegistrationPlugin::notifyTransferringResources(
ResourceKey DstKey, ResourceKey SrcKey) {
auto SI = EHFrameRanges.find(SrcKey);
- if (SI != EHFrameRanges.end()) {
+ if (SI == EHFrameRanges.end())
+ return;
+
+ auto DI = EHFrameRanges.find(DstKey);
+ if (DI != EHFrameRanges.end()) {
auto &SrcRanges = SI->second;
- auto &DstRanges = EHFrameRanges[DstKey];
+ auto &DstRanges = DI->second;
DstRanges.reserve(DstRanges.size() + SrcRanges.size());
for (auto &SrcRange : SrcRanges)
DstRanges.push_back(std::move(SrcRange));
EHFrameRanges.erase(SI);
+ } else {
+ // We need to move SrcKey's ranges over without invalidating the SI
+ // iterator.
+ auto Tmp = std::move(SI->second);
+ EHFrameRanges.erase(SI);
+ EHFrameRanges[DstKey] = std::move(Tmp);
}
}