LLVM 20.0.0git
LazyReexports.cpp
Go to the documentation of this file.
1//===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===//
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
10
15
16#define DEBUG_TYPE "orc"
17
18namespace llvm {
19namespace orc {
20
22 ExecutorAddr ErrorHandlerAddr,
24 : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
25
27 JITDylib &SourceJD, SymbolStringPtr SymbolName,
28 NotifyResolvedFunction NotifyResolved) {
29 assert(TP && "TrampolinePool not set");
30
31 std::lock_guard<std::mutex> Lock(LCTMMutex);
32 auto Trampoline = TP->getTrampoline();
33
34 if (!Trampoline)
35 return Trampoline.takeError();
36
37 Reexports[*Trampoline] = ReexportsEntry{&SourceJD, std::move(SymbolName)};
38 Notifiers[*Trampoline] = std::move(NotifyResolved);
39 return *Trampoline;
40}
41
43 ES.reportError(std::move(Err));
44 return ErrorHandlerAddr;
45}
46
49 std::lock_guard<std::mutex> Lock(LCTMMutex);
50 auto I = Reexports.find(TrampolineAddr);
51 if (I == Reexports.end())
53 "Missing reexport for trampoline address %p" +
54 formatv("{0:x}", TrampolineAddr));
55 return I->second;
56}
57
59 ExecutorAddr ResolvedAddr) {
60 NotifyResolvedFunction NotifyResolved;
61 {
62 std::lock_guard<std::mutex> Lock(LCTMMutex);
63 auto I = Notifiers.find(TrampolineAddr);
64 if (I != Notifiers.end()) {
65 NotifyResolved = std::move(I->second);
66 Notifiers.erase(I);
67 }
68 }
69
70 return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
71}
72
74 ExecutorAddr TrampolineAddr,
75 NotifyLandingResolvedFunction NotifyLandingResolved) {
76
77 auto Entry = findReexport(TrampolineAddr);
78 if (!Entry)
79 return NotifyLandingResolved(reportCallThroughError(Entry.takeError()));
80
81 // Declaring SLS and the callback outside of the call to ES.lookup is a
82 // workaround to fix build failures on AIX and on z/OS platforms.
83 SymbolLookupSet SLS({Entry->SymbolName});
84 auto Callback = [this, TrampolineAddr, SymbolName = Entry->SymbolName,
85 NotifyLandingResolved = std::move(NotifyLandingResolved)](
87 if (Result) {
88 assert(Result->size() == 1 && "Unexpected result size");
89 assert(Result->count(SymbolName) && "Unexpected result value");
90 ExecutorAddr LandingAddr = (*Result)[SymbolName].getAddress();
91
92 if (auto Err = notifyResolved(TrampolineAddr, LandingAddr))
93 NotifyLandingResolved(reportCallThroughError(std::move(Err)));
94 else
95 NotifyLandingResolved(LandingAddr);
96 } else {
97 NotifyLandingResolved(reportCallThroughError(Result.takeError()));
98 }
99 };
100
102 makeJITDylibSearchOrder(Entry->SourceJD,
104 std::move(SLS), SymbolState::Ready, std::move(Callback),
106}
107
110 ExecutorAddr ErrorHandlerAddr) {
111 switch (T.getArch()) {
112 default:
113 return make_error<StringError>(
114 std::string("No callback manager available for ") + T.str(),
116
117 case Triple::aarch64:
119 return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
120 ErrorHandlerAddr);
121
122 case Triple::x86:
123 return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
124
126 return LocalLazyCallThroughManager::Create<OrcLoongArch64>(
127 ES, ErrorHandlerAddr);
128
129 case Triple::mips:
130 return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
131 ErrorHandlerAddr);
132
133 case Triple::mipsel:
134 return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
135 ErrorHandlerAddr);
136
137 case Triple::mips64:
138 case Triple::mips64el:
139 return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
140
141 case Triple::riscv64:
142 return LocalLazyCallThroughManager::Create<OrcRiscv64>(ES,
143 ErrorHandlerAddr);
144
145 case Triple::x86_64:
146 if (T.getOS() == Triple::OSType::Win32)
147 return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
148 ES, ErrorHandlerAddr);
149 else
150 return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
151 ES, ErrorHandlerAddr);
152 }
153}
154
157 JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
158 : MaterializationUnit(extractFlags(CallableAliases)),
159 LCTManager(LCTManager), RSManager(RSManager), SourceJD(SourceJD),
160 CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
161
163 return "<Lazy Reexports>";
164}
165
166void LazyReexportsMaterializationUnit::materialize(
167 std::unique_ptr<MaterializationResponsibility> R) {
168 auto RequestedSymbols = R->getRequestedSymbols();
169
170 SymbolAliasMap RequestedAliases;
171 for (auto &RequestedSymbol : RequestedSymbols) {
172 auto I = CallableAliases.find(RequestedSymbol);
173 assert(I != CallableAliases.end() && "Symbol not found in alias map?");
174 RequestedAliases[I->first] = std::move(I->second);
175 CallableAliases.erase(I);
176 }
177
178 if (!CallableAliases.empty())
179 if (auto Err = R->replace(lazyReexports(LCTManager, RSManager, SourceJD,
180 std::move(CallableAliases),
181 AliaseeTable))) {
182 R->getExecutionSession().reportError(std::move(Err));
183 R->failMaterialization();
184 return;
185 }
186
187 SymbolMap Inits;
188 for (auto &Alias : RequestedAliases) {
189 auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
190 SourceJD, Alias.second.Aliasee,
191 [&TargetJD = R->getTargetJITDylib(), &RSManager = this->RSManager,
192 StubSym = Alias.first](ExecutorAddr ResolvedAddr) -> Error {
193 return RSManager.redirect(TargetJD, StubSym,
194 ExecutorSymbolDef(ResolvedAddr, {}));
195 });
196
197 if (!CallThroughTrampoline) {
198 R->getExecutionSession().reportError(CallThroughTrampoline.takeError());
199 R->failMaterialization();
200 return;
201 }
202
203 Inits[Alias.first] = {*CallThroughTrampoline, Alias.second.AliasFlags};
204 }
205
206 if (AliaseeTable != nullptr && !RequestedAliases.empty())
207 AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
208
209 if (auto Err = R->replace(std::make_unique<RedirectableMaterializationUnit>(
210 RSManager, std::move(Inits)))) {
211 R->getExecutionSession().reportError(std::move(Err));
212 return R->failMaterialization();
213 }
214}
215
216void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
217 const SymbolStringPtr &Name) {
218 assert(CallableAliases.count(Name) &&
219 "Symbol not covered by this MaterializationUnit");
220 CallableAliases.erase(Name);
221}
222
223MaterializationUnit::Interface
224LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
226 for (auto &KV : Aliases) {
227 assert(KV.second.AliasFlags.isCallable() &&
228 "Lazy re-exports must be callable symbols");
229 SymbolFlags[KV.first] = KV.second.AliasFlags;
230 }
231 return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr);
232}
233
235public:
237 : MaterializationUnit(getInterface(Reexports)), LRMgr(LRMgr),
238 Reexports(std::move(Reexports)) {}
239
240private:
241 Interface getInterface(const SymbolAliasMap &Reexports) {
243 for (auto &[Alias, AI] : Reexports)
244 SF[Alias] = AI.AliasFlags;
245 return {std::move(SF), nullptr};
246 }
247
248 StringRef getName() const override { return "LazyReexportsManager::MU"; }
249
250 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
251 LRMgr.emitReentryTrampolines(std::move(R), std::move(Reexports));
252 }
253
254 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override {
255 Reexports.erase(Name);
256 }
257
258 LazyReexportsManager &LRMgr;
259 SymbolAliasMap Reexports;
260};
261
262class LazyReexportsManager::Plugin : public ObjectLinkingLayer::Plugin {
263public:
267
269 return Error::success();
270 }
271
273 return Error::success();
274 }
275
277 ResourceKey SrcKey) override {}
278
279private:
280 std::mutex M;
281};
282
284LazyReexportsManager::Create(EmitTrampolinesFn EmitTrampolines,
286 JITDylib &PlatformJD) {
287 Error Err = Error::success();
288 std::unique_ptr<LazyReexportsManager> LRM(new LazyReexportsManager(
289 std::move(EmitTrampolines), RSMgr, PlatformJD, Err));
290 if (Err)
291 return std::move(Err);
292 return std::move(LRM);
293}
294
295Error LazyReexportsManager::handleRemoveResources(JITDylib &JD, ResourceKey K) {
297 auto I = KeyToReentryAddr.find(K);
298 if (I != KeyToReentryAddr.end()) {
299 auto &ReentryAddrs = I->second;
300 for (auto &ReentryAddr : ReentryAddrs) {
301 assert(CallThroughs.count(ReentryAddr) && "CallTrhough missing");
302 CallThroughs.erase(ReentryAddr);
303 }
304 KeyToReentryAddr.erase(I);
305 }
306 });
307 return Error::success();
308}
309
310void LazyReexportsManager::handleTransferResources(JITDylib &JD,
311 ResourceKey DstK,
312 ResourceKey SrcK) {
313 auto I = KeyToReentryAddr.find(SrcK);
314 if (I != KeyToReentryAddr.end()) {
315 auto J = KeyToReentryAddr.find(DstK);
316 if (J == KeyToReentryAddr.end()) {
317 auto Tmp = std::move(I->second);
318 KeyToReentryAddr.erase(I);
319 KeyToReentryAddr[DstK] = std::move(Tmp);
320 } else {
321 auto &SrcReentryAddrs = I->second;
322 auto &DstReentryAddrs = J->second;
323 for (auto &ReentryAddr : SrcReentryAddrs)
324 DstReentryAddrs.push_back(std::move(ReentryAddr));
325 KeyToReentryAddr.erase(I);
326 }
327 }
328}
329
330LazyReexportsManager::LazyReexportsManager(EmitTrampolinesFn EmitTrampolines,
332 JITDylib &PlatformJD, Error &Err)
333 : ES(PlatformJD.getExecutionSession()),
334 EmitTrampolines(std::move(EmitTrampolines)), RSMgr(RSMgr) {
335
336 using namespace shared;
337
339
341
342 WFs[ES.intern("__orc_rt_resolve_tag")] =
343 ES.wrapAsyncWithSPS<SPSExpected<SPSExecutorSymbolDef>(SPSExecutorAddr)>(
344 this, &LazyReexportsManager::resolve);
345
346 Err = ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
347}
348
349std::unique_ptr<MaterializationUnit>
350LazyReexportsManager::createLazyReexports(SymbolAliasMap Reexports) {
351 return std::make_unique<MU>(*this, std::move(Reexports));
352}
353
354void LazyReexportsManager::emitReentryTrampolines(
355 std::unique_ptr<MaterializationResponsibility> MR,
356 SymbolAliasMap Reexports) {
357 size_t NumTrampolines = Reexports.size();
358 auto RT = MR->getResourceTracker();
359 EmitTrampolines(
360 std::move(RT), NumTrampolines,
361 [this, MR = std::move(MR), Reexports = std::move(Reexports)](
362 Expected<std::vector<ExecutorSymbolDef>> ReentryPoints) mutable {
363 emitRedirectableSymbols(std::move(MR), std::move(Reexports),
364 std::move(ReentryPoints));
365 });
366}
367
368void LazyReexportsManager::emitRedirectableSymbols(
369 std::unique_ptr<MaterializationResponsibility> MR, SymbolAliasMap Reexports,
370 Expected<std::vector<ExecutorSymbolDef>> ReentryPoints) {
371
372 if (!ReentryPoints) {
373 MR->getExecutionSession().reportError(ReentryPoints.takeError());
374 MR->failMaterialization();
375 return;
376 }
377
378 assert(Reexports.size() == ReentryPoints->size() &&
379 "Number of reentry points doesn't match number of reexports");
380
381 // Bind entry points to names.
382 SymbolMap Redirs;
383 size_t I = 0;
384 for (auto &[Name, AI] : Reexports)
385 Redirs[Name] = (*ReentryPoints)[I++];
386
387 I = 0;
388 if (auto Err = MR->withResourceKeyDo([&](ResourceKey K) {
389 for (auto &[Name, AI] : Reexports) {
390 const auto &ReentryPoint = (*ReentryPoints)[I++];
391 CallThroughs[ReentryPoint.getAddress()] = {Name, AI.Aliasee,
392 &MR->getTargetJITDylib()};
393 KeyToReentryAddr[K].push_back(ReentryPoint.getAddress());
394 }
395 })) {
396 MR->getExecutionSession().reportError(std::move(Err));
397 MR->failMaterialization();
398 return;
399 }
400
401 RSMgr.emitRedirectableSymbols(std::move(MR), std::move(Redirs));
402}
403
404void LazyReexportsManager::resolve(ResolveSendResultFn SendResult,
405 ExecutorAddr ReentryStubAddr) {
406
407 CallThroughInfo LandingInfo;
408
409 ES.runSessionLocked([&]() {
410 auto I = CallThroughs.find(ReentryStubAddr);
411 if (I == CallThroughs.end())
412 return SendResult(make_error<StringError>(
413 "Reentry address " + formatv("{0:x}", ReentryStubAddr) +
414 " not registered",
416 LandingInfo = I->second;
417 });
418
419 SymbolInstance LandingSym(LandingInfo.JD, std::move(LandingInfo.BodyName));
420 LandingSym.lookupAsync([this, JD = std::move(LandingInfo.JD),
421 ReentryName = std::move(LandingInfo.Name),
422 SendResult = std::move(SendResult)](
423 Expected<ExecutorSymbolDef> Result) mutable {
424 if (Result) {
425 // FIXME: Make RedirectionManager operations async, then use the async
426 // APIs here.
427 if (auto Err = RSMgr.redirect(*JD, ReentryName, *Result))
428 SendResult(std::move(Err));
429 else
430 SendResult(std::move(Result));
431 } else
432 SendResult(std::move(Result));
433 });
434}
435
436} // End namespace orc.
437} // End namespace llvm.
std::string Name
RelaxConfig Config
Definition: ELF_riscv.cpp:506
#define _
#define I(x, y, z)
Definition: MD5.cpp:58
#define G(x, y, z)
Definition: MD5.cpp:56
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:156
bool erase(const KeyT &Val)
Definition: DenseMap.h:321
bool empty() const
Definition: DenseMap.h:98
iterator end()
Definition: DenseMap.h:84
Helper for Errors used as out-parameters.
Definition: Error.h:1130
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
@ loongarch64
Definition: Triple.h:62
@ mips64el
Definition: Triple.h:67
@ aarch64_32
Definition: Triple.h:53
An ExecutionSession represents a running JIT program.
Definition: Core.h:1339
void reportError(Error Err)
Report a error for this execution session.
Definition: Core.h:1474
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
Definition: Core.h:1393
static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H)
Wrap a handler that takes concrete argument types (and a sender for a concrete return type) to produc...
Definition: Core.h:1607
void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, SymbolLookupSet Symbols, SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete, RegisterDependenciesFunction RegisterDependencies)
Search the given JITDylibs for the given symbols.
Definition: Core.cpp:1788
Error registerJITDispatchHandlers(JITDylib &JD, JITDispatchHandlerAssociationMap WFs)
For each tag symbol name, associate the corresponding AsyncHandlerWrapperFunction with the address of...
Definition: Core.cpp:1897
decltype(auto) runSessionLocked(Func &&F)
Run the given lambda with the session mutex locked.
Definition: Core.h:1403
Represents an address in the executor process.
Represents a JIT'd dynamic library.
Definition: Core.h:897
ExecutionSession & getExecutionSession() const
Get a reference to the ExecutionSession for this JITDylib.
Definition: Core.h:916
Manages a set of 'lazy call-through' trampolines.
Definition: LazyReexports.h:39
ExecutorAddr reportCallThroughError(Error Err)
Expected< ReexportsEntry > findReexport(ExecutorAddr TrampolineAddr)
Error notifyResolved(ExecutorAddr TrampolineAddr, ExecutorAddr ResolvedAddr)
void resolveTrampolineLandingAddress(ExecutorAddr TrampolineAddr, TrampolinePool::NotifyLandingResolvedFunction NotifyLandingResolved)
LazyCallThroughManager(ExecutionSession &ES, ExecutorAddr ErrorHandlerAddr, TrampolinePool *TP)
Expected< ExecutorAddr > getCallThroughTrampoline(JITDylib &SourceJD, SymbolStringPtr SymbolName, NotifyResolvedFunction NotifyResolved)
MU(LazyReexportsManager &LRMgr, SymbolAliasMap Reexports)
void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &G, jitlink::PassConfiguration &Config) override
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) override
Error notifyFailed(MaterializationResponsibility &MR) override
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override
LazyReexportsMaterializationUnit(LazyCallThroughManager &LCTManager, RedirectableSymbolManager &RSManager, JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
StringRef getName() const override
Return the name of this materialization unit.
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Definition: Core.h:571
A MaterializationUnit represents a set of symbol definitions that can be materialized as a group,...
Base class for managing redirectable symbols in which a call gets redirected to another symbol in run...
virtual void emitRedirectableSymbols(std::unique_ptr< MaterializationResponsibility > MR, SymbolMap InitialDests)=0
Emit redirectable symbol.
A set of symbols to look up, each associated with a SymbolLookupFlags value.
Definition: Core.h:194
Pointer to a pooled string representing a symbol name.
Base class for pools of compiler re-entry trampolines.
Expected< ExecutorAddr > getTrampoline()
Get an available trampoline address.
unique_function is a type-erasing functor similar to std::function.
SymbolFlags
Symbol flags.
Definition: Symbol.h:24
JITDylibSearchOrder makeJITDylibSearchOrder(ArrayRef< JITDylib * > JDs, JITDylibLookupFlags Flags=JITDylibLookupFlags::MatchExportedSymbolsOnly)
Convenience function for creating a search order from an ArrayRef of JITDylib*, all with the same fla...
Definition: Core.h:177
DenseMap< SymbolStringPtr, SymbolAliasMapEntry > SymbolAliasMap
A map of Symbols to (Symbol, Flags) pairs.
Definition: Core.h:412
DenseMap< SymbolStringPtr, ExecutorSymbolDef > SymbolMap
A map from symbol names (as SymbolStringPtrs) to JITSymbols (address/flags pairs).
DenseMap< SymbolStringPtr, JITSymbolFlags > SymbolFlagsMap
A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
Expected< std::unique_ptr< LazyCallThroughManager > > createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, ExecutorAddr ErrorHandlerAddr)
Create a LocalLazyCallThroughManager from the given triple and execution session.
std::unique_ptr< LazyReexportsMaterializationUnit > lazyReexports(LazyCallThroughManager &LCTManager, RedirectableSymbolManager &RSManager, JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc=nullptr)
Define lazy-reexports based on the given SymbolAliasMap.
RegisterDependenciesFunction NoDependenciesToRegister
This can be used as the value for a RegisterDependenciesFunction if there are no dependants to regist...
Definition: Core.cpp:38
@ Ready
Emitted to memory, but waiting on transitive dependencies.
uintptr_t ResourceKey
Definition: Core.h:74
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:98
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1291
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858