xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp (revision a9fdf375b3769a1df18d72aa6eb1e627a22a29e7)
1 //===------- ObjectLinkingLayer.cpp - JITLink backed ORC ObjectLayer ------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
10 
11 #include "llvm/ADT/Optional.h"
12 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
13 
14 #include <vector>
15 
16 #define DEBUG_TYPE "orc"
17 
18 using namespace llvm;
19 using namespace llvm::jitlink;
20 using namespace llvm::orc;
21 
22 namespace llvm {
23 namespace orc {
24 
25 class ObjectLinkingLayerJITLinkContext final : public JITLinkContext {
26 public:
27   ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer &Layer,
28                                    MaterializationResponsibility MR,
29                                    std::unique_ptr<MemoryBuffer> ObjBuffer)
30       : Layer(Layer), MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {}
31 
32   JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
33 
34   MemoryBufferRef getObjectBuffer() const override {
35     return ObjBuffer->getMemBufferRef();
36   }
37 
38   void notifyFailed(Error Err) override {
39     Layer.getExecutionSession().reportError(std::move(Err));
40     MR.failMaterialization();
41   }
42 
43   void lookup(const DenseSet<StringRef> &Symbols,
44               JITLinkAsyncLookupContinuation LookupContinuation) override {
45 
46     JITDylibSearchList SearchOrder;
47     MR.getTargetJITDylib().withSearchOrderDo(
48         [&](const JITDylibSearchList &JDs) { SearchOrder = JDs; });
49 
50     auto &ES = Layer.getExecutionSession();
51 
52     SymbolNameSet InternedSymbols;
53     for (auto &S : Symbols)
54       InternedSymbols.insert(ES.intern(S));
55 
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) {
62       if (!Result)
63         (*SharedLookupContinuation)(Result.takeError());
64       else {
65         AsyncLookupResult LR;
66         for (auto &KV : *Result)
67           LR[*KV.first] = KV.second;
68         (*SharedLookupContinuation)(std::move(LR));
69       }
70     };
71 
72     ES.lookup(
73         SearchOrder, std::move(InternedSymbols), std::move(OnResolve),
74         // OnReady:
75         [&ES](Error Err) { ES.reportError(std::move(Err)); },
76         // RegisterDependencies:
77         [this](const SymbolDependenceMap &Deps) {
78           registerDependencies(Deps);
79         });
80   }
81 
82   void notifyResolved(AtomGraph &G) override {
83     auto &ES = Layer.getExecutionSession();
84 
85     SymbolFlagsMap ExtraSymbolsToClaim;
86     bool AutoClaim = Layer.AutoClaimObjectSymbols;
87 
88     SymbolMap InternedResult;
89     for (auto *DA : G.defined_atoms())
90       if (DA->hasName() && DA->isGlobal()) {
91         auto InternedName = ES.intern(DA->getName());
92         JITSymbolFlags Flags;
93 
94         if (DA->isExported())
95           Flags |= JITSymbolFlags::Exported;
96         if (DA->isWeak())
97           Flags |= JITSymbolFlags::Weak;
98         if (DA->isCallable())
99           Flags |= JITSymbolFlags::Callable;
100         if (DA->isCommon())
101           Flags |= JITSymbolFlags::Common;
102 
103         InternedResult[InternedName] =
104             JITEvaluatedSymbol(DA->getAddress(), Flags);
105         if (AutoClaim && !MR.getSymbols().count(InternedName)) {
106           assert(!ExtraSymbolsToClaim.count(InternedName) &&
107                  "Duplicate symbol to claim?");
108           ExtraSymbolsToClaim[InternedName] = Flags;
109         }
110       }
111 
112     for (auto *A : G.absolute_atoms())
113       if (A->hasName()) {
114         auto InternedName = ES.intern(A->getName());
115         JITSymbolFlags Flags;
116         Flags |= JITSymbolFlags::Absolute;
117         if (A->isWeak())
118           Flags |= JITSymbolFlags::Weak;
119         if (A->isCallable())
120           Flags |= JITSymbolFlags::Callable;
121         InternedResult[InternedName] =
122             JITEvaluatedSymbol(A->getAddress(), Flags);
123         if (AutoClaim && !MR.getSymbols().count(InternedName)) {
124           assert(!ExtraSymbolsToClaim.count(InternedName) &&
125                  "Duplicate symbol to claim?");
126           ExtraSymbolsToClaim[InternedName] = Flags;
127         }
128       }
129 
130     if (!ExtraSymbolsToClaim.empty())
131       if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim))
132         return notifyFailed(std::move(Err));
133 
134     MR.resolve(InternedResult);
135 
136     Layer.notifyLoaded(MR);
137   }
138 
139   void notifyFinalized(
140       std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
141 
142     if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
143       Layer.getExecutionSession().reportError(std::move(Err));
144       MR.failMaterialization();
145 
146       return;
147     }
148     MR.emit();
149   }
150 
151   AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override {
152     return [this](AtomGraph &G) { return markResponsibilitySymbolsLive(G); };
153   }
154 
155   Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override {
156     // Add passes to mark duplicate defs as should-discard, and to walk the
157     // atom graph to build the symbol dependence graph.
158     Config.PrePrunePasses.push_back(
159         [this](AtomGraph &G) { return markSymbolsToDiscard(G); });
160     Config.PostPrunePasses.push_back(
161         [this](AtomGraph &G) { return computeNamedSymbolDependencies(G); });
162 
163     Layer.modifyPassConfig(MR, TT, Config);
164 
165     return Error::success();
166   }
167 
168 private:
169   using AnonAtomNamedDependenciesMap =
170       DenseMap<const DefinedAtom *, SymbolNameSet>;
171 
172   Error markSymbolsToDiscard(AtomGraph &G) {
173     auto &ES = Layer.getExecutionSession();
174     for (auto *DA : G.defined_atoms())
175       if (DA->isWeak() && DA->hasName()) {
176         auto S = ES.intern(DA->getName());
177         auto I = MR.getSymbols().find(S);
178         if (I == MR.getSymbols().end())
179           DA->setShouldDiscard(true);
180       }
181 
182     for (auto *A : G.absolute_atoms())
183       if (A->isWeak() && A->hasName()) {
184         auto S = ES.intern(A->getName());
185         auto I = MR.getSymbols().find(S);
186         if (I == MR.getSymbols().end())
187           A->setShouldDiscard(true);
188       }
189 
190     return Error::success();
191   }
192 
193   Error markResponsibilitySymbolsLive(AtomGraph &G) const {
194     auto &ES = Layer.getExecutionSession();
195     for (auto *DA : G.defined_atoms())
196       if (DA->hasName() &&
197           MR.getSymbols().count(ES.intern(DA->getName())))
198         DA->setLive(true);
199     return Error::success();
200   }
201 
202   Error computeNamedSymbolDependencies(AtomGraph &G) {
203     auto &ES = MR.getTargetJITDylib().getExecutionSession();
204     auto AnonDeps = computeAnonDeps(G);
205 
206     for (auto *DA : G.defined_atoms()) {
207 
208       // Skip anonymous and non-global atoms: we do not need dependencies for
209       // these.
210       if (!DA->hasName() || !DA->isGlobal())
211         continue;
212 
213       auto DAName = ES.intern(DA->getName());
214       SymbolNameSet &DADeps = NamedSymbolDeps[DAName];
215 
216       for (auto &E : DA->edges()) {
217         auto &TA = E.getTarget();
218 
219         if (TA.hasName())
220           DADeps.insert(ES.intern(TA.getName()));
221         else {
222           assert(TA.isDefined() && "Anonymous atoms must be defined");
223           auto &DTA = static_cast<DefinedAtom &>(TA);
224           auto I = AnonDeps.find(&DTA);
225           if (I != AnonDeps.end())
226             for (auto &S : I->second)
227               DADeps.insert(S);
228         }
229       }
230     }
231 
232     return Error::success();
233   }
234 
235   AnonAtomNamedDependenciesMap computeAnonDeps(AtomGraph &G) {
236 
237     auto &ES = MR.getTargetJITDylib().getExecutionSession();
238     AnonAtomNamedDependenciesMap DepMap;
239 
240     // For all anonymous atoms:
241     // (1) Add their named dependencies.
242     // (2) Add them to the worklist for further iteration if they have any
243     //     depend on any other anonymous atoms.
244     struct WorklistEntry {
245       WorklistEntry(DefinedAtom *DA, DenseSet<DefinedAtom *> DAAnonDeps)
246           : DA(DA), DAAnonDeps(std::move(DAAnonDeps)) {}
247 
248       DefinedAtom *DA = nullptr;
249       DenseSet<DefinedAtom *> DAAnonDeps;
250     };
251     std::vector<WorklistEntry> Worklist;
252     for (auto *DA : G.defined_atoms())
253       if (!DA->hasName()) {
254         auto &DANamedDeps = DepMap[DA];
255         DenseSet<DefinedAtom *> DAAnonDeps;
256 
257         for (auto &E : DA->edges()) {
258           auto &TA = E.getTarget();
259           if (TA.hasName())
260             DANamedDeps.insert(ES.intern(TA.getName()));
261           else {
262             assert(TA.isDefined() && "Anonymous atoms must be defined");
263             DAAnonDeps.insert(static_cast<DefinedAtom *>(&TA));
264           }
265         }
266 
267         if (!DAAnonDeps.empty())
268           Worklist.push_back(WorklistEntry(DA, std::move(DAAnonDeps)));
269       }
270 
271     // Loop over all anonymous atoms with anonymous dependencies, propagating
272     // their respective *named* dependencies. Iterate until we hit a stable
273     // state.
274     bool Changed;
275     do {
276       Changed = false;
277       for (auto &WLEntry : Worklist) {
278         auto *DA = WLEntry.DA;
279         auto &DANamedDeps = DepMap[DA];
280         auto &DAAnonDeps = WLEntry.DAAnonDeps;
281 
282         for (auto *TA : DAAnonDeps) {
283           auto I = DepMap.find(TA);
284           if (I != DepMap.end())
285             for (const auto &S : I->second)
286               Changed |= DANamedDeps.insert(S).second;
287         }
288       }
289     } while (Changed);
290 
291     return DepMap;
292   }
293 
294   void registerDependencies(const SymbolDependenceMap &QueryDeps) {
295     for (auto &NamedDepsEntry : NamedSymbolDeps) {
296       auto &Name = NamedDepsEntry.first;
297       auto &NameDeps = NamedDepsEntry.second;
298       SymbolDependenceMap SymbolDeps;
299 
300       for (const auto &QueryDepsEntry : QueryDeps) {
301         JITDylib &SourceJD = *QueryDepsEntry.first;
302         const SymbolNameSet &Symbols = QueryDepsEntry.second;
303         auto &DepsForJD = SymbolDeps[&SourceJD];
304 
305         for (const auto &S : Symbols)
306           if (NameDeps.count(S))
307             DepsForJD.insert(S);
308 
309         if (DepsForJD.empty())
310           SymbolDeps.erase(&SourceJD);
311       }
312 
313       MR.addDependencies(Name, SymbolDeps);
314     }
315   }
316 
317   ObjectLinkingLayer &Layer;
318   MaterializationResponsibility MR;
319   std::unique_ptr<MemoryBuffer> ObjBuffer;
320   DenseMap<SymbolStringPtr, SymbolNameSet> NamedSymbolDeps;
321 };
322 
323 ObjectLinkingLayer::Plugin::~Plugin() {}
324 
325 ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES,
326                                        JITLinkMemoryManager &MemMgr)
327     : ObjectLayer(ES), MemMgr(MemMgr) {}
328 
329 ObjectLinkingLayer::~ObjectLinkingLayer() {
330   if (auto Err = removeAllModules())
331     getExecutionSession().reportError(std::move(Err));
332 }
333 
334 void ObjectLinkingLayer::emit(MaterializationResponsibility R,
335                               std::unique_ptr<MemoryBuffer> O) {
336   assert(O && "Object must not be null");
337   jitLink(llvm::make_unique<ObjectLinkingLayerJITLinkContext>(
338       *this, std::move(R), std::move(O)));
339 }
340 
341 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
342                                           const Triple &TT,
343                                           PassConfiguration &PassConfig) {
344   for (auto &P : Plugins)
345     P->modifyPassConfig(MR, TT, PassConfig);
346 }
347 
348 void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
349   for (auto &P : Plugins)
350     P->notifyLoaded(MR);
351 }
352 
353 Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR,
354                                         AllocPtr Alloc) {
355   Error Err = Error::success();
356   for (auto &P : Plugins)
357     Err = joinErrors(std::move(Err), P->notifyEmitted(MR));
358 
359   if (Err)
360     return Err;
361 
362   {
363     std::lock_guard<std::mutex> Lock(LayerMutex);
364     UntrackedAllocs.push_back(std::move(Alloc));
365   }
366 
367   return Error::success();
368 }
369 
370 Error ObjectLinkingLayer::removeModule(VModuleKey K) {
371   Error Err = Error::success();
372 
373   for (auto &P : Plugins)
374     Err = joinErrors(std::move(Err), P->notifyRemovingModule(K));
375 
376   AllocPtr Alloc;
377 
378   {
379     std::lock_guard<std::mutex> Lock(LayerMutex);
380     auto AllocItr = TrackedAllocs.find(K);
381     Alloc = std::move(AllocItr->second);
382     TrackedAllocs.erase(AllocItr);
383   }
384 
385   assert(Alloc && "No allocation for key K");
386 
387   return joinErrors(std::move(Err), Alloc->deallocate());
388 }
389 
390 Error ObjectLinkingLayer::removeAllModules() {
391 
392   Error Err = Error::success();
393 
394   for (auto &P : Plugins)
395     Err = joinErrors(std::move(Err), P->notifyRemovingAllModules());
396 
397   std::vector<AllocPtr> Allocs;
398   {
399     std::lock_guard<std::mutex> Lock(LayerMutex);
400     Allocs = std::move(UntrackedAllocs);
401 
402     for (auto &KV : TrackedAllocs)
403       Allocs.push_back(std::move(KV.second));
404 
405     TrackedAllocs.clear();
406   }
407 
408   while (!Allocs.empty()) {
409     Err = joinErrors(std::move(Err), Allocs.back()->deallocate());
410     Allocs.pop_back();
411   }
412 
413   return Err;
414 }
415 
416 void LocalEHFrameRegistrationPlugin::modifyPassConfig(
417     MaterializationResponsibility &MR, const Triple &TT,
418     PassConfiguration &PassConfig) {
419   assert(!InProcessLinks.count(&MR) && "Link for MR already being tracked?");
420 
421   PassConfig.PostFixupPasses.push_back(
422       createEHFrameRecorderPass(TT, [this, &MR](JITTargetAddress Addr) {
423         if (Addr)
424           InProcessLinks[&MR] = jitTargetAddressToPointer<void *>(Addr);
425       }));
426 }
427 
428 Error LocalEHFrameRegistrationPlugin::notifyEmitted(
429     MaterializationResponsibility &MR) {
430 
431   auto EHFrameAddrItr = InProcessLinks.find(&MR);
432   if (EHFrameAddrItr == InProcessLinks.end())
433     return Error::success();
434 
435   const void *EHFrameAddr = EHFrameAddrItr->second;
436   assert(EHFrameAddr && "eh-frame addr to register can not be null");
437 
438   InProcessLinks.erase(EHFrameAddrItr);
439   if (auto Key = MR.getVModuleKey())
440     TrackedEHFrameAddrs[Key] = EHFrameAddr;
441   else
442     UntrackedEHFrameAddrs.push_back(EHFrameAddr);
443 
444   return registerEHFrameSection(EHFrameAddr);
445 }
446 
447 Error LocalEHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) {
448   auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K);
449   if (EHFrameAddrItr == TrackedEHFrameAddrs.end())
450     return Error::success();
451 
452   const void *EHFrameAddr = EHFrameAddrItr->second;
453   assert(EHFrameAddr && "Tracked eh-frame addr must not be null");
454 
455   TrackedEHFrameAddrs.erase(EHFrameAddrItr);
456 
457   return deregisterEHFrameSection(EHFrameAddr);
458 }
459 
460 Error LocalEHFrameRegistrationPlugin::notifyRemovingAllModules() {
461 
462   std::vector<const void *> EHFrameAddrs = std::move(UntrackedEHFrameAddrs);
463   EHFrameAddrs.reserve(EHFrameAddrs.size() + TrackedEHFrameAddrs.size());
464 
465   for (auto &KV : TrackedEHFrameAddrs)
466     EHFrameAddrs.push_back(KV.second);
467 
468   TrackedEHFrameAddrs.clear();
469 
470   Error Err = Error::success();
471 
472   while (!EHFrameAddrs.empty()) {
473     const void *EHFrameAddr = EHFrameAddrs.back();
474     assert(EHFrameAddr && "Untracked eh-frame addr must not be null");
475     EHFrameAddrs.pop_back();
476     Err = joinErrors(std::move(Err), deregisterEHFrameSection(EHFrameAddr));
477   }
478 
479   return Err;
480 }
481 
482 } // End namespace orc.
483 } // End namespace llvm.
484