1 //===------- ObjectLinkingLayer.cpp - JITLink backed ORC ObjectLayer ------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
11 #include "llvm/ADT/Optional.h"
12 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
16 #define DEBUG_TYPE "orc"
19 using namespace llvm::jitlink
;
20 using namespace llvm::orc
;
25 class ObjectLinkingLayerJITLinkContext final
: public JITLinkContext
{
27 ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer
&Layer
,
28 MaterializationResponsibility MR
,
29 std::unique_ptr
<MemoryBuffer
> ObjBuffer
)
30 : Layer(Layer
), MR(std::move(MR
)), ObjBuffer(std::move(ObjBuffer
)) {}
32 JITLinkMemoryManager
&getMemoryManager() override
{ return Layer
.MemMgr
; }
34 MemoryBufferRef
getObjectBuffer() const override
{
35 return ObjBuffer
->getMemBufferRef();
38 void notifyFailed(Error Err
) override
{
39 Layer
.getExecutionSession().reportError(std::move(Err
));
40 MR
.failMaterialization();
43 void lookup(const DenseSet
<StringRef
> &Symbols
,
44 JITLinkAsyncLookupContinuation LookupContinuation
) override
{
46 JITDylibSearchList SearchOrder
;
47 MR
.getTargetJITDylib().withSearchOrderDo(
48 [&](const JITDylibSearchList
&JDs
) { SearchOrder
= JDs
; });
50 auto &ES
= Layer
.getExecutionSession();
52 SymbolNameSet InternedSymbols
;
53 for (auto &S
: Symbols
)
54 InternedSymbols
.insert(ES
.intern(S
));
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
= [this, SharedLookupContinuation
](Expected
<SymbolMap
> Result
) {
62 auto Main
= Layer
.getExecutionSession().intern("_main");
64 (*SharedLookupContinuation
)(Result
.takeError());
67 for (auto &KV
: *Result
)
68 LR
[*KV
.first
] = KV
.second
;
69 (*SharedLookupContinuation
)(std::move(LR
));
73 ES
.lookup(SearchOrder
, std::move(InternedSymbols
), SymbolState::Resolved
,
74 std::move(OnResolve
), [this](const SymbolDependenceMap
&Deps
) {
75 registerDependencies(Deps
);
79 void notifyResolved(AtomGraph
&G
) override
{
80 auto &ES
= Layer
.getExecutionSession();
82 SymbolFlagsMap ExtraSymbolsToClaim
;
83 bool AutoClaim
= Layer
.AutoClaimObjectSymbols
;
85 SymbolMap InternedResult
;
86 for (auto *DA
: G
.defined_atoms())
87 if (DA
->hasName() && DA
->isGlobal()) {
88 auto InternedName
= ES
.intern(DA
->getName());
92 Flags
|= JITSymbolFlags::Exported
;
94 Flags
|= JITSymbolFlags::Weak
;
96 Flags
|= JITSymbolFlags::Callable
;
98 Flags
|= JITSymbolFlags::Common
;
100 InternedResult
[InternedName
] =
101 JITEvaluatedSymbol(DA
->getAddress(), Flags
);
102 if (AutoClaim
&& !MR
.getSymbols().count(InternedName
)) {
103 assert(!ExtraSymbolsToClaim
.count(InternedName
) &&
104 "Duplicate symbol to claim?");
105 ExtraSymbolsToClaim
[InternedName
] = Flags
;
109 for (auto *A
: G
.absolute_atoms())
111 auto InternedName
= ES
.intern(A
->getName());
112 JITSymbolFlags Flags
;
113 Flags
|= JITSymbolFlags::Absolute
;
115 Flags
|= JITSymbolFlags::Weak
;
117 Flags
|= JITSymbolFlags::Callable
;
118 InternedResult
[InternedName
] =
119 JITEvaluatedSymbol(A
->getAddress(), Flags
);
120 if (AutoClaim
&& !MR
.getSymbols().count(InternedName
)) {
121 assert(!ExtraSymbolsToClaim
.count(InternedName
) &&
122 "Duplicate symbol to claim?");
123 ExtraSymbolsToClaim
[InternedName
] = Flags
;
127 if (!ExtraSymbolsToClaim
.empty())
128 if (auto Err
= MR
.defineMaterializing(ExtraSymbolsToClaim
))
129 return notifyFailed(std::move(Err
));
130 if (auto Err
= MR
.notifyResolved(InternedResult
)) {
131 Layer
.getExecutionSession().reportError(std::move(Err
));
132 MR
.failMaterialization();
135 Layer
.notifyLoaded(MR
);
138 void notifyFinalized(
139 std::unique_ptr
<JITLinkMemoryManager::Allocation
> A
) override
{
140 if (auto Err
= Layer
.notifyEmitted(MR
, std::move(A
))) {
141 Layer
.getExecutionSession().reportError(std::move(Err
));
142 MR
.failMaterialization();
145 if (auto Err
= MR
.notifyEmitted()) {
146 Layer
.getExecutionSession().reportError(std::move(Err
));
147 MR
.failMaterialization();
151 AtomGraphPassFunction
getMarkLivePass(const Triple
&TT
) const override
{
152 return [this](AtomGraph
&G
) { return markResponsibilitySymbolsLive(G
); };
155 Error
modifyPassConfig(const Triple
&TT
, PassConfiguration
&Config
) override
{
156 // Add passes to mark duplicate defs as should-discard, and to walk the
157 // atom graph to build the symbol dependence graph.
158 Config
.PrePrunePasses
.push_back(
159 [this](AtomGraph
&G
) { return markSymbolsToDiscard(G
); });
160 Config
.PostPrunePasses
.push_back(
161 [this](AtomGraph
&G
) { return computeNamedSymbolDependencies(G
); });
163 Layer
.modifyPassConfig(MR
, TT
, Config
);
165 return Error::success();
169 using AnonAtomNamedDependenciesMap
=
170 DenseMap
<const DefinedAtom
*, SymbolNameSet
>;
172 Error
markSymbolsToDiscard(AtomGraph
&G
) {
173 auto &ES
= Layer
.getExecutionSession();
174 for (auto *DA
: G
.defined_atoms())
175 if (DA
->isWeak() && DA
->hasName()) {
176 auto S
= ES
.intern(DA
->getName());
177 auto I
= MR
.getSymbols().find(S
);
178 if (I
== MR
.getSymbols().end())
179 DA
->setShouldDiscard(true);
182 for (auto *A
: G
.absolute_atoms())
183 if (A
->isWeak() && A
->hasName()) {
184 auto S
= ES
.intern(A
->getName());
185 auto I
= MR
.getSymbols().find(S
);
186 if (I
== MR
.getSymbols().end())
187 A
->setShouldDiscard(true);
190 return Error::success();
193 Error
markResponsibilitySymbolsLive(AtomGraph
&G
) const {
194 auto &ES
= Layer
.getExecutionSession();
195 for (auto *DA
: G
.defined_atoms())
197 MR
.getSymbols().count(ES
.intern(DA
->getName())))
199 return Error::success();
202 Error
computeNamedSymbolDependencies(AtomGraph
&G
) {
203 auto &ES
= MR
.getTargetJITDylib().getExecutionSession();
204 auto AnonDeps
= computeAnonDeps(G
);
206 for (auto *DA
: G
.defined_atoms()) {
208 // Skip anonymous and non-global atoms: we do not need dependencies for
210 if (!DA
->hasName() || !DA
->isGlobal())
213 auto DAName
= ES
.intern(DA
->getName());
214 SymbolNameSet
&DADeps
= NamedSymbolDeps
[DAName
];
216 for (auto &E
: DA
->edges()) {
217 auto &TA
= E
.getTarget();
220 DADeps
.insert(ES
.intern(TA
.getName()));
222 assert(TA
.isDefined() && "Anonymous atoms must be defined");
223 auto &DTA
= static_cast<DefinedAtom
&>(TA
);
224 auto I
= AnonDeps
.find(&DTA
);
225 if (I
!= AnonDeps
.end())
226 for (auto &S
: I
->second
)
232 return Error::success();
235 AnonAtomNamedDependenciesMap
computeAnonDeps(AtomGraph
&G
) {
237 auto &ES
= MR
.getTargetJITDylib().getExecutionSession();
238 AnonAtomNamedDependenciesMap DepMap
;
240 // For all anonymous atoms:
241 // (1) Add their named dependencies.
242 // (2) Add them to the worklist for further iteration if they have any
243 // depend on any other anonymous atoms.
244 struct WorklistEntry
{
245 WorklistEntry(DefinedAtom
*DA
, DenseSet
<DefinedAtom
*> DAAnonDeps
)
246 : DA(DA
), DAAnonDeps(std::move(DAAnonDeps
)) {}
248 DefinedAtom
*DA
= nullptr;
249 DenseSet
<DefinedAtom
*> DAAnonDeps
;
251 std::vector
<WorklistEntry
> Worklist
;
252 for (auto *DA
: G
.defined_atoms())
253 if (!DA
->hasName()) {
254 auto &DANamedDeps
= DepMap
[DA
];
255 DenseSet
<DefinedAtom
*> DAAnonDeps
;
257 for (auto &E
: DA
->edges()) {
258 auto &TA
= E
.getTarget();
260 DANamedDeps
.insert(ES
.intern(TA
.getName()));
262 assert(TA
.isDefined() && "Anonymous atoms must be defined");
263 DAAnonDeps
.insert(static_cast<DefinedAtom
*>(&TA
));
267 if (!DAAnonDeps
.empty())
268 Worklist
.push_back(WorklistEntry(DA
, std::move(DAAnonDeps
)));
271 // Loop over all anonymous atoms with anonymous dependencies, propagating
272 // their respective *named* dependencies. Iterate until we hit a stable
277 for (auto &WLEntry
: Worklist
) {
278 auto *DA
= WLEntry
.DA
;
279 auto &DANamedDeps
= DepMap
[DA
];
280 auto &DAAnonDeps
= WLEntry
.DAAnonDeps
;
282 for (auto *TA
: DAAnonDeps
) {
283 auto I
= DepMap
.find(TA
);
284 if (I
!= DepMap
.end())
285 for (const auto &S
: I
->second
)
286 Changed
|= DANamedDeps
.insert(S
).second
;
294 void registerDependencies(const SymbolDependenceMap
&QueryDeps
) {
295 for (auto &NamedDepsEntry
: NamedSymbolDeps
) {
296 auto &Name
= NamedDepsEntry
.first
;
297 auto &NameDeps
= NamedDepsEntry
.second
;
298 SymbolDependenceMap SymbolDeps
;
300 for (const auto &QueryDepsEntry
: QueryDeps
) {
301 JITDylib
&SourceJD
= *QueryDepsEntry
.first
;
302 const SymbolNameSet
&Symbols
= QueryDepsEntry
.second
;
303 auto &DepsForJD
= SymbolDeps
[&SourceJD
];
305 for (const auto &S
: Symbols
)
306 if (NameDeps
.count(S
))
309 if (DepsForJD
.empty())
310 SymbolDeps
.erase(&SourceJD
);
313 MR
.addDependencies(Name
, SymbolDeps
);
317 ObjectLinkingLayer
&Layer
;
318 MaterializationResponsibility MR
;
319 std::unique_ptr
<MemoryBuffer
> ObjBuffer
;
320 DenseMap
<SymbolStringPtr
, SymbolNameSet
> NamedSymbolDeps
;
323 ObjectLinkingLayer::Plugin::~Plugin() {}
325 ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession
&ES
,
326 JITLinkMemoryManager
&MemMgr
)
327 : ObjectLayer(ES
), MemMgr(MemMgr
) {}
329 ObjectLinkingLayer::~ObjectLinkingLayer() {
330 if (auto Err
= removeAllModules())
331 getExecutionSession().reportError(std::move(Err
));
334 void ObjectLinkingLayer::emit(MaterializationResponsibility R
,
335 std::unique_ptr
<MemoryBuffer
> O
) {
336 assert(O
&& "Object must not be null");
337 jitLink(std::make_unique
<ObjectLinkingLayerJITLinkContext
>(
338 *this, std::move(R
), std::move(O
)));
341 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility
&MR
,
343 PassConfiguration
&PassConfig
) {
344 for (auto &P
: Plugins
)
345 P
->modifyPassConfig(MR
, TT
, PassConfig
);
348 void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility
&MR
) {
349 for (auto &P
: Plugins
)
353 Error
ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility
&MR
,
355 Error Err
= Error::success();
356 for (auto &P
: Plugins
)
357 Err
= joinErrors(std::move(Err
), P
->notifyEmitted(MR
));
363 std::lock_guard
<std::mutex
> Lock(LayerMutex
);
364 UntrackedAllocs
.push_back(std::move(Alloc
));
367 return Error::success();
370 Error
ObjectLinkingLayer::removeModule(VModuleKey K
) {
371 Error Err
= Error::success();
373 for (auto &P
: Plugins
)
374 Err
= joinErrors(std::move(Err
), P
->notifyRemovingModule(K
));
379 std::lock_guard
<std::mutex
> Lock(LayerMutex
);
380 auto AllocItr
= TrackedAllocs
.find(K
);
381 Alloc
= std::move(AllocItr
->second
);
382 TrackedAllocs
.erase(AllocItr
);
385 assert(Alloc
&& "No allocation for key K");
387 return joinErrors(std::move(Err
), Alloc
->deallocate());
390 Error
ObjectLinkingLayer::removeAllModules() {
392 Error Err
= Error::success();
394 for (auto &P
: Plugins
)
395 Err
= joinErrors(std::move(Err
), P
->notifyRemovingAllModules());
397 std::vector
<AllocPtr
> Allocs
;
399 std::lock_guard
<std::mutex
> Lock(LayerMutex
);
400 Allocs
= std::move(UntrackedAllocs
);
402 for (auto &KV
: TrackedAllocs
)
403 Allocs
.push_back(std::move(KV
.second
));
405 TrackedAllocs
.clear();
408 while (!Allocs
.empty()) {
409 Err
= joinErrors(std::move(Err
), Allocs
.back()->deallocate());
416 EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
417 jitlink::EHFrameRegistrar
&Registrar
)
418 : Registrar(Registrar
) {}
420 void EHFrameRegistrationPlugin::modifyPassConfig(
421 MaterializationResponsibility
&MR
, const Triple
&TT
,
422 PassConfiguration
&PassConfig
) {
423 assert(!InProcessLinks
.count(&MR
) && "Link for MR already being tracked?");
425 PassConfig
.PostFixupPasses
.push_back(
426 createEHFrameRecorderPass(TT
, [this, &MR
](JITTargetAddress Addr
,
429 InProcessLinks
[&MR
] = { Addr
, Size
};
433 Error
EHFrameRegistrationPlugin::notifyEmitted(
434 MaterializationResponsibility
&MR
) {
436 auto EHFrameRangeItr
= InProcessLinks
.find(&MR
);
437 if (EHFrameRangeItr
== InProcessLinks
.end())
438 return Error::success();
440 auto EHFrameRange
= EHFrameRangeItr
->second
;
441 assert(EHFrameRange
.Addr
&&
442 "eh-frame addr to register can not be null");
444 InProcessLinks
.erase(EHFrameRangeItr
);
445 if (auto Key
= MR
.getVModuleKey())
446 TrackedEHFrameRanges
[Key
] = EHFrameRange
;
448 UntrackedEHFrameRanges
.push_back(EHFrameRange
);
450 return Registrar
.registerEHFrames(EHFrameRange
.Addr
, EHFrameRange
.Size
);
453 Error
EHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K
) {
454 auto EHFrameRangeItr
= TrackedEHFrameRanges
.find(K
);
455 if (EHFrameRangeItr
== TrackedEHFrameRanges
.end())
456 return Error::success();
458 auto EHFrameRange
= EHFrameRangeItr
->second
;
459 assert(EHFrameRange
.Addr
&& "Tracked eh-frame range must not be null");
461 TrackedEHFrameRanges
.erase(EHFrameRangeItr
);
463 return Registrar
.deregisterEHFrames(EHFrameRange
.Addr
, EHFrameRange
.Size
);
466 Error
EHFrameRegistrationPlugin::notifyRemovingAllModules() {
468 std::vector
<EHFrameRange
> EHFrameRanges
=
469 std::move(UntrackedEHFrameRanges
);
470 EHFrameRanges
.reserve(EHFrameRanges
.size() + TrackedEHFrameRanges
.size());
472 for (auto &KV
: TrackedEHFrameRanges
)
473 EHFrameRanges
.push_back(KV
.second
);
475 TrackedEHFrameRanges
.clear();
477 Error Err
= Error::success();
479 while (!EHFrameRanges
.empty()) {
480 auto EHFrameRange
= EHFrameRanges
.back();
481 assert(EHFrameRange
.Addr
&& "Untracked eh-frame range must not be null");
482 EHFrameRanges
.pop_back();
483 Err
= joinErrors(std::move(Err
),
484 Registrar
.deregisterEHFrames(EHFrameRange
.Addr
,
491 } // End namespace orc.
492 } // End namespace llvm.