blob: ff9b55dbbcbd08288194b5ba10419ee8176923cf [file] [log] [blame]
Lang Hames11c8dfa52019-04-20 17:10:34 +00001//===------- 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"
Lang Hames1233c152019-04-22 03:03:09 +000012#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
Lang Hames11c8dfa52019-04-20 17:10:34 +000013
14#include <vector>
15
16#define DEBUG_TYPE "orc"
17
18using namespace llvm;
19using namespace llvm::jitlink;
20using namespace llvm::orc;
21
22namespace llvm {
23namespace orc {
24
25class ObjectLinkingLayerJITLinkContext final : public JITLinkContext {
26public:
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
Lang Hamesd4a80892019-06-07 19:33:51 +000072 ES.lookup(SearchOrder, std::move(InternedSymbols), SymbolState::Resolved,
73 std::move(OnResolve), [this](const SymbolDependenceMap &Deps) {
74 registerDependencies(Deps);
75 });
Lang Hames11c8dfa52019-04-20 17:10:34 +000076 }
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
Lang Hames2f8c6f92019-06-13 20:11:23 +0000130 MR.notifyResolved(InternedResult);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000131
Lang Hamesa9fdf372019-04-26 22:58:39 +0000132 Layer.notifyLoaded(MR);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000133 }
134
135 void notifyFinalized(
136 std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
137
Lang Hamesa9fdf372019-04-26 22:58:39 +0000138 if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
139 Layer.getExecutionSession().reportError(std::move(Err));
140 MR.failMaterialization();
Lang Hames11c8dfa52019-04-20 17:10:34 +0000141
Lang Hamesa9fdf372019-04-26 22:58:39 +0000142 return;
143 }
Lang Hames2f8c6f92019-06-13 20:11:23 +0000144 MR.notifyEmitted();
Lang Hames11c8dfa52019-04-20 17:10:34 +0000145 }
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
Lang Hamesa9fdf372019-04-26 22:58:39 +0000159 Layer.modifyPassConfig(MR, TT, Config);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000160
161 return Error::success();
162 }
163
164private:
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;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000317};
318
Lang Hamesa9fdf372019-04-26 22:58:39 +0000319ObjectLinkingLayer::Plugin::~Plugin() {}
320
321ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES,
322 JITLinkMemoryManager &MemMgr)
323 : ObjectLayer(ES), MemMgr(MemMgr) {}
324
325ObjectLinkingLayer::~ObjectLinkingLayer() {
326 if (auto Err = removeAllModules())
327 getExecutionSession().reportError(std::move(Err));
328}
Lang Hames11c8dfa52019-04-20 17:10:34 +0000329
330void ObjectLinkingLayer::emit(MaterializationResponsibility R,
331 std::unique_ptr<MemoryBuffer> O) {
332 assert(O && "Object must not be null");
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000333 jitLink(std::make_unique<ObjectLinkingLayerJITLinkContext>(
Lang Hames11c8dfa52019-04-20 17:10:34 +0000334 *this, std::move(R), std::move(O)));
335}
336
Lang Hamesa9fdf372019-04-26 22:58:39 +0000337void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
338 const Triple &TT,
339 PassConfiguration &PassConfig) {
340 for (auto &P : Plugins)
341 P->modifyPassConfig(MR, TT, PassConfig);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000342}
343
Lang Hamesa9fdf372019-04-26 22:58:39 +0000344void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
345 for (auto &P : Plugins)
346 P->notifyLoaded(MR);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000347}
348
Lang Hamesa9fdf372019-04-26 22:58:39 +0000349Error 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));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000354
Lang Hamesa9fdf372019-04-26 22:58:39 +0000355 if (Err)
356 return Err;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000357
Lang Hamesa9fdf372019-04-26 22:58:39 +0000358 {
359 std::lock_guard<std::mutex> Lock(LayerMutex);
360 UntrackedAllocs.push_back(std::move(Alloc));
361 }
Lang Hames11c8dfa52019-04-20 17:10:34 +0000362
Lang Hamesa9fdf372019-04-26 22:58:39 +0000363 return Error::success();
364}
365
366Error 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
386Error 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
Lang Hamesf5a885f2019-07-04 00:05:12 +0000412EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
413 jitlink::EHFrameRegistrar &Registrar)
414 : Registrar(Registrar) {}
415
416void EHFrameRegistrationPlugin::modifyPassConfig(
Lang Hamesa9fdf372019-04-26 22:58:39 +0000417 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)
Lang Hamesf5a885f2019-07-04 00:05:12 +0000424 InProcessLinks[&MR] = Addr;
Lang Hamesa9fdf372019-04-26 22:58:39 +0000425 }));
426}
427
Lang Hamesf5a885f2019-07-04 00:05:12 +0000428Error EHFrameRegistrationPlugin::notifyEmitted(
Lang Hamesa9fdf372019-04-26 22:58:39 +0000429 MaterializationResponsibility &MR) {
430
431 auto EHFrameAddrItr = InProcessLinks.find(&MR);
432 if (EHFrameAddrItr == InProcessLinks.end())
433 return Error::success();
434
Lang Hamesf5a885f2019-07-04 00:05:12 +0000435 auto EHFrameAddr = EHFrameAddrItr->second;
Lang Hamesa9fdf372019-04-26 22:58:39 +0000436 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
Lang Hamesf5a885f2019-07-04 00:05:12 +0000444 return Registrar.registerEHFrames(EHFrameAddr);
Lang Hamesa9fdf372019-04-26 22:58:39 +0000445}
446
Lang Hamesf5a885f2019-07-04 00:05:12 +0000447Error EHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) {
Lang Hamesa9fdf372019-04-26 22:58:39 +0000448 auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K);
449 if (EHFrameAddrItr == TrackedEHFrameAddrs.end())
450 return Error::success();
451
Lang Hamesf5a885f2019-07-04 00:05:12 +0000452 auto EHFrameAddr = EHFrameAddrItr->second;
Lang Hamesa9fdf372019-04-26 22:58:39 +0000453 assert(EHFrameAddr && "Tracked eh-frame addr must not be null");
454
455 TrackedEHFrameAddrs.erase(EHFrameAddrItr);
456
Lang Hamesf5a885f2019-07-04 00:05:12 +0000457 return Registrar.deregisterEHFrames(EHFrameAddr);
Lang Hamesa9fdf372019-04-26 22:58:39 +0000458}
459
Lang Hamesf5a885f2019-07-04 00:05:12 +0000460Error EHFrameRegistrationPlugin::notifyRemovingAllModules() {
Lang Hamesa9fdf372019-04-26 22:58:39 +0000461
Lang Hamesf5a885f2019-07-04 00:05:12 +0000462 std::vector<JITTargetAddress> EHFrameAddrs = std::move(UntrackedEHFrameAddrs);
Lang Hamesa9fdf372019-04-26 22:58:39 +0000463 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()) {
Lang Hamesf5a885f2019-07-04 00:05:12 +0000473 auto EHFrameAddr = EHFrameAddrs.back();
Lang Hamesa9fdf372019-04-26 22:58:39 +0000474 assert(EHFrameAddr && "Untracked eh-frame addr must not be null");
475 EHFrameAddrs.pop_back();
Lang Hamesf5a885f2019-07-04 00:05:12 +0000476 Err = joinErrors(std::move(Err), Registrar.deregisterEHFrames(EHFrameAddr));
Lang Hamesa9fdf372019-04-26 22:58:39 +0000477 }
478
479 return Err;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000480}
481
482} // End namespace orc.
483} // End namespace llvm.