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:
ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer & Layer,MaterializationResponsibility MR,std::unique_ptr<MemoryBuffer> ObjBuffer)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 
getMemoryManager()32   JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
33 
getObjectBuffer() const34   MemoryBufferRef getObjectBuffer() const override {
35     return ObjBuffer->getMemBufferRef();
36   }
37 
notifyFailed(Error Err)38   void notifyFailed(Error Err) override {
39     Layer.getExecutionSession().reportError(std::move(Err));
40     MR.failMaterialization();
41   }
42 
lookup(const DenseSet<StringRef> & Symbols,JITLinkAsyncLookupContinuation LookupContinuation)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(SearchOrder, std::move(InternedSymbols), SymbolState::Resolved,
73               std::move(OnResolve), [this](const SymbolDependenceMap &Deps) {
74                 registerDependencies(Deps);
75               });
76   }
77 
notifyResolved(AtomGraph & G)78   void notifyResolved(AtomGraph &G) override {
79     auto &ES = Layer.getExecutionSession();
80 
81     SymbolFlagsMap ExtraSymbolsToClaim;
82     bool AutoClaim = Layer.AutoClaimObjectSymbols;
83 
84     SymbolMap InternedResult;
85     for (auto *DA : G.defined_atoms())
86       if (DA->hasName() && DA->isGlobal()) {
87         auto InternedName = ES.intern(DA->getName());
88         JITSymbolFlags Flags;
89 
90         if (DA->isExported())
91           Flags |= JITSymbolFlags::Exported;
92         if (DA->isWeak())
93           Flags |= JITSymbolFlags::Weak;
94         if (DA->isCallable())
95           Flags |= JITSymbolFlags::Callable;
96         if (DA->isCommon())
97           Flags |= JITSymbolFlags::Common;
98 
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;
105         }
106       }
107 
108     for (auto *A : G.absolute_atoms())
109       if (A->hasName()) {
110         auto InternedName = ES.intern(A->getName());
111         JITSymbolFlags Flags;
112         Flags |= JITSymbolFlags::Absolute;
113         if (A->isWeak())
114           Flags |= JITSymbolFlags::Weak;
115         if (A->isCallable())
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;
123         }
124       }
125 
126     if (!ExtraSymbolsToClaim.empty())
127       if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim))
128         return notifyFailed(std::move(Err));
129 
130     MR.notifyResolved(InternedResult);
131 
132     Layer.notifyLoaded(MR);
133   }
134 
notifyFinalized(std::unique_ptr<JITLinkMemoryManager::Allocation> A)135   void notifyFinalized(
136       std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
137 
138     if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
139       Layer.getExecutionSession().reportError(std::move(Err));
140       MR.failMaterialization();
141 
142       return;
143     }
144     MR.notifyEmitted();
145   }
146 
getMarkLivePass(const Triple & TT) const147   AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override {
148     return [this](AtomGraph &G) { return markResponsibilitySymbolsLive(G); };
149   }
150 
modifyPassConfig(const Triple & TT,PassConfiguration & Config)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); });
158 
159     Layer.modifyPassConfig(MR, TT, Config);
160 
161     return Error::success();
162   }
163 
164 private:
165   using AnonAtomNamedDependenciesMap =
166       DenseMap<const DefinedAtom *, SymbolNameSet>;
167 
markSymbolsToDiscard(AtomGraph & G)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);
176       }
177 
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);
184       }
185 
186     return Error::success();
187   }
188 
markResponsibilitySymbolsLive(AtomGraph & G) const189   Error markResponsibilitySymbolsLive(AtomGraph &G) const {
190     auto &ES = Layer.getExecutionSession();
191     for (auto *DA : G.defined_atoms())
192       if (DA->hasName() &&
193           MR.getSymbols().count(ES.intern(DA->getName())))
194         DA->setLive(true);
195     return Error::success();
196   }
197 
computeNamedSymbolDependencies(AtomGraph & G)198   Error computeNamedSymbolDependencies(AtomGraph &G) {
199     auto &ES = MR.getTargetJITDylib().getExecutionSession();
200     auto AnonDeps = computeAnonDeps(G);
201 
202     for (auto *DA : G.defined_atoms()) {
203 
204       // Skip anonymous and non-global atoms: we do not need dependencies for
205       // these.
206       if (!DA->hasName() || !DA->isGlobal())
207         continue;
208 
209       auto DAName = ES.intern(DA->getName());
210       SymbolNameSet &DADeps = NamedSymbolDeps[DAName];
211 
212       for (auto &E : DA->edges()) {
213         auto &TA = E.getTarget();
214 
215         if (TA.hasName())
216           DADeps.insert(ES.intern(TA.getName()));
217         else {
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)
223               DADeps.insert(S);
224         }
225       }
226     }
227 
228     return Error::success();
229   }
230 
computeAnonDeps(AtomGraph & G)231   AnonAtomNamedDependenciesMap computeAnonDeps(AtomGraph &G) {
232 
233     auto &ES = MR.getTargetJITDylib().getExecutionSession();
234     AnonAtomNamedDependenciesMap DepMap;
235 
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)) {}
243 
244       DefinedAtom *DA = nullptr;
245       DenseSet<DefinedAtom *> DAAnonDeps;
246     };
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;
252 
253         for (auto &E : DA->edges()) {
254           auto &TA = E.getTarget();
255           if (TA.hasName())
256             DANamedDeps.insert(ES.intern(TA.getName()));
257           else {
258             assert(TA.isDefined() && "Anonymous atoms must be defined");
259             DAAnonDeps.insert(static_cast<DefinedAtom *>(&TA));
260           }
261         }
262 
263         if (!DAAnonDeps.empty())
264           Worklist.push_back(WorklistEntry(DA, std::move(DAAnonDeps)));
265       }
266 
267     // Loop over all anonymous atoms with anonymous dependencies, propagating
268     // their respective *named* dependencies. Iterate until we hit a stable
269     // state.
270     bool Changed;
271     do {
272       Changed = false;
273       for (auto &WLEntry : Worklist) {
274         auto *DA = WLEntry.DA;
275         auto &DANamedDeps = DepMap[DA];
276         auto &DAAnonDeps = WLEntry.DAAnonDeps;
277 
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;
283         }
284       }
285     } while (Changed);
286 
287     return DepMap;
288   }
289 
registerDependencies(const SymbolDependenceMap & QueryDeps)290   void registerDependencies(const SymbolDependenceMap &QueryDeps) {
291     for (auto &NamedDepsEntry : NamedSymbolDeps) {
292       auto &Name = NamedDepsEntry.first;
293       auto &NameDeps = NamedDepsEntry.second;
294       SymbolDependenceMap SymbolDeps;
295 
296       for (const auto &QueryDepsEntry : QueryDeps) {
297         JITDylib &SourceJD = *QueryDepsEntry.first;
298         const SymbolNameSet &Symbols = QueryDepsEntry.second;
299         auto &DepsForJD = SymbolDeps[&SourceJD];
300 
301         for (const auto &S : Symbols)
302           if (NameDeps.count(S))
303             DepsForJD.insert(S);
304 
305         if (DepsForJD.empty())
306           SymbolDeps.erase(&SourceJD);
307       }
308 
309       MR.addDependencies(Name, SymbolDeps);
310     }
311   }
312 
313   ObjectLinkingLayer &Layer;
314   MaterializationResponsibility MR;
315   std::unique_ptr<MemoryBuffer> ObjBuffer;
316   DenseMap<SymbolStringPtr, SymbolNameSet> NamedSymbolDeps;
317 };
318 
~Plugin()319 ObjectLinkingLayer::Plugin::~Plugin() {}
320 
ObjectLinkingLayer(ExecutionSession & ES,JITLinkMemoryManager & MemMgr)321 ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES,
322                                        JITLinkMemoryManager &MemMgr)
323     : ObjectLayer(ES), MemMgr(MemMgr) {}
324 
~ObjectLinkingLayer()325 ObjectLinkingLayer::~ObjectLinkingLayer() {
326   if (auto Err = removeAllModules())
327     getExecutionSession().reportError(std::move(Err));
328 }
329 
emit(MaterializationResponsibility R,std::unique_ptr<MemoryBuffer> O)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)));
335 }
336 
modifyPassConfig(MaterializationResponsibility & MR,const Triple & TT,PassConfiguration & PassConfig)337 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
338                                           const Triple &TT,
339                                           PassConfiguration &PassConfig) {
340   for (auto &P : Plugins)
341     P->modifyPassConfig(MR, TT, PassConfig);
342 }
343 
notifyLoaded(MaterializationResponsibility & MR)344 void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
345   for (auto &P : Plugins)
346     P->notifyLoaded(MR);
347 }
348 
notifyEmitted(MaterializationResponsibility & MR,AllocPtr Alloc)349 Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR,
350                                         AllocPtr Alloc) {
351   Error Err = Error::success();
352   for (auto &P : Plugins)
353     Err = joinErrors(std::move(Err), P->notifyEmitted(MR));
354 
355   if (Err)
356     return Err;
357 
358   {
359     std::lock_guard<std::mutex> Lock(LayerMutex);
360     UntrackedAllocs.push_back(std::move(Alloc));
361   }
362 
363   return Error::success();
364 }
365 
removeModule(VModuleKey K)366 Error ObjectLinkingLayer::removeModule(VModuleKey K) {
367   Error Err = Error::success();
368 
369   for (auto &P : Plugins)
370     Err = joinErrors(std::move(Err), P->notifyRemovingModule(K));
371 
372   AllocPtr Alloc;
373 
374   {
375     std::lock_guard<std::mutex> Lock(LayerMutex);
376     auto AllocItr = TrackedAllocs.find(K);
377     Alloc = std::move(AllocItr->second);
378     TrackedAllocs.erase(AllocItr);
379   }
380 
381   assert(Alloc && "No allocation for key K");
382 
383   return joinErrors(std::move(Err), Alloc->deallocate());
384 }
385 
removeAllModules()386 Error ObjectLinkingLayer::removeAllModules() {
387 
388   Error Err = Error::success();
389 
390   for (auto &P : Plugins)
391     Err = joinErrors(std::move(Err), P->notifyRemovingAllModules());
392 
393   std::vector<AllocPtr> Allocs;
394   {
395     std::lock_guard<std::mutex> Lock(LayerMutex);
396     Allocs = std::move(UntrackedAllocs);
397 
398     for (auto &KV : TrackedAllocs)
399       Allocs.push_back(std::move(KV.second));
400 
401     TrackedAllocs.clear();
402   }
403 
404   while (!Allocs.empty()) {
405     Err = joinErrors(std::move(Err), Allocs.back()->deallocate());
406     Allocs.pop_back();
407   }
408 
409   return Err;
410 }
411 
EHFrameRegistrationPlugin(jitlink::EHFrameRegistrar & Registrar)412 EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
413     jitlink::EHFrameRegistrar &Registrar)
414     : Registrar(Registrar) {}
415 
modifyPassConfig(MaterializationResponsibility & MR,const Triple & TT,PassConfiguration & PassConfig)416 void EHFrameRegistrationPlugin::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] = Addr;
425       }));
426 }
427 
notifyEmitted(MaterializationResponsibility & MR)428 Error EHFrameRegistrationPlugin::notifyEmitted(
429     MaterializationResponsibility &MR) {
430 
431   auto EHFrameAddrItr = InProcessLinks.find(&MR);
432   if (EHFrameAddrItr == InProcessLinks.end())
433     return Error::success();
434 
435   auto 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 Registrar.registerEHFrames(EHFrameAddr);
445 }
446 
notifyRemovingModule(VModuleKey K)447 Error EHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) {
448   auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K);
449   if (EHFrameAddrItr == TrackedEHFrameAddrs.end())
450     return Error::success();
451 
452   auto EHFrameAddr = EHFrameAddrItr->second;
453   assert(EHFrameAddr && "Tracked eh-frame addr must not be null");
454 
455   TrackedEHFrameAddrs.erase(EHFrameAddrItr);
456 
457   return Registrar.deregisterEHFrames(EHFrameAddr);
458 }
459 
notifyRemovingAllModules()460 Error EHFrameRegistrationPlugin::notifyRemovingAllModules() {
461 
462   std::vector<JITTargetAddress> 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     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));
477   }
478 
479   return Err;
480 }
481 
482 } // End namespace orc.
483 } // End namespace llvm.
484