1 //===------ LinkGraphLinkingLayer.cpp - Link LinkGraphs with JITLink ------===//
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/LinkGraphLinkingLayer.h"
10 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
11 #include "llvm/ExecutionEngine/JITLink/aarch32.h"
12 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
13 #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
14 #include "llvm/Support/MemoryBuffer.h"
16 #define DEBUG_TYPE "orc"
19 using namespace llvm::jitlink
;
20 using namespace llvm::orc
;
24 ExecutorAddr
getJITSymbolPtrForSymbol(Symbol
&Sym
, const Triple
&TT
) {
25 switch (TT
.getArch()) {
30 if (hasTargetFlags(Sym
, aarch32::ThumbSymbol
)) {
31 // Set LSB to indicate thumb target
32 assert(Sym
.isCallable() && "Only callable symbols can have thumb flag");
33 assert((Sym
.getAddress().getValue() & 0x01) == 0 && "LSB is clear");
34 return Sym
.getAddress() + 0x01;
36 return Sym
.getAddress();
38 return Sym
.getAddress();
42 } // end anonymous namespace
47 class LinkGraphLinkingLayer::JITLinkCtx final
: public JITLinkContext
{
49 JITLinkCtx(LinkGraphLinkingLayer
&Layer
,
50 std::unique_ptr
<MaterializationResponsibility
> MR
,
51 std::unique_ptr
<MemoryBuffer
> ObjBuffer
)
52 : JITLinkContext(&MR
->getTargetJITDylib()), Layer(Layer
),
53 MR(std::move(MR
)), ObjBuffer(std::move(ObjBuffer
)) {
54 std::lock_guard
<std::mutex
> Lock(Layer
.LayerMutex
);
55 Plugins
= Layer
.Plugins
;
59 // If there is an object buffer return function then use it to
60 // return ownership of the buffer.
61 if (Layer
.ReturnObjectBuffer
&& ObjBuffer
)
62 Layer
.ReturnObjectBuffer(std::move(ObjBuffer
));
65 JITLinkMemoryManager
&getMemoryManager() override
{ return Layer
.MemMgr
; }
67 void notifyMaterializing(LinkGraph
&G
) {
68 for (auto &P
: Plugins
)
69 P
->notifyMaterializing(*MR
, G
, *this,
70 ObjBuffer
? ObjBuffer
->getMemBufferRef()
74 void notifyFailed(Error Err
) override
{
75 for (auto &P
: Plugins
)
76 Err
= joinErrors(std::move(Err
), P
->notifyFailed(*MR
));
77 Layer
.getExecutionSession().reportError(std::move(Err
));
78 MR
->failMaterialization();
81 void lookup(const LookupMap
&Symbols
,
82 std::unique_ptr
<JITLinkAsyncLookupContinuation
> LC
) override
{
84 JITDylibSearchOrder LinkOrder
;
85 MR
->getTargetJITDylib().withLinkOrderDo(
86 [&](const JITDylibSearchOrder
&LO
) { LinkOrder
= LO
; });
88 auto &ES
= Layer
.getExecutionSession();
90 SymbolLookupSet LookupSet
;
91 for (auto &KV
: Symbols
) {
92 orc::SymbolLookupFlags LookupFlags
;
94 case jitlink::SymbolLookupFlags::RequiredSymbol
:
95 LookupFlags
= orc::SymbolLookupFlags::RequiredSymbol
;
97 case jitlink::SymbolLookupFlags::WeaklyReferencedSymbol
:
98 LookupFlags
= orc::SymbolLookupFlags::WeaklyReferencedSymbol
;
101 LookupSet
.add(KV
.first
, LookupFlags
);
104 // OnResolve -- De-intern the symbols and pass the result to the linker.
105 auto OnResolve
= [LookupContinuation
=
106 std::move(LC
)](Expected
<SymbolMap
> Result
) mutable {
108 LookupContinuation
->run(Result
.takeError());
110 AsyncLookupResult LR
;
111 for (auto &KV
: *Result
)
112 LR
[KV
.first
] = KV
.second
;
113 LookupContinuation
->run(std::move(LR
));
117 ES
.lookup(LookupKind::Static
, LinkOrder
, std::move(LookupSet
),
118 SymbolState::Resolved
, std::move(OnResolve
),
119 [this](const SymbolDependenceMap
&Deps
) {
120 // Translate LookupDeps map to SymbolSourceJD.
121 for (auto &[DepJD
, Deps
] : Deps
)
122 for (auto &DepSym
: Deps
)
123 SymbolSourceJDs
[NonOwningSymbolStringPtr(DepSym
)] = DepJD
;
127 Error
notifyResolved(LinkGraph
&G
) override
{
129 SymbolFlagsMap ExtraSymbolsToClaim
;
130 bool AutoClaim
= Layer
.AutoClaimObjectSymbols
;
132 SymbolMap InternedResult
;
133 for (auto *Sym
: G
.defined_symbols())
134 if (Sym
->getScope() < Scope::SideEffectsOnly
) {
135 auto Ptr
= getJITSymbolPtrForSymbol(*Sym
, G
.getTargetTriple());
136 auto Flags
= getJITSymbolFlagsForSymbol(*Sym
);
137 InternedResult
[Sym
->getName()] = {Ptr
, Flags
};
138 if (AutoClaim
&& !MR
->getSymbols().count(Sym
->getName())) {
139 assert(!ExtraSymbolsToClaim
.count(Sym
->getName()) &&
140 "Duplicate symbol to claim?");
141 ExtraSymbolsToClaim
[Sym
->getName()] = Flags
;
145 for (auto *Sym
: G
.absolute_symbols())
146 if (Sym
->getScope() < Scope::SideEffectsOnly
) {
147 auto Ptr
= getJITSymbolPtrForSymbol(*Sym
, G
.getTargetTriple());
148 auto Flags
= getJITSymbolFlagsForSymbol(*Sym
);
149 InternedResult
[Sym
->getName()] = {Ptr
, Flags
};
150 if (AutoClaim
&& !MR
->getSymbols().count(Sym
->getName())) {
151 assert(!ExtraSymbolsToClaim
.count(Sym
->getName()) &&
152 "Duplicate symbol to claim?");
153 ExtraSymbolsToClaim
[Sym
->getName()] = Flags
;
157 if (!ExtraSymbolsToClaim
.empty())
158 if (auto Err
= MR
->defineMaterializing(ExtraSymbolsToClaim
))
163 // Check that InternedResult matches up with MR->getSymbols(), overriding
164 // flags if requested.
165 // This guards against faulty transformations / compilers / object caches.
167 // First check that there aren't any missing symbols.
168 size_t NumMaterializationSideEffectsOnlySymbols
= 0;
169 SymbolNameVector MissingSymbols
;
170 for (auto &[Sym
, Flags
] : MR
->getSymbols()) {
172 auto I
= InternedResult
.find(Sym
);
174 // If this is a materialization-side-effects only symbol then bump
175 // the counter and remove in from the result, otherwise make sure that
177 if (Flags
.hasMaterializationSideEffectsOnly())
178 ++NumMaterializationSideEffectsOnlySymbols
;
179 else if (I
== InternedResult
.end())
180 MissingSymbols
.push_back(Sym
);
181 else if (Layer
.OverrideObjectFlags
)
182 I
->second
.setFlags(Flags
);
185 // If there were missing symbols then report the error.
186 if (!MissingSymbols
.empty())
187 return make_error
<MissingSymbolDefinitions
>(
188 Layer
.getExecutionSession().getSymbolStringPool(), G
.getName(),
189 std::move(MissingSymbols
));
191 // If there are more definitions than expected, add them to the
192 // ExtraSymbols vector.
193 SymbolNameVector ExtraSymbols
;
194 if (InternedResult
.size() >
195 MR
->getSymbols().size() - NumMaterializationSideEffectsOnlySymbols
) {
196 for (auto &KV
: InternedResult
)
197 if (!MR
->getSymbols().count(KV
.first
))
198 ExtraSymbols
.push_back(KV
.first
);
201 // If there were extra definitions then report the error.
202 if (!ExtraSymbols
.empty())
203 return make_error
<UnexpectedSymbolDefinitions
>(
204 Layer
.getExecutionSession().getSymbolStringPool(), G
.getName(),
205 std::move(ExtraSymbols
));
208 if (auto Err
= MR
->notifyResolved(InternedResult
))
212 return Error::success();
215 void notifyFinalized(JITLinkMemoryManager::FinalizedAlloc A
) override
{
216 if (auto Err
= notifyEmitted(std::move(A
))) {
217 Layer
.getExecutionSession().reportError(std::move(Err
));
218 MR
->failMaterialization();
222 if (auto Err
= MR
->notifyEmitted(SymbolDepGroups
)) {
223 Layer
.getExecutionSession().reportError(std::move(Err
));
224 MR
->failMaterialization();
228 LinkGraphPassFunction
getMarkLivePass(const Triple
&TT
) const override
{
229 return [this](LinkGraph
&G
) { return markResponsibilitySymbolsLive(G
); };
232 Error
modifyPassConfig(LinkGraph
&LG
, PassConfiguration
&Config
) override
{
233 // Add passes to mark duplicate defs as should-discard, and to walk the
234 // link graph to build the symbol dependence graph.
235 Config
.PrePrunePasses
.push_back([this](LinkGraph
&G
) {
236 return claimOrExternalizeWeakAndCommonSymbols(G
);
239 for (auto &P
: Plugins
)
240 P
->modifyPassConfig(*MR
, LG
, Config
);
242 Config
.PreFixupPasses
.push_back(
243 [this](LinkGraph
&G
) { return registerDependencies(G
); });
245 return Error::success();
248 void notifyLoaded() {
249 for (auto &P
: Plugins
)
250 P
->notifyLoaded(*MR
);
253 Error
notifyEmitted(jitlink::JITLinkMemoryManager::FinalizedAlloc FA
) {
254 Error Err
= Error::success();
255 for (auto &P
: Plugins
)
256 Err
= joinErrors(std::move(Err
), P
->notifyEmitted(*MR
));
261 joinErrors(std::move(Err
), Layer
.MemMgr
.deallocate(std::move(FA
)));
266 return Layer
.recordFinalizedAlloc(*MR
, std::move(FA
));
268 return Error::success();
272 Error
claimOrExternalizeWeakAndCommonSymbols(LinkGraph
&G
) {
273 SymbolFlagsMap NewSymbolsToClaim
;
274 std::vector
<std::pair
<SymbolStringPtr
, Symbol
*>> NameToSym
;
276 auto ProcessSymbol
= [&](Symbol
*Sym
) {
277 if (Sym
->hasName() && Sym
->getLinkage() == Linkage::Weak
&&
278 Sym
->getScope() != Scope::Local
) {
279 if (!MR
->getSymbols().count(Sym
->getName())) {
280 NewSymbolsToClaim
[Sym
->getName()] =
281 getJITSymbolFlagsForSymbol(*Sym
) | JITSymbolFlags::Weak
;
282 NameToSym
.push_back(std::make_pair(Sym
->getName(), Sym
));
287 for (auto *Sym
: G
.defined_symbols())
289 for (auto *Sym
: G
.absolute_symbols())
292 // Attempt to claim all weak defs that we're not already responsible for.
293 // This may fail if the resource tracker has become defunct, but should
294 // always succeed otherwise.
295 if (auto Err
= MR
->defineMaterializing(std::move(NewSymbolsToClaim
)))
298 // Walk the list of symbols that we just tried to claim. Symbols that we're
299 // responsible for are marked live. Symbols that we're not responsible for
300 // are turned into external references.
301 for (auto &KV
: NameToSym
) {
302 if (MR
->getSymbols().count(KV
.first
))
303 KV
.second
->setLive(true);
305 G
.makeExternal(*KV
.second
);
308 return Error::success();
311 Error
markResponsibilitySymbolsLive(LinkGraph
&G
) const {
312 for (auto *Sym
: G
.defined_symbols())
313 if (Sym
->hasName() && MR
->getSymbols().count(Sym
->getName()))
315 return Error::success();
318 Error
registerDependencies(LinkGraph
&G
) {
321 bool InWorklist
= false;
322 DenseSet
<Symbol
*> Defs
;
323 DenseSet
<Symbol
*> SymbolDeps
;
324 DenseSet
<Block
*> AnonEdges
, AnonBackEdges
;
327 DenseMap
<Block
*, BlockInfo
> BlockInfos
;
329 // Reserve space so that BlockInfos doesn't need to resize. This is
330 // essential to avoid invalidating pointers to entries below.
332 size_t NumBlocks
= 0;
333 for (auto &Sec
: G
.sections())
334 NumBlocks
+= Sec
.blocks_size();
335 BlockInfos
.reserve(NumBlocks
);
338 // Identify non-locally-scoped symbols defined by each block.
339 for (auto *Sym
: G
.defined_symbols()) {
340 if (Sym
->getScope() != Scope::Local
)
341 BlockInfos
[&Sym
->getBlock()].Defs
.insert(Sym
);
344 // Identify the symbolic and anonymous-block dependencies for each block.
345 for (auto *B
: G
.blocks()) {
346 auto &BI
= BlockInfos
[B
];
348 for (auto &E
: B
->edges()) {
350 // External symbols are trivially depended on.
351 if (E
.getTarget().isExternal()) {
352 BI
.SymbolDeps
.insert(&E
.getTarget());
356 // Anonymous symbols aren't depended on at all (they're assumed to be
357 // already available).
358 if (E
.getTarget().isAbsolute())
361 // If we get here then we depend on a symbol defined by some other
363 auto &TgtBI
= BlockInfos
[&E
.getTarget().getBlock()];
365 // If that block has any definitions then use the first one as the
366 // "effective" dependence here (all symbols in TgtBI will become
367 // ready at the same time, and chosing a single symbol to represent
368 // the block keeps the SymbolDepGroup size small).
369 if (!TgtBI
.Defs
.empty()) {
370 BI
.SymbolDeps
.insert(*TgtBI
.Defs
.begin());
374 // Otherwise we've got a dependence on an anonymous block. Record it
375 // here for back-propagating symbol dependencies below.
376 BI
.AnonEdges
.insert(&E
.getTarget().getBlock());
377 TgtBI
.AnonBackEdges
.insert(B
);
381 // Prune anonymous blocks.
383 std::vector
<Block
*> BlocksToRemove
;
384 for (auto &[B
, BI
] : BlockInfos
) {
385 // Skip blocks with defs. We only care about anonyous blocks.
386 if (!BI
.Defs
.empty())
389 BlocksToRemove
.push_back(B
);
391 for (auto *FB
: BI
.AnonEdges
)
392 BlockInfos
[FB
].AnonBackEdges
.erase(B
);
394 for (auto *BB
: BI
.AnonBackEdges
)
395 BlockInfos
[BB
].AnonEdges
.erase(B
);
397 for (auto *FB
: BI
.AnonEdges
) {
398 auto &FBI
= BlockInfos
[FB
];
399 for (auto *BB
: BI
.AnonBackEdges
)
400 FBI
.AnonBackEdges
.insert(BB
);
403 for (auto *BB
: BI
.AnonBackEdges
) {
404 auto &BBI
= BlockInfos
[BB
];
405 for (auto *SD
: BI
.SymbolDeps
)
406 BBI
.SymbolDeps
.insert(SD
);
407 for (auto *FB
: BI
.AnonEdges
)
408 BBI
.AnonEdges
.insert(FB
);
412 for (auto *B
: BlocksToRemove
)
416 // Build the initial dependence propagation worklist.
417 std::deque
<Block
*> Worklist
;
418 for (auto &[B
, BI
] : BlockInfos
) {
419 if (!BI
.SymbolDeps
.empty() && !BI
.AnonBackEdges
.empty()) {
420 Worklist
.push_back(B
);
421 BI
.InWorklist
= true;
425 // Propagate symbol deps through the graph.
426 while (!Worklist
.empty()) {
427 auto *B
= Worklist
.front();
428 Worklist
.pop_front();
430 auto &BI
= BlockInfos
[B
];
431 BI
.InWorklist
= false;
433 for (auto *DB
: BI
.AnonBackEdges
) {
434 auto &DBI
= BlockInfos
[DB
];
435 for (auto *Sym
: BI
.SymbolDeps
) {
436 if (DBI
.SymbolDeps
.insert(Sym
).second
&& !DBI
.InWorklist
) {
437 Worklist
.push_back(DB
);
438 DBI
.InWorklist
= true;
444 // Transform our local dependence information into a list of
445 // SymbolDependenceGroups (in the SymbolDepGroups member), ready for use in
446 // the upcoming notifyFinalized call.
447 auto &TargetJD
= MR
->getTargetJITDylib();
449 for (auto &[B
, BI
] : BlockInfos
) {
450 if (!BI
.Defs
.empty()) {
451 SymbolDepGroups
.push_back(SymbolDependenceGroup());
452 auto &SDG
= SymbolDepGroups
.back();
454 for (auto *Def
: BI
.Defs
)
455 SDG
.Symbols
.insert(Def
->getName());
457 for (auto *Dep
: BI
.SymbolDeps
) {
458 auto DepName
= Dep
->getName();
459 if (Dep
->isDefined())
460 SDG
.Dependencies
[&TargetJD
].insert(std::move(DepName
));
463 SymbolSourceJDs
.find(NonOwningSymbolStringPtr(DepName
));
464 if (SourceJDItr
!= SymbolSourceJDs
.end())
465 SDG
.Dependencies
[SourceJDItr
->second
].insert(std::move(DepName
));
471 return Error::success();
474 LinkGraphLinkingLayer
&Layer
;
475 std::vector
<std::shared_ptr
<LinkGraphLinkingLayer::Plugin
>> Plugins
;
476 std::unique_ptr
<MaterializationResponsibility
> MR
;
477 std::unique_ptr
<MemoryBuffer
> ObjBuffer
;
478 DenseMap
<NonOwningSymbolStringPtr
, JITDylib
*> SymbolSourceJDs
;
479 std::vector
<SymbolDependenceGroup
> SymbolDepGroups
;
482 LinkGraphLinkingLayer::Plugin::~Plugin() = default;
484 LinkGraphLinkingLayer::LinkGraphLinkingLayer(ExecutionSession
&ES
)
485 : LinkGraphLayer(ES
), MemMgr(ES
.getExecutorProcessControl().getMemMgr()) {
486 ES
.registerResourceManager(*this);
489 LinkGraphLinkingLayer::LinkGraphLinkingLayer(ExecutionSession
&ES
,
490 JITLinkMemoryManager
&MemMgr
)
491 : LinkGraphLayer(ES
), MemMgr(MemMgr
) {
492 ES
.registerResourceManager(*this);
495 LinkGraphLinkingLayer::LinkGraphLinkingLayer(
496 ExecutionSession
&ES
, std::unique_ptr
<JITLinkMemoryManager
> MemMgr
)
497 : LinkGraphLayer(ES
), MemMgr(*MemMgr
), MemMgrOwnership(std::move(MemMgr
)) {
498 ES
.registerResourceManager(*this);
501 LinkGraphLinkingLayer::~LinkGraphLinkingLayer() {
502 assert(Allocs
.empty() && "Layer destroyed with resources still attached");
503 getExecutionSession().deregisterResourceManager(*this);
506 void LinkGraphLinkingLayer::emit(
507 std::unique_ptr
<MaterializationResponsibility
> R
,
508 std::unique_ptr
<LinkGraph
> G
) {
509 assert(R
&& "R must not be null");
510 assert(G
&& "G must not be null");
511 auto Ctx
= std::make_unique
<JITLinkCtx
>(*this, std::move(R
), nullptr);
512 Ctx
->notifyMaterializing(*G
);
513 link(std::move(G
), std::move(Ctx
));
516 void LinkGraphLinkingLayer::emit(
517 std::unique_ptr
<MaterializationResponsibility
> R
,
518 std::unique_ptr
<LinkGraph
> G
, std::unique_ptr
<MemoryBuffer
> ObjBuf
) {
519 assert(R
&& "R must not be null");
520 assert(G
&& "G must not be null");
521 assert(ObjBuf
&& "Object must not be null");
523 std::make_unique
<JITLinkCtx
>(*this, std::move(R
), std::move(ObjBuf
));
524 Ctx
->notifyMaterializing(*G
);
525 link(std::move(G
), std::move(Ctx
));
528 Error
LinkGraphLinkingLayer::recordFinalizedAlloc(
529 MaterializationResponsibility
&MR
, FinalizedAlloc FA
) {
530 auto Err
= MR
.withResourceKeyDo(
531 [&](ResourceKey K
) { Allocs
[K
].push_back(std::move(FA
)); });
534 Err
= joinErrors(std::move(Err
), MemMgr
.deallocate(std::move(FA
)));
539 Error
LinkGraphLinkingLayer::handleRemoveResources(JITDylib
&JD
,
543 Error Err
= Error::success();
544 for (auto &P
: Plugins
)
545 Err
= joinErrors(std::move(Err
), P
->notifyRemovingResources(JD
, K
));
550 std::vector
<FinalizedAlloc
> AllocsToRemove
;
551 getExecutionSession().runSessionLocked([&] {
552 auto I
= Allocs
.find(K
);
553 if (I
!= Allocs
.end()) {
554 std::swap(AllocsToRemove
, I
->second
);
559 if (AllocsToRemove
.empty())
560 return Error::success();
562 return MemMgr
.deallocate(std::move(AllocsToRemove
));
565 void LinkGraphLinkingLayer::handleTransferResources(JITDylib
&JD
,
567 ResourceKey SrcKey
) {
568 if (Allocs
.contains(SrcKey
)) {
569 // DstKey may not be in the DenseMap yet, so the following line may resize
570 // the container and invalidate iterators and value references.
571 auto &DstAllocs
= Allocs
[DstKey
];
572 auto &SrcAllocs
= Allocs
[SrcKey
];
573 DstAllocs
.reserve(DstAllocs
.size() + SrcAllocs
.size());
574 for (auto &Alloc
: SrcAllocs
)
575 DstAllocs
.push_back(std::move(Alloc
));
577 Allocs
.erase(SrcKey
);
580 for (auto &P
: Plugins
)
581 P
->notifyTransferringResources(JD
, DstKey
, SrcKey
);
584 } // End namespace orc.
585 } // End namespace llvm.