• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~ObjectLinkingLayerJITLinkContext()32   ~ObjectLinkingLayerJITLinkContext() {
33     // If there is an object buffer return function then use it to
34     // return ownership of the buffer.
35     if (Layer.ReturnObjectBuffer)
36       Layer.ReturnObjectBuffer(std::move(ObjBuffer));
37   }
38 
getMemoryManager()39   JITLinkMemoryManager &getMemoryManager() override { return *Layer.MemMgr; }
40 
getObjectBuffer() const41   MemoryBufferRef getObjectBuffer() const override {
42     return ObjBuffer->getMemBufferRef();
43   }
44 
notifyFailed(Error Err)45   void notifyFailed(Error Err) override {
46     Layer.getExecutionSession().reportError(std::move(Err));
47     MR.failMaterialization();
48   }
49 
lookup(const LookupMap & Symbols,std::unique_ptr<JITLinkAsyncLookupContinuation> LC)50   void lookup(const LookupMap &Symbols,
51               std::unique_ptr<JITLinkAsyncLookupContinuation> LC) override {
52 
53     JITDylibSearchOrder SearchOrder;
54     MR.getTargetJITDylib().withSearchOrderDo(
55         [&](const JITDylibSearchOrder &O) { SearchOrder = O; });
56 
57     auto &ES = Layer.getExecutionSession();
58 
59     SymbolLookupSet LookupSet;
60     for (auto &KV : Symbols) {
61       orc::SymbolLookupFlags LookupFlags;
62       switch (KV.second) {
63       case jitlink::SymbolLookupFlags::RequiredSymbol:
64         LookupFlags = orc::SymbolLookupFlags::RequiredSymbol;
65         break;
66       case jitlink::SymbolLookupFlags::WeaklyReferencedSymbol:
67         LookupFlags = orc::SymbolLookupFlags::WeaklyReferencedSymbol;
68         break;
69       }
70       LookupSet.add(ES.intern(KV.first), LookupFlags);
71     }
72 
73     // OnResolve -- De-intern the symbols and pass the result to the linker.
74     auto OnResolve = [this, LookupContinuation = std::move(LC)](
75                          Expected<SymbolMap> Result) mutable {
76       auto Main = Layer.getExecutionSession().intern("_main");
77       if (!Result)
78         LookupContinuation->run(Result.takeError());
79       else {
80         AsyncLookupResult LR;
81         for (auto &KV : *Result)
82           LR[*KV.first] = KV.second;
83         LookupContinuation->run(std::move(LR));
84       }
85     };
86 
87     ES.lookup(LookupKind::Static, SearchOrder, std::move(LookupSet),
88               SymbolState::Resolved, std::move(OnResolve),
89               [this](const SymbolDependenceMap &Deps) {
90                 registerDependencies(Deps);
91               });
92   }
93 
notifyResolved(LinkGraph & G)94   void notifyResolved(LinkGraph &G) override {
95     auto &ES = Layer.getExecutionSession();
96 
97     SymbolFlagsMap ExtraSymbolsToClaim;
98     bool AutoClaim = Layer.AutoClaimObjectSymbols;
99 
100     SymbolMap InternedResult;
101     for (auto *Sym : G.defined_symbols())
102       if (Sym->hasName() && Sym->getScope() != Scope::Local) {
103         auto InternedName = ES.intern(Sym->getName());
104         JITSymbolFlags Flags;
105 
106         if (Sym->isCallable())
107           Flags |= JITSymbolFlags::Callable;
108         if (Sym->getScope() == Scope::Default)
109           Flags |= JITSymbolFlags::Exported;
110 
111         InternedResult[InternedName] =
112             JITEvaluatedSymbol(Sym->getAddress(), Flags);
113         if (AutoClaim && !MR.getSymbols().count(InternedName)) {
114           assert(!ExtraSymbolsToClaim.count(InternedName) &&
115                  "Duplicate symbol to claim?");
116           ExtraSymbolsToClaim[InternedName] = Flags;
117         }
118       }
119 
120     for (auto *Sym : G.absolute_symbols())
121       if (Sym->hasName()) {
122         auto InternedName = ES.intern(Sym->getName());
123         JITSymbolFlags Flags;
124         Flags |= JITSymbolFlags::Absolute;
125         if (Sym->isCallable())
126           Flags |= JITSymbolFlags::Callable;
127         if (Sym->getLinkage() == Linkage::Weak)
128           Flags |= JITSymbolFlags::Weak;
129         InternedResult[InternedName] =
130             JITEvaluatedSymbol(Sym->getAddress(), Flags);
131         if (AutoClaim && !MR.getSymbols().count(InternedName)) {
132           assert(!ExtraSymbolsToClaim.count(InternedName) &&
133                  "Duplicate symbol to claim?");
134           ExtraSymbolsToClaim[InternedName] = Flags;
135         }
136       }
137 
138     if (!ExtraSymbolsToClaim.empty())
139       if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim))
140         return notifyFailed(std::move(Err));
141     if (auto Err = MR.notifyResolved(InternedResult)) {
142       Layer.getExecutionSession().reportError(std::move(Err));
143       MR.failMaterialization();
144       return;
145     }
146     Layer.notifyLoaded(MR);
147   }
148 
notifyFinalized(std::unique_ptr<JITLinkMemoryManager::Allocation> A)149   void notifyFinalized(
150       std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
151     if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
152       Layer.getExecutionSession().reportError(std::move(Err));
153       MR.failMaterialization();
154       return;
155     }
156     if (auto Err = MR.notifyEmitted()) {
157       Layer.getExecutionSession().reportError(std::move(Err));
158       MR.failMaterialization();
159     }
160   }
161 
getMarkLivePass(const Triple & TT) const162   LinkGraphPassFunction getMarkLivePass(const Triple &TT) const override {
163     return [this](LinkGraph &G) { return markResponsibilitySymbolsLive(G); };
164   }
165 
modifyPassConfig(const Triple & TT,PassConfiguration & Config)166   Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override {
167     // Add passes to mark duplicate defs as should-discard, and to walk the
168     // link graph to build the symbol dependence graph.
169     Config.PrePrunePasses.push_back(
170         [this](LinkGraph &G) { return externalizeWeakAndCommonSymbols(G); });
171     Config.PostPrunePasses.push_back(
172         [this](LinkGraph &G) { return computeNamedSymbolDependencies(G); });
173 
174     Layer.modifyPassConfig(MR, TT, Config);
175 
176     return Error::success();
177   }
178 
179 private:
180   using AnonToNamedDependenciesMap = DenseMap<const Symbol *, SymbolNameSet>;
181 
externalizeWeakAndCommonSymbols(LinkGraph & G)182   Error externalizeWeakAndCommonSymbols(LinkGraph &G) {
183     auto &ES = Layer.getExecutionSession();
184     for (auto *Sym : G.defined_symbols())
185       if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak) {
186         if (!MR.getSymbols().count(ES.intern(Sym->getName())))
187           G.makeExternal(*Sym);
188       }
189 
190     for (auto *Sym : G.absolute_symbols())
191       if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak) {
192         if (!MR.getSymbols().count(ES.intern(Sym->getName())))
193           G.makeExternal(*Sym);
194       }
195 
196     return Error::success();
197   }
198 
markResponsibilitySymbolsLive(LinkGraph & G) const199   Error markResponsibilitySymbolsLive(LinkGraph &G) const {
200     auto &ES = Layer.getExecutionSession();
201     for (auto *Sym : G.defined_symbols())
202       if (Sym->hasName() && MR.getSymbols().count(ES.intern(Sym->getName())))
203         Sym->setLive(true);
204     return Error::success();
205   }
206 
computeNamedSymbolDependencies(LinkGraph & G)207   Error computeNamedSymbolDependencies(LinkGraph &G) {
208     auto &ES = MR.getTargetJITDylib().getExecutionSession();
209     auto AnonDeps = computeAnonDeps(G);
210 
211     for (auto *Sym : G.defined_symbols()) {
212 
213       // Skip anonymous and non-global atoms: we do not need dependencies for
214       // these.
215       if (Sym->getScope() == Scope::Local)
216         continue;
217 
218       auto SymName = ES.intern(Sym->getName());
219       SymbolNameSet &SymDeps = NamedSymbolDeps[SymName];
220 
221       for (auto &E : Sym->getBlock().edges()) {
222         auto &TargetSym = E.getTarget();
223 
224         if (TargetSym.getScope() != Scope::Local)
225           SymDeps.insert(ES.intern(TargetSym.getName()));
226         else {
227           assert(TargetSym.isDefined() &&
228                  "Anonymous/local symbols must be defined");
229           auto I = AnonDeps.find(&TargetSym);
230           if (I != AnonDeps.end())
231             for (auto &S : I->second)
232               SymDeps.insert(S);
233         }
234       }
235     }
236 
237     return Error::success();
238   }
239 
computeAnonDeps(LinkGraph & G)240   AnonToNamedDependenciesMap computeAnonDeps(LinkGraph &G) {
241 
242     auto &ES = MR.getTargetJITDylib().getExecutionSession();
243     AnonToNamedDependenciesMap DepMap;
244 
245     // For all anonymous symbols:
246     // (1) Add their named dependencies.
247     // (2) Add them to the worklist for further iteration if they have any
248     //     depend on any other anonymous symbols.
249     struct WorklistEntry {
250       WorklistEntry(Symbol *Sym, DenseSet<Symbol *> SymAnonDeps)
251           : Sym(Sym), SymAnonDeps(std::move(SymAnonDeps)) {}
252 
253       Symbol *Sym = nullptr;
254       DenseSet<Symbol *> SymAnonDeps;
255     };
256     std::vector<WorklistEntry> Worklist;
257     for (auto *Sym : G.defined_symbols())
258       if (!Sym->hasName()) {
259         auto &SymNamedDeps = DepMap[Sym];
260         DenseSet<Symbol *> SymAnonDeps;
261 
262         for (auto &E : Sym->getBlock().edges()) {
263           auto &TargetSym = E.getTarget();
264           if (TargetSym.hasName())
265             SymNamedDeps.insert(ES.intern(TargetSym.getName()));
266           else {
267             assert(TargetSym.isDefined() &&
268                    "Anonymous symbols must be defined");
269             SymAnonDeps.insert(&TargetSym);
270           }
271         }
272 
273         if (!SymAnonDeps.empty())
274           Worklist.push_back(WorklistEntry(Sym, std::move(SymAnonDeps)));
275       }
276 
277     // Loop over all anonymous symbols with anonymous dependencies, propagating
278     // their respective *named* dependencies. Iterate until we hit a stable
279     // state.
280     bool Changed;
281     do {
282       Changed = false;
283       for (auto &WLEntry : Worklist) {
284         auto *Sym = WLEntry.Sym;
285         auto &SymNamedDeps = DepMap[Sym];
286         auto &SymAnonDeps = WLEntry.SymAnonDeps;
287 
288         for (auto *TargetSym : SymAnonDeps) {
289           auto I = DepMap.find(TargetSym);
290           if (I != DepMap.end())
291             for (const auto &S : I->second)
292               Changed |= SymNamedDeps.insert(S).second;
293         }
294       }
295     } while (Changed);
296 
297     return DepMap;
298   }
299 
registerDependencies(const SymbolDependenceMap & QueryDeps)300   void registerDependencies(const SymbolDependenceMap &QueryDeps) {
301     for (auto &NamedDepsEntry : NamedSymbolDeps) {
302       auto &Name = NamedDepsEntry.first;
303       auto &NameDeps = NamedDepsEntry.second;
304       SymbolDependenceMap SymbolDeps;
305 
306       for (const auto &QueryDepsEntry : QueryDeps) {
307         JITDylib &SourceJD = *QueryDepsEntry.first;
308         const SymbolNameSet &Symbols = QueryDepsEntry.second;
309         auto &DepsForJD = SymbolDeps[&SourceJD];
310 
311         for (const auto &S : Symbols)
312           if (NameDeps.count(S))
313             DepsForJD.insert(S);
314 
315         if (DepsForJD.empty())
316           SymbolDeps.erase(&SourceJD);
317       }
318 
319       MR.addDependencies(Name, SymbolDeps);
320     }
321   }
322 
323   ObjectLinkingLayer &Layer;
324   MaterializationResponsibility MR;
325   std::unique_ptr<MemoryBuffer> ObjBuffer;
326   DenseMap<SymbolStringPtr, SymbolNameSet> NamedSymbolDeps;
327 };
328 
~Plugin()329 ObjectLinkingLayer::Plugin::~Plugin() {}
330 
ObjectLinkingLayer(ExecutionSession & ES,std::unique_ptr<JITLinkMemoryManager> MemMgr)331 ObjectLinkingLayer::ObjectLinkingLayer(
332     ExecutionSession &ES, std::unique_ptr<JITLinkMemoryManager> MemMgr)
333     : ObjectLayer(ES), MemMgr(std::move(MemMgr)) {}
334 
~ObjectLinkingLayer()335 ObjectLinkingLayer::~ObjectLinkingLayer() {
336   if (auto Err = removeAllModules())
337     getExecutionSession().reportError(std::move(Err));
338 }
339 
emit(MaterializationResponsibility R,std::unique_ptr<MemoryBuffer> O)340 void ObjectLinkingLayer::emit(MaterializationResponsibility R,
341                               std::unique_ptr<MemoryBuffer> O) {
342   assert(O && "Object must not be null");
343   jitLink(std::make_unique<ObjectLinkingLayerJITLinkContext>(
344       *this, std::move(R), std::move(O)));
345 }
346 
modifyPassConfig(MaterializationResponsibility & MR,const Triple & TT,PassConfiguration & PassConfig)347 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
348                                           const Triple &TT,
349                                           PassConfiguration &PassConfig) {
350   for (auto &P : Plugins)
351     P->modifyPassConfig(MR, TT, PassConfig);
352 }
353 
notifyLoaded(MaterializationResponsibility & MR)354 void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
355   for (auto &P : Plugins)
356     P->notifyLoaded(MR);
357 }
358 
notifyEmitted(MaterializationResponsibility & MR,AllocPtr Alloc)359 Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR,
360                                         AllocPtr Alloc) {
361   Error Err = Error::success();
362   for (auto &P : Plugins)
363     Err = joinErrors(std::move(Err), P->notifyEmitted(MR));
364 
365   if (Err)
366     return Err;
367 
368   {
369     std::lock_guard<std::mutex> Lock(LayerMutex);
370     UntrackedAllocs.push_back(std::move(Alloc));
371   }
372 
373   return Error::success();
374 }
375 
removeModule(VModuleKey K)376 Error ObjectLinkingLayer::removeModule(VModuleKey K) {
377   Error Err = Error::success();
378 
379   for (auto &P : Plugins)
380     Err = joinErrors(std::move(Err), P->notifyRemovingModule(K));
381 
382   AllocPtr Alloc;
383 
384   {
385     std::lock_guard<std::mutex> Lock(LayerMutex);
386     auto AllocItr = TrackedAllocs.find(K);
387     Alloc = std::move(AllocItr->second);
388     TrackedAllocs.erase(AllocItr);
389   }
390 
391   assert(Alloc && "No allocation for key K");
392 
393   return joinErrors(std::move(Err), Alloc->deallocate());
394 }
395 
removeAllModules()396 Error ObjectLinkingLayer::removeAllModules() {
397 
398   Error Err = Error::success();
399 
400   for (auto &P : Plugins)
401     Err = joinErrors(std::move(Err), P->notifyRemovingAllModules());
402 
403   std::vector<AllocPtr> Allocs;
404   {
405     std::lock_guard<std::mutex> Lock(LayerMutex);
406     Allocs = std::move(UntrackedAllocs);
407 
408     for (auto &KV : TrackedAllocs)
409       Allocs.push_back(std::move(KV.second));
410 
411     TrackedAllocs.clear();
412   }
413 
414   while (!Allocs.empty()) {
415     Err = joinErrors(std::move(Err), Allocs.back()->deallocate());
416     Allocs.pop_back();
417   }
418 
419   return Err;
420 }
421 
EHFrameRegistrationPlugin(EHFrameRegistrar & Registrar)422 EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
423     EHFrameRegistrar &Registrar)
424     : Registrar(Registrar) {}
425 
modifyPassConfig(MaterializationResponsibility & MR,const Triple & TT,PassConfiguration & PassConfig)426 void EHFrameRegistrationPlugin::modifyPassConfig(
427     MaterializationResponsibility &MR, const Triple &TT,
428     PassConfiguration &PassConfig) {
429   assert(!InProcessLinks.count(&MR) && "Link for MR already being tracked?");
430 
431   PassConfig.PostFixupPasses.push_back(
432       createEHFrameRecorderPass(TT, [this, &MR](JITTargetAddress Addr,
433                                                 size_t Size) {
434         if (Addr)
435           InProcessLinks[&MR] = { Addr, Size };
436       }));
437 }
438 
notifyEmitted(MaterializationResponsibility & MR)439 Error EHFrameRegistrationPlugin::notifyEmitted(
440     MaterializationResponsibility &MR) {
441 
442   auto EHFrameRangeItr = InProcessLinks.find(&MR);
443   if (EHFrameRangeItr == InProcessLinks.end())
444     return Error::success();
445 
446   auto EHFrameRange = EHFrameRangeItr->second;
447   assert(EHFrameRange.Addr &&
448          "eh-frame addr to register can not be null");
449 
450   InProcessLinks.erase(EHFrameRangeItr);
451   if (auto Key = MR.getVModuleKey())
452     TrackedEHFrameRanges[Key] = EHFrameRange;
453   else
454     UntrackedEHFrameRanges.push_back(EHFrameRange);
455 
456   return Registrar.registerEHFrames(EHFrameRange.Addr, EHFrameRange.Size);
457 }
458 
notifyRemovingModule(VModuleKey K)459 Error EHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) {
460   auto EHFrameRangeItr = TrackedEHFrameRanges.find(K);
461   if (EHFrameRangeItr == TrackedEHFrameRanges.end())
462     return Error::success();
463 
464   auto EHFrameRange = EHFrameRangeItr->second;
465   assert(EHFrameRange.Addr && "Tracked eh-frame range must not be null");
466 
467   TrackedEHFrameRanges.erase(EHFrameRangeItr);
468 
469   return Registrar.deregisterEHFrames(EHFrameRange.Addr, EHFrameRange.Size);
470 }
471 
notifyRemovingAllModules()472 Error EHFrameRegistrationPlugin::notifyRemovingAllModules() {
473 
474   std::vector<EHFrameRange> EHFrameRanges =
475     std::move(UntrackedEHFrameRanges);
476   EHFrameRanges.reserve(EHFrameRanges.size() + TrackedEHFrameRanges.size());
477 
478   for (auto &KV : TrackedEHFrameRanges)
479     EHFrameRanges.push_back(KV.second);
480 
481   TrackedEHFrameRanges.clear();
482 
483   Error Err = Error::success();
484 
485   while (!EHFrameRanges.empty()) {
486     auto EHFrameRange = EHFrameRanges.back();
487     assert(EHFrameRange.Addr && "Untracked eh-frame range must not be null");
488     EHFrameRanges.pop_back();
489     Err = joinErrors(std::move(Err),
490                      Registrar.deregisterEHFrames(EHFrameRange.Addr,
491                                                   EHFrameRange.Size));
492   }
493 
494   return Err;
495 }
496 
497 } // End namespace orc.
498 } // End namespace llvm.
499