xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp (revision 1233c15be59160eb48bec08327db012bc3f2aedf)
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     if (Layer.NotifyLoaded)
137       Layer.NotifyLoaded(MR.getVModuleKey());
138   }
139 
140   void notifyFinalized(
141       std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
142 
143     if (EHFrameAddr) {
144       // If there is an eh-frame then try to register it.
145       if (auto Err = registerEHFrameSection((void *)EHFrameAddr)) {
146         Layer.getExecutionSession().reportError(std::move(Err));
147         MR.failMaterialization();
148         return;
149       }
150     }
151 
152     MR.emit();
153     Layer.notifyFinalized(
154         ObjectLinkingLayer::ObjectResources(std::move(A), EHFrameAddr));
155   }
156 
157   AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override {
158     return [this](AtomGraph &G) { return markResponsibilitySymbolsLive(G); };
159   }
160 
161   Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override {
162     // Add passes to mark duplicate defs as should-discard, and to walk the
163     // atom graph to build the symbol dependence graph.
164     Config.PrePrunePasses.push_back(
165         [this](AtomGraph &G) { return markSymbolsToDiscard(G); });
166     Config.PostPrunePasses.push_back(
167         [this](AtomGraph &G) { return computeNamedSymbolDependencies(G); });
168 
169     Config.PostFixupPasses.push_back(
170         createEHFrameRecorderPass(TT, EHFrameAddr));
171 
172     if (Layer.ModifyPassConfig)
173       Layer.ModifyPassConfig(TT, Config);
174 
175     return Error::success();
176   }
177 
178 private:
179   using AnonAtomNamedDependenciesMap =
180       DenseMap<const DefinedAtom *, SymbolNameSet>;
181 
182   Error markSymbolsToDiscard(AtomGraph &G) {
183     auto &ES = Layer.getExecutionSession();
184     for (auto *DA : G.defined_atoms())
185       if (DA->isWeak() && DA->hasName()) {
186         auto S = ES.intern(DA->getName());
187         auto I = MR.getSymbols().find(S);
188         if (I == MR.getSymbols().end())
189           DA->setShouldDiscard(true);
190       }
191 
192     for (auto *A : G.absolute_atoms())
193       if (A->isWeak() && A->hasName()) {
194         auto S = ES.intern(A->getName());
195         auto I = MR.getSymbols().find(S);
196         if (I == MR.getSymbols().end())
197           A->setShouldDiscard(true);
198       }
199 
200     return Error::success();
201   }
202 
203   Error markResponsibilitySymbolsLive(AtomGraph &G) const {
204     auto &ES = Layer.getExecutionSession();
205     for (auto *DA : G.defined_atoms())
206       if (DA->hasName() &&
207           MR.getSymbols().count(ES.intern(DA->getName())))
208         DA->setLive(true);
209     return Error::success();
210   }
211 
212   Error computeNamedSymbolDependencies(AtomGraph &G) {
213     auto &ES = MR.getTargetJITDylib().getExecutionSession();
214     auto AnonDeps = computeAnonDeps(G);
215 
216     for (auto *DA : G.defined_atoms()) {
217 
218       // Skip anonymous and non-global atoms: we do not need dependencies for
219       // these.
220       if (!DA->hasName() || !DA->isGlobal())
221         continue;
222 
223       auto DAName = ES.intern(DA->getName());
224       SymbolNameSet &DADeps = NamedSymbolDeps[DAName];
225 
226       for (auto &E : DA->edges()) {
227         auto &TA = E.getTarget();
228 
229         if (TA.hasName())
230           DADeps.insert(ES.intern(TA.getName()));
231         else {
232           assert(TA.isDefined() && "Anonymous atoms must be defined");
233           auto &DTA = static_cast<DefinedAtom &>(TA);
234           auto I = AnonDeps.find(&DTA);
235           if (I != AnonDeps.end())
236             for (auto &S : I->second)
237               DADeps.insert(S);
238         }
239       }
240     }
241 
242     return Error::success();
243   }
244 
245   AnonAtomNamedDependenciesMap computeAnonDeps(AtomGraph &G) {
246 
247     auto &ES = MR.getTargetJITDylib().getExecutionSession();
248     AnonAtomNamedDependenciesMap DepMap;
249 
250     // For all anonymous atoms:
251     // (1) Add their named dependencies.
252     // (2) Add them to the worklist for further iteration if they have any
253     //     depend on any other anonymous atoms.
254     struct WorklistEntry {
255       WorklistEntry(DefinedAtom *DA, DenseSet<DefinedAtom *> DAAnonDeps)
256           : DA(DA), DAAnonDeps(std::move(DAAnonDeps)) {}
257 
258       DefinedAtom *DA = nullptr;
259       DenseSet<DefinedAtom *> DAAnonDeps;
260     };
261     std::vector<WorklistEntry> Worklist;
262     for (auto *DA : G.defined_atoms())
263       if (!DA->hasName()) {
264         auto &DANamedDeps = DepMap[DA];
265         DenseSet<DefinedAtom *> DAAnonDeps;
266 
267         for (auto &E : DA->edges()) {
268           auto &TA = E.getTarget();
269           if (TA.hasName())
270             DANamedDeps.insert(ES.intern(TA.getName()));
271           else {
272             assert(TA.isDefined() && "Anonymous atoms must be defined");
273             DAAnonDeps.insert(static_cast<DefinedAtom *>(&TA));
274           }
275         }
276 
277         if (!DAAnonDeps.empty())
278           Worklist.push_back(WorklistEntry(DA, std::move(DAAnonDeps)));
279       }
280 
281     // Loop over all anonymous atoms with anonymous dependencies, propagating
282     // their respective *named* dependencies. Iterate until we hit a stable
283     // state.
284     bool Changed;
285     do {
286       Changed = false;
287       for (auto &WLEntry : Worklist) {
288         auto *DA = WLEntry.DA;
289         auto &DANamedDeps = DepMap[DA];
290         auto &DAAnonDeps = WLEntry.DAAnonDeps;
291 
292         for (auto *TA : DAAnonDeps) {
293           auto I = DepMap.find(TA);
294           if (I != DepMap.end())
295             for (const auto &S : I->second)
296               Changed |= DANamedDeps.insert(S).second;
297         }
298       }
299     } while (Changed);
300 
301     return DepMap;
302   }
303 
304   void registerDependencies(const SymbolDependenceMap &QueryDeps) {
305     for (auto &NamedDepsEntry : NamedSymbolDeps) {
306       auto &Name = NamedDepsEntry.first;
307       auto &NameDeps = NamedDepsEntry.second;
308       SymbolDependenceMap SymbolDeps;
309 
310       for (const auto &QueryDepsEntry : QueryDeps) {
311         JITDylib &SourceJD = *QueryDepsEntry.first;
312         const SymbolNameSet &Symbols = QueryDepsEntry.second;
313         auto &DepsForJD = SymbolDeps[&SourceJD];
314 
315         for (const auto &S : Symbols)
316           if (NameDeps.count(S))
317             DepsForJD.insert(S);
318 
319         if (DepsForJD.empty())
320           SymbolDeps.erase(&SourceJD);
321       }
322 
323       MR.addDependencies(Name, SymbolDeps);
324     }
325   }
326 
327   ObjectLinkingLayer &Layer;
328   MaterializationResponsibility MR;
329   std::unique_ptr<MemoryBuffer> ObjBuffer;
330   DenseMap<SymbolStringPtr, SymbolNameSet> NamedSymbolDeps;
331   JITTargetAddress EHFrameAddr = 0;
332 };
333 
334 ObjectLinkingLayer::ObjectLinkingLayer(
335     ExecutionSession &ES, JITLinkMemoryManager &MemMgr,
336     NotifyLoadedFunction NotifyLoaded, NotifyEmittedFunction NotifyEmitted,
337     ModifyPassConfigFunction ModifyPassConfig)
338     : ObjectLayer(ES), MemMgr(MemMgr), NotifyLoaded(std::move(NotifyLoaded)),
339       NotifyEmitted(std::move(NotifyEmitted)),
340       ModifyPassConfig(std::move(ModifyPassConfig)) {}
341 
342 void ObjectLinkingLayer::emit(MaterializationResponsibility R,
343                               std::unique_ptr<MemoryBuffer> O) {
344   assert(O && "Object must not be null");
345   jitLink(llvm::make_unique<ObjectLinkingLayerJITLinkContext>(
346       *this, std::move(R), std::move(O)));
347 }
348 
349 ObjectLinkingLayer::ObjectResources::ObjectResources(
350     AllocPtr Alloc, JITTargetAddress EHFrameAddr)
351     : Alloc(std::move(Alloc)), EHFrameAddr(EHFrameAddr) {}
352 
353 ObjectLinkingLayer::ObjectResources::ObjectResources(ObjectResources &&Other)
354     : Alloc(std::move(Other.Alloc)), EHFrameAddr(Other.EHFrameAddr) {
355   Other.EHFrameAddr = 0;
356 }
357 
358 ObjectLinkingLayer::ObjectResources &
359 ObjectLinkingLayer::ObjectResources::operator=(ObjectResources &&Other) {
360   std::swap(Alloc, Other.Alloc);
361   std::swap(EHFrameAddr, Other.EHFrameAddr);
362   return *this;
363 }
364 
365 ObjectLinkingLayer::ObjectResources::~ObjectResources() {
366   const char *ErrBanner =
367       "ObjectLinkingLayer received error deallocating object resources:";
368 
369   assert((EHFrameAddr == 0 || Alloc) &&
370          "Non-null EHFrameAddr must have an associated allocation");
371 
372   if (EHFrameAddr)
373     if (auto Err = deregisterEHFrameSection((void *)EHFrameAddr))
374       logAllUnhandledErrors(std::move(Err), llvm::errs(), ErrBanner);
375 
376   if (Alloc)
377     if (auto Err = Alloc->deallocate())
378       logAllUnhandledErrors(std::move(Err), llvm::errs(), ErrBanner);
379 }
380 
381 } // End namespace orc.
382 } // End namespace llvm.
383