1 //===------- ObjectLinkingLayer.cpp - JITLink backed ORC ObjectLayer ------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
11 #include "llvm/ADT/Optional.h"
12 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
16 #define DEBUG_TYPE "orc"
19 using namespace llvm::jitlink;
20 using namespace llvm::orc;
25 class ObjectLinkingLayerJITLinkContext final : public JITLinkContext {
27 ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer &Layer,
28 MaterializationResponsibility MR,
29 std::unique_ptr<MemoryBuffer> ObjBuffer)
30 : Layer(Layer), MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {}
32 JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
34 MemoryBufferRef getObjectBuffer() const override {
35 return ObjBuffer->getMemBufferRef();
38 void notifyFailed(Error Err) override {
39 Layer.getExecutionSession().reportError(std::move(Err));
40 MR.failMaterialization();
43 void lookup(const DenseSet<StringRef> &Symbols,
44 JITLinkAsyncLookupContinuation LookupContinuation) override {
46 JITDylibSearchList SearchOrder;
47 MR.getTargetJITDylib().withSearchOrderDo(
48 [&](const JITDylibSearchList &JDs) { SearchOrder = JDs; });
50 auto &ES = Layer.getExecutionSession();
52 SymbolNameSet InternedSymbols;
53 for (auto &S : Symbols)
54 InternedSymbols.insert(ES.intern(S));
56 // OnResolve -- De-intern the symbols and pass the result to the linker.
57 // FIXME: Capture LookupContinuation by move once we have c++14.
58 auto SharedLookupContinuation =
59 std::make_shared<JITLinkAsyncLookupContinuation>(
60 std::move(LookupContinuation));
61 auto OnResolve = [SharedLookupContinuation](Expected<SymbolMap> Result) {
63 (*SharedLookupContinuation)(Result.takeError());
66 for (auto &KV : *Result)
67 LR[*KV.first] = KV.second;
68 (*SharedLookupContinuation)(std::move(LR));
72 ES.lookup(SearchOrder, std::move(InternedSymbols), SymbolState::Resolved,
73 std::move(OnResolve), [this](const SymbolDependenceMap &Deps) {
74 registerDependencies(Deps);
78 void notifyResolved(AtomGraph &G) override {
79 auto &ES = Layer.getExecutionSession();
81 SymbolFlagsMap ExtraSymbolsToClaim;
82 bool AutoClaim = Layer.AutoClaimObjectSymbols;
84 SymbolMap InternedResult;
85 for (auto *DA : G.defined_atoms())
86 if (DA->hasName() && DA->isGlobal()) {
87 auto InternedName = ES.intern(DA->getName());
91 Flags |= JITSymbolFlags::Exported;
93 Flags |= JITSymbolFlags::Weak;
95 Flags |= JITSymbolFlags::Callable;
97 Flags |= JITSymbolFlags::Common;
99 InternedResult[InternedName] =
100 JITEvaluatedSymbol(DA->getAddress(), Flags);
101 if (AutoClaim && !MR.getSymbols().count(InternedName)) {
102 assert(!ExtraSymbolsToClaim.count(InternedName) &&
103 "Duplicate symbol to claim?");
104 ExtraSymbolsToClaim[InternedName] = Flags;
108 for (auto *A : G.absolute_atoms())
110 auto InternedName = ES.intern(A->getName());
111 JITSymbolFlags Flags;
112 Flags |= JITSymbolFlags::Absolute;
114 Flags |= JITSymbolFlags::Weak;
116 Flags |= JITSymbolFlags::Callable;
117 InternedResult[InternedName] =
118 JITEvaluatedSymbol(A->getAddress(), Flags);
119 if (AutoClaim && !MR.getSymbols().count(InternedName)) {
120 assert(!ExtraSymbolsToClaim.count(InternedName) &&
121 "Duplicate symbol to claim?");
122 ExtraSymbolsToClaim[InternedName] = Flags;
126 if (!ExtraSymbolsToClaim.empty())
127 if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim))
128 return notifyFailed(std::move(Err));
130 MR.notifyResolved(InternedResult);
132 Layer.notifyLoaded(MR);
135 void notifyFinalized(
136 std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
138 if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
139 Layer.getExecutionSession().reportError(std::move(Err));
140 MR.failMaterialization();
147 AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override {
148 return [this](AtomGraph &G) { return markResponsibilitySymbolsLive(G); };
151 Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override {
152 // Add passes to mark duplicate defs as should-discard, and to walk the
153 // atom graph to build the symbol dependence graph.
154 Config.PrePrunePasses.push_back(
155 [this](AtomGraph &G) { return markSymbolsToDiscard(G); });
156 Config.PostPrunePasses.push_back(
157 [this](AtomGraph &G) { return computeNamedSymbolDependencies(G); });
159 Layer.modifyPassConfig(MR, TT, Config);
161 return Error::success();
165 using AnonAtomNamedDependenciesMap =
166 DenseMap<const DefinedAtom *, SymbolNameSet>;
168 Error markSymbolsToDiscard(AtomGraph &G) {
169 auto &ES = Layer.getExecutionSession();
170 for (auto *DA : G.defined_atoms())
171 if (DA->isWeak() && DA->hasName()) {
172 auto S = ES.intern(DA->getName());
173 auto I = MR.getSymbols().find(S);
174 if (I == MR.getSymbols().end())
175 DA->setShouldDiscard(true);
178 for (auto *A : G.absolute_atoms())
179 if (A->isWeak() && A->hasName()) {
180 auto S = ES.intern(A->getName());
181 auto I = MR.getSymbols().find(S);
182 if (I == MR.getSymbols().end())
183 A->setShouldDiscard(true);
186 return Error::success();
189 Error markResponsibilitySymbolsLive(AtomGraph &G) const {
190 auto &ES = Layer.getExecutionSession();
191 for (auto *DA : G.defined_atoms())
193 MR.getSymbols().count(ES.intern(DA->getName())))
195 return Error::success();
198 Error computeNamedSymbolDependencies(AtomGraph &G) {
199 auto &ES = MR.getTargetJITDylib().getExecutionSession();
200 auto AnonDeps = computeAnonDeps(G);
202 for (auto *DA : G.defined_atoms()) {
204 // Skip anonymous and non-global atoms: we do not need dependencies for
206 if (!DA->hasName() || !DA->isGlobal())
209 auto DAName = ES.intern(DA->getName());
210 SymbolNameSet &DADeps = NamedSymbolDeps[DAName];
212 for (auto &E : DA->edges()) {
213 auto &TA = E.getTarget();
216 DADeps.insert(ES.intern(TA.getName()));
218 assert(TA.isDefined() && "Anonymous atoms must be defined");
219 auto &DTA = static_cast<DefinedAtom &>(TA);
220 auto I = AnonDeps.find(&DTA);
221 if (I != AnonDeps.end())
222 for (auto &S : I->second)
228 return Error::success();
231 AnonAtomNamedDependenciesMap computeAnonDeps(AtomGraph &G) {
233 auto &ES = MR.getTargetJITDylib().getExecutionSession();
234 AnonAtomNamedDependenciesMap DepMap;
236 // For all anonymous atoms:
237 // (1) Add their named dependencies.
238 // (2) Add them to the worklist for further iteration if they have any
239 // depend on any other anonymous atoms.
240 struct WorklistEntry {
241 WorklistEntry(DefinedAtom *DA, DenseSet<DefinedAtom *> DAAnonDeps)
242 : DA(DA), DAAnonDeps(std::move(DAAnonDeps)) {}
244 DefinedAtom *DA = nullptr;
245 DenseSet<DefinedAtom *> DAAnonDeps;
247 std::vector<WorklistEntry> Worklist;
248 for (auto *DA : G.defined_atoms())
249 if (!DA->hasName()) {
250 auto &DANamedDeps = DepMap[DA];
251 DenseSet<DefinedAtom *> DAAnonDeps;
253 for (auto &E : DA->edges()) {
254 auto &TA = E.getTarget();
256 DANamedDeps.insert(ES.intern(TA.getName()));
258 assert(TA.isDefined() && "Anonymous atoms must be defined");
259 DAAnonDeps.insert(static_cast<DefinedAtom *>(&TA));
263 if (!DAAnonDeps.empty())
264 Worklist.push_back(WorklistEntry(DA, std::move(DAAnonDeps)));
267 // Loop over all anonymous atoms with anonymous dependencies, propagating
268 // their respective *named* dependencies. Iterate until we hit a stable
273 for (auto &WLEntry : Worklist) {
274 auto *DA = WLEntry.DA;
275 auto &DANamedDeps = DepMap[DA];
276 auto &DAAnonDeps = WLEntry.DAAnonDeps;
278 for (auto *TA : DAAnonDeps) {
279 auto I = DepMap.find(TA);
280 if (I != DepMap.end())
281 for (const auto &S : I->second)
282 Changed |= DANamedDeps.insert(S).second;
290 void registerDependencies(const SymbolDependenceMap &QueryDeps) {
291 for (auto &NamedDepsEntry : NamedSymbolDeps) {
292 auto &Name = NamedDepsEntry.first;
293 auto &NameDeps = NamedDepsEntry.second;
294 SymbolDependenceMap SymbolDeps;
296 for (const auto &QueryDepsEntry : QueryDeps) {
297 JITDylib &SourceJD = *QueryDepsEntry.first;
298 const SymbolNameSet &Symbols = QueryDepsEntry.second;
299 auto &DepsForJD = SymbolDeps[&SourceJD];
301 for (const auto &S : Symbols)
302 if (NameDeps.count(S))
305 if (DepsForJD.empty())
306 SymbolDeps.erase(&SourceJD);
309 MR.addDependencies(Name, SymbolDeps);
313 ObjectLinkingLayer &Layer;
314 MaterializationResponsibility MR;
315 std::unique_ptr<MemoryBuffer> ObjBuffer;
316 DenseMap<SymbolStringPtr, SymbolNameSet> NamedSymbolDeps;
319 ObjectLinkingLayer::Plugin::~Plugin() {}
321 ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES,
322 JITLinkMemoryManager &MemMgr)
323 : ObjectLayer(ES), MemMgr(MemMgr) {}
325 ObjectLinkingLayer::~ObjectLinkingLayer() {
326 if (auto Err = removeAllModules())
327 getExecutionSession().reportError(std::move(Err));
330 void ObjectLinkingLayer::emit(MaterializationResponsibility R,
331 std::unique_ptr<MemoryBuffer> O) {
332 assert(O && "Object must not be null");
333 jitLink(llvm::make_unique<ObjectLinkingLayerJITLinkContext>(
334 *this, std::move(R), std::move(O)));
337 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
339 PassConfiguration &PassConfig) {
340 for (auto &P : Plugins)
341 P->modifyPassConfig(MR, TT, PassConfig);
344 void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
345 for (auto &P : Plugins)
349 Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR,
351 Error Err = Error::success();
352 for (auto &P : Plugins)
353 Err = joinErrors(std::move(Err), P->notifyEmitted(MR));
359 std::lock_guard<std::mutex> Lock(LayerMutex);
360 UntrackedAllocs.push_back(std::move(Alloc));
363 return Error::success();
366 Error ObjectLinkingLayer::removeModule(VModuleKey K) {
367 Error Err = Error::success();
369 for (auto &P : Plugins)
370 Err = joinErrors(std::move(Err), P->notifyRemovingModule(K));
375 std::lock_guard<std::mutex> Lock(LayerMutex);
376 auto AllocItr = TrackedAllocs.find(K);
377 Alloc = std::move(AllocItr->second);
378 TrackedAllocs.erase(AllocItr);
381 assert(Alloc && "No allocation for key K");
383 return joinErrors(std::move(Err), Alloc->deallocate());
386 Error ObjectLinkingLayer::removeAllModules() {
388 Error Err = Error::success();
390 for (auto &P : Plugins)
391 Err = joinErrors(std::move(Err), P->notifyRemovingAllModules());
393 std::vector<AllocPtr> Allocs;
395 std::lock_guard<std::mutex> Lock(LayerMutex);
396 Allocs = std::move(UntrackedAllocs);
398 for (auto &KV : TrackedAllocs)
399 Allocs.push_back(std::move(KV.second));
401 TrackedAllocs.clear();
404 while (!Allocs.empty()) {
405 Err = joinErrors(std::move(Err), Allocs.back()->deallocate());
412 EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
413 jitlink::EHFrameRegistrar &Registrar)
414 : Registrar(Registrar) {}
416 void EHFrameRegistrationPlugin::modifyPassConfig(
417 MaterializationResponsibility &MR, const Triple &TT,
418 PassConfiguration &PassConfig) {
419 assert(!InProcessLinks.count(&MR) && "Link for MR already being tracked?");
421 PassConfig.PostFixupPasses.push_back(
422 createEHFrameRecorderPass(TT, [this, &MR](JITTargetAddress Addr) {
424 InProcessLinks[&MR] = Addr;
428 Error EHFrameRegistrationPlugin::notifyEmitted(
429 MaterializationResponsibility &MR) {
431 auto EHFrameAddrItr = InProcessLinks.find(&MR);
432 if (EHFrameAddrItr == InProcessLinks.end())
433 return Error::success();
435 auto EHFrameAddr = EHFrameAddrItr->second;
436 assert(EHFrameAddr && "eh-frame addr to register can not be null");
438 InProcessLinks.erase(EHFrameAddrItr);
439 if (auto Key = MR.getVModuleKey())
440 TrackedEHFrameAddrs[Key] = EHFrameAddr;
442 UntrackedEHFrameAddrs.push_back(EHFrameAddr);
444 return Registrar.registerEHFrames(EHFrameAddr);
447 Error EHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) {
448 auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K);
449 if (EHFrameAddrItr == TrackedEHFrameAddrs.end())
450 return Error::success();
452 auto EHFrameAddr = EHFrameAddrItr->second;
453 assert(EHFrameAddr && "Tracked eh-frame addr must not be null");
455 TrackedEHFrameAddrs.erase(EHFrameAddrItr);
457 return Registrar.deregisterEHFrames(EHFrameAddr);
460 Error EHFrameRegistrationPlugin::notifyRemovingAllModules() {
462 std::vector<JITTargetAddress> EHFrameAddrs = std::move(UntrackedEHFrameAddrs);
463 EHFrameAddrs.reserve(EHFrameAddrs.size() + TrackedEHFrameAddrs.size());
465 for (auto &KV : TrackedEHFrameAddrs)
466 EHFrameAddrs.push_back(KV.second);
468 TrackedEHFrameAddrs.clear();
470 Error Err = Error::success();
472 while (!EHFrameAddrs.empty()) {
473 auto EHFrameAddr = EHFrameAddrs.back();
474 assert(EHFrameAddr && "Untracked eh-frame addr must not be null");
475 EHFrameAddrs.pop_back();
476 Err = joinErrors(std::move(Err), Registrar.deregisterEHFrames(EHFrameAddr));
482 } // End namespace orc.
483 } // End namespace llvm.