]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / ExecutionEngine / Orc / ObjectLinkingLayer.cpp
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(SearchOrder, std::move(InternedSymbols), SymbolState::Resolved,
73               std::move(OnResolve), [this](const SymbolDependenceMap &Deps) {
74                 registerDependencies(Deps);
75               });
76   }
77
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
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
147   AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override {
148     return [this](AtomGraph &G) { return markResponsibilitySymbolsLive(G); };
149   }
150
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
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
189   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
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
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
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
319 ObjectLinkingLayer::Plugin::~Plugin() {}
320
321 ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES,
322                                        JITLinkMemoryManager &MemMgr)
323     : ObjectLayer(ES), MemMgr(MemMgr) {}
324
325 ObjectLinkingLayer::~ObjectLinkingLayer() {
326   if (auto Err = removeAllModules())
327     getExecutionSession().reportError(std::move(Err));
328 }
329
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
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
344 void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
345   for (auto &P : Plugins)
346     P->notifyLoaded(MR);
347 }
348
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
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
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
412 EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
413     jitlink::EHFrameRegistrar &Registrar)
414     : Registrar(Registrar) {}
415
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
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
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
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.