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