1 //===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===//
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/LazyReexports.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
14 #define DEBUG_TYPE "orc"
19 LazyCallThroughManager::LazyCallThroughManager(
20 ExecutionSession
&ES
, JITTargetAddress ErrorHandlerAddr
, TrampolinePool
*TP
)
21 : ES(ES
), ErrorHandlerAddr(ErrorHandlerAddr
), TP(TP
) {}
23 Expected
<JITTargetAddress
> LazyCallThroughManager::getCallThroughTrampoline(
24 JITDylib
&SourceJD
, SymbolStringPtr SymbolName
,
25 NotifyResolvedFunction NotifyResolved
) {
26 assert(TP
&& "TrampolinePool not set");
28 std::lock_guard
<std::mutex
> Lock(LCTMMutex
);
29 auto Trampoline
= TP
->getTrampoline();
32 return Trampoline
.takeError();
34 Reexports
[*Trampoline
] = ReexportsEntry
{&SourceJD
, std::move(SymbolName
)};
35 Notifiers
[*Trampoline
] = std::move(NotifyResolved
);
39 JITTargetAddress
LazyCallThroughManager::reportCallThroughError(Error Err
) {
40 ES
.reportError(std::move(Err
));
41 return ErrorHandlerAddr
;
44 Expected
<LazyCallThroughManager::ReexportsEntry
>
45 LazyCallThroughManager::findReexport(JITTargetAddress TrampolineAddr
) {
46 std::lock_guard
<std::mutex
> Lock(LCTMMutex
);
47 auto I
= Reexports
.find(TrampolineAddr
);
48 if (I
== Reexports
.end())
49 return createStringError(inconvertibleErrorCode(),
50 "Missing reexport for trampoline address %p",
55 Error
LazyCallThroughManager::notifyResolved(JITTargetAddress TrampolineAddr
,
56 JITTargetAddress ResolvedAddr
) {
57 NotifyResolvedFunction NotifyResolved
;
59 std::lock_guard
<std::mutex
> Lock(LCTMMutex
);
60 auto I
= Notifiers
.find(TrampolineAddr
);
61 if (I
!= Notifiers
.end()) {
62 NotifyResolved
= std::move(I
->second
);
67 return NotifyResolved
? NotifyResolved(ResolvedAddr
) : Error::success();
70 void LazyCallThroughManager::resolveTrampolineLandingAddress(
71 JITTargetAddress TrampolineAddr
,
72 NotifyLandingResolvedFunction NotifyLandingResolved
) {
74 auto Entry
= findReexport(TrampolineAddr
);
76 return NotifyLandingResolved(reportCallThroughError(Entry
.takeError()));
78 // Declaring SLS and the callback outside of the call to ES.lookup is a
79 // workaround to fix build failures on AIX and on z/OS platforms.
80 SymbolLookupSet
SLS({Entry
->SymbolName
});
81 auto Callback
= [this, TrampolineAddr
, SymbolName
= Entry
->SymbolName
,
82 NotifyLandingResolved
= std::move(NotifyLandingResolved
)](
83 Expected
<SymbolMap
> Result
) mutable {
85 assert(Result
->size() == 1 && "Unexpected result size");
86 assert(Result
->count(SymbolName
) && "Unexpected result value");
87 JITTargetAddress LandingAddr
= (*Result
)[SymbolName
].getAddress();
89 if (auto Err
= notifyResolved(TrampolineAddr
, LandingAddr
))
90 NotifyLandingResolved(reportCallThroughError(std::move(Err
)));
92 NotifyLandingResolved(LandingAddr
);
94 NotifyLandingResolved(reportCallThroughError(Result
.takeError()));
98 ES
.lookup(LookupKind::Static
,
99 makeJITDylibSearchOrder(Entry
->SourceJD
,
100 JITDylibLookupFlags::MatchAllSymbols
),
101 std::move(SLS
), SymbolState::Ready
, std::move(Callback
),
102 NoDependenciesToRegister
);
105 Expected
<std::unique_ptr
<LazyCallThroughManager
>>
106 createLocalLazyCallThroughManager(const Triple
&T
, ExecutionSession
&ES
,
107 JITTargetAddress ErrorHandlerAddr
) {
108 switch (T
.getArch()) {
110 return make_error
<StringError
>(
111 std::string("No callback manager available for ") + T
.str(),
112 inconvertibleErrorCode());
114 case Triple::aarch64
:
115 case Triple::aarch64_32
:
116 return LocalLazyCallThroughManager::Create
<OrcAArch64
>(ES
,
120 return LocalLazyCallThroughManager::Create
<OrcI386
>(ES
, ErrorHandlerAddr
);
123 return LocalLazyCallThroughManager::Create
<OrcMips32Be
>(ES
,
127 return LocalLazyCallThroughManager::Create
<OrcMips32Le
>(ES
,
131 case Triple::mips64el
:
132 return LocalLazyCallThroughManager::Create
<OrcMips64
>(ES
, ErrorHandlerAddr
);
135 if (T
.getOS() == Triple::OSType::Win32
)
136 return LocalLazyCallThroughManager::Create
<OrcX86_64_Win32
>(
137 ES
, ErrorHandlerAddr
);
139 return LocalLazyCallThroughManager::Create
<OrcX86_64_SysV
>(
140 ES
, ErrorHandlerAddr
);
144 LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
145 LazyCallThroughManager
&LCTManager
, IndirectStubsManager
&ISManager
,
146 JITDylib
&SourceJD
, SymbolAliasMap CallableAliases
, ImplSymbolMap
*SrcJDLoc
)
147 : MaterializationUnit(extractFlags(CallableAliases
), nullptr),
148 LCTManager(LCTManager
), ISManager(ISManager
), SourceJD(SourceJD
),
149 CallableAliases(std::move(CallableAliases
)), AliaseeTable(SrcJDLoc
) {}
151 StringRef
LazyReexportsMaterializationUnit::getName() const {
152 return "<Lazy Reexports>";
155 void LazyReexportsMaterializationUnit::materialize(
156 std::unique_ptr
<MaterializationResponsibility
> R
) {
157 auto RequestedSymbols
= R
->getRequestedSymbols();
159 SymbolAliasMap RequestedAliases
;
160 for (auto &RequestedSymbol
: RequestedSymbols
) {
161 auto I
= CallableAliases
.find(RequestedSymbol
);
162 assert(I
!= CallableAliases
.end() && "Symbol not found in alias map?");
163 RequestedAliases
[I
->first
] = std::move(I
->second
);
164 CallableAliases
.erase(I
);
167 if (!CallableAliases
.empty())
168 if (auto Err
= R
->replace(lazyReexports(LCTManager
, ISManager
, SourceJD
,
169 std::move(CallableAliases
),
171 R
->getExecutionSession().reportError(std::move(Err
));
172 R
->failMaterialization();
176 IndirectStubsManager::StubInitsMap StubInits
;
177 for (auto &Alias
: RequestedAliases
) {
179 auto CallThroughTrampoline
= LCTManager
.getCallThroughTrampoline(
180 SourceJD
, Alias
.second
.Aliasee
,
181 [&ISManager
= this->ISManager
,
182 StubSym
= Alias
.first
](JITTargetAddress ResolvedAddr
) -> Error
{
183 return ISManager
.updatePointer(*StubSym
, ResolvedAddr
);
186 if (!CallThroughTrampoline
) {
187 SourceJD
.getExecutionSession().reportError(
188 CallThroughTrampoline
.takeError());
189 R
->failMaterialization();
193 StubInits
[*Alias
.first
] =
194 std::make_pair(*CallThroughTrampoline
, Alias
.second
.AliasFlags
);
197 if (AliaseeTable
!= nullptr && !RequestedAliases
.empty())
198 AliaseeTable
->trackImpls(RequestedAliases
, &SourceJD
);
200 if (auto Err
= ISManager
.createStubs(StubInits
)) {
201 SourceJD
.getExecutionSession().reportError(std::move(Err
));
202 R
->failMaterialization();
207 for (auto &Alias
: RequestedAliases
)
208 Stubs
[Alias
.first
] = ISManager
.findStub(*Alias
.first
, false);
210 // No registered dependencies, so these calls cannot fail.
211 cantFail(R
->notifyResolved(Stubs
));
212 cantFail(R
->notifyEmitted());
215 void LazyReexportsMaterializationUnit::discard(const JITDylib
&JD
,
216 const SymbolStringPtr
&Name
) {
217 assert(CallableAliases
.count(Name
) &&
218 "Symbol not covered by this MaterializationUnit");
219 CallableAliases
.erase(Name
);
223 LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap
&Aliases
) {
224 SymbolFlagsMap SymbolFlags
;
225 for (auto &KV
: Aliases
) {
226 assert(KV
.second
.AliasFlags
.isCallable() &&
227 "Lazy re-exports must be callable symbols");
228 SymbolFlags
[KV
.first
] = KV
.second
.AliasFlags
;
233 } // End namespace orc.
234 } // End namespace llvm.