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
9#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
10
11#include "llvm/ExecutionEngine/Orc/BindCallControllerHandlerSPS.h"
12#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
13#include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
14#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
15#include "llvm/TargetParser/Triple.h"
16
17#define DEBUG_TYPE "orc"
18
19namespace llvm {
20namespace orc {
21
22LazyCallThroughManager::LazyCallThroughManager(ExecutionSession &ES,
23 ExecutorAddr ErrorHandlerAddr,
24 TrampolinePool *TP)
25 : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
26
27Expected<ExecutorAddr> LazyCallThroughManager::getCallThroughTrampoline(
28 JITDylib &SourceJD, SymbolStringPtr SymbolName,
29 NotifyResolvedFunction NotifyResolved) {
30 assert(TP && "TrampolinePool not set");
31
32 std::lock_guard<std::mutex> Lock(LCTMMutex);
33 auto Trampoline = TP->getTrampoline();
34
35 if (!Trampoline)
36 return Trampoline.takeError();
37
38 Reexports[*Trampoline] = ReexportsEntry{.SourceJD: &SourceJD, .SymbolName: std::move(SymbolName)};
39 Notifiers[*Trampoline] = std::move(NotifyResolved);
40 return *Trampoline;
41}
42
43ExecutorAddr LazyCallThroughManager::reportCallThroughError(Error Err) {
44 ES.reportError(Err: std::move(Err));
45 return ErrorHandlerAddr;
46}
47
48Expected<LazyCallThroughManager::ReexportsEntry>
49LazyCallThroughManager::findReexport(ExecutorAddr TrampolineAddr) {
50 std::lock_guard<std::mutex> Lock(LCTMMutex);
51 auto I = Reexports.find(x: TrampolineAddr);
52 if (I == Reexports.end())
53 return createStringError(EC: inconvertibleErrorCode(),
54 S: "Missing reexport for trampoline address %p" +
55 formatv(Fmt: "{0:x}", Vals&: TrampolineAddr));
56 return I->second;
57}
58
59Error LazyCallThroughManager::notifyResolved(ExecutorAddr TrampolineAddr,
60 ExecutorAddr ResolvedAddr) {
61 NotifyResolvedFunction NotifyResolved;
62 {
63 std::lock_guard<std::mutex> Lock(LCTMMutex);
64 auto I = Notifiers.find(x: TrampolineAddr);
65 if (I != Notifiers.end()) {
66 NotifyResolved = std::move(I->second);
67 Notifiers.erase(position: I);
68 }
69 }
70
71 return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
72}
73
74void LazyCallThroughManager::resolveTrampolineLandingAddress(
75 ExecutorAddr TrampolineAddr,
76 NotifyLandingResolvedFunction NotifyLandingResolved) {
77
78 auto Entry = findReexport(TrampolineAddr);
79 if (!Entry)
80 return NotifyLandingResolved(reportCallThroughError(Err: Entry.takeError()));
81
82 // Declaring SLS and the callback outside of the call to ES.lookup is a
83 // workaround to fix build failures on AIX and on z/OS platforms.
84 SymbolLookupSet SLS({Entry->SymbolName});
85 auto Callback = [this, TrampolineAddr, SymbolName = Entry->SymbolName,
86 NotifyLandingResolved = std::move(NotifyLandingResolved)](
87 Expected<SymbolMap> Result) mutable {
88 if (Result) {
89 assert(Result->size() == 1 && "Unexpected result size");
90 assert(Result->count(SymbolName) && "Unexpected result value");
91 ExecutorAddr LandingAddr = (*Result)[SymbolName].getAddress();
92
93 if (auto Err = notifyResolved(TrampolineAddr, ResolvedAddr: LandingAddr))
94 NotifyLandingResolved(reportCallThroughError(Err: std::move(Err)));
95 else
96 NotifyLandingResolved(LandingAddr);
97 } else {
98 NotifyLandingResolved(reportCallThroughError(Err: Result.takeError()));
99 }
100 };
101
102 ES.lookup(K: LookupKind::Static,
103 SearchOrder: makeJITDylibSearchOrder(JDs: Entry->SourceJD,
104 Flags: JITDylibLookupFlags::MatchAllSymbols),
105 Symbols: std::move(SLS), RequiredState: SymbolState::Ready, NotifyComplete: std::move(Callback),
106 RegisterDependencies: NoDependenciesToRegister);
107}
108
109Expected<std::unique_ptr<LazyCallThroughManager>>
110createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
111 ExecutorAddr ErrorHandlerAddr) {
112 switch (T.getArch()) {
113 default:
114 return make_error<StringError>(
115 Args: std::string("No callback manager available for ") + T.str(),
116 Args: inconvertibleErrorCode());
117
118 case Triple::aarch64:
119 case Triple::aarch64_32:
120 return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
121 ErrorHandlerAddr);
122
123 case Triple::x86:
124 return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
125
126 case Triple::loongarch64:
127 return LocalLazyCallThroughManager::Create<OrcLoongArch64>(
128 ES, ErrorHandlerAddr);
129
130 case Triple::mips:
131 return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
132 ErrorHandlerAddr);
133
134 case Triple::mipsel:
135 return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
136 ErrorHandlerAddr);
137
138 case Triple::mips64:
139 case Triple::mips64el:
140 return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
141
142 case Triple::riscv64:
143 return LocalLazyCallThroughManager::Create<OrcRiscv64>(ES,
144 ErrorHandlerAddr);
145
146 case Triple::x86_64:
147 if (T.getOS() == Triple::OSType::Win32)
148 return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
149 ES, ErrorHandlerAddr);
150 else
151 return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
152 ES, ErrorHandlerAddr);
153 }
154}
155
156LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
157 LazyCallThroughManager &LCTManager, RedirectableSymbolManager &RSManager,
158 JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
159 : MaterializationUnit(extractFlags(Aliases: CallableAliases)),
160 LCTManager(LCTManager), RSManager(RSManager), SourceJD(SourceJD),
161 CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
162
163StringRef LazyReexportsMaterializationUnit::getName() const {
164 return "<Lazy Reexports>";
165}
166
167void LazyReexportsMaterializationUnit::materialize(
168 std::unique_ptr<MaterializationResponsibility> R) {
169 auto RequestedSymbols = R->getRequestedSymbols();
170
171 SymbolAliasMap RequestedAliases;
172 for (auto &RequestedSymbol : RequestedSymbols) {
173 auto I = CallableAliases.find(Val: RequestedSymbol);
174 assert(I != CallableAliases.end() && "Symbol not found in alias map?");
175 RequestedAliases[I->first] = std::move(I->second);
176 CallableAliases.erase(I);
177 }
178
179 if (!CallableAliases.empty())
180 if (auto Err = R->replace(MU: lazyReexports(LCTManager, RSManager, SourceJD,
181 CallableAliases: std::move(CallableAliases),
182 SrcJDLoc: AliaseeTable))) {
183 R->getExecutionSession().reportError(Err: std::move(Err));
184 R->failMaterialization();
185 return;
186 }
187
188 SymbolMap Inits;
189 for (auto &Alias : RequestedAliases) {
190 auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
191 SourceJD, SymbolName: Alias.second.Aliasee,
192 NotifyResolved: [&TargetJD = R->getTargetJITDylib(), &RSManager = this->RSManager,
193 StubSym = Alias.first](ExecutorAddr ResolvedAddr) -> Error {
194 return RSManager.redirect(JD&: TargetJD, Symbol: StubSym,
195 NewDest: ExecutorSymbolDef(ResolvedAddr, {}));
196 });
197
198 if (!CallThroughTrampoline) {
199 R->getExecutionSession().reportError(Err: CallThroughTrampoline.takeError());
200 R->failMaterialization();
201 return;
202 }
203
204 Inits[Alias.first] = {*CallThroughTrampoline, Alias.second.AliasFlags};
205 }
206
207 if (AliaseeTable != nullptr && !RequestedAliases.empty())
208 AliaseeTable->trackImpls(ImplMaps: RequestedAliases, SrcJD: &SourceJD);
209
210 if (auto Err = R->replace(MU: std::make_unique<RedirectableMaterializationUnit>(
211 args&: RSManager, args: std::move(Inits)))) {
212 R->getExecutionSession().reportError(Err: std::move(Err));
213 return R->failMaterialization();
214 }
215}
216
217void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
218 const SymbolStringPtr &Name) {
219 assert(CallableAliases.count(Name) &&
220 "Symbol not covered by this MaterializationUnit");
221 CallableAliases.erase(Val: Name);
222}
223
224MaterializationUnit::Interface
225LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
226 SymbolFlagsMap SymbolFlags;
227 for (auto &KV : Aliases) {
228 assert(KV.second.AliasFlags.isCallable() &&
229 "Lazy re-exports must be callable symbols");
230 SymbolFlags[KV.first] = KV.second.AliasFlags;
231 }
232 return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr);
233}
234
235class LazyReexportsManager::MU : public MaterializationUnit {
236public:
237 MU(LazyReexportsManager &LRMgr, SymbolAliasMap Reexports)
238 : MaterializationUnit(getInterface(Reexports)), LRMgr(LRMgr),
239 Reexports(std::move(Reexports)) {}
240
241private:
242 Interface getInterface(const SymbolAliasMap &Reexports) {
243 SymbolFlagsMap SF;
244 for (auto &[Alias, AI] : Reexports)
245 SF[Alias] = AI.AliasFlags;
246 return {std::move(SF), nullptr};
247 }
248
249 StringRef getName() const override { return "LazyReexportsManager::MU"; }
250
251 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
252 LRMgr.emitReentryTrampolines(MR: std::move(R), Reexports: std::move(Reexports));
253 }
254
255 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override {
256 Reexports.erase(Val: Name);
257 }
258
259 LazyReexportsManager &LRMgr;
260 SymbolAliasMap Reexports;
261};
262
263class LazyReexportsManager::Plugin : public ObjectLinkingLayer::Plugin {
264public:
265 void modifyPassConfig(MaterializationResponsibility &MR,
266 jitlink::LinkGraph &G,
267 jitlink::PassConfiguration &Config) override {}
268
269 Error notifyFailed(MaterializationResponsibility &MR) override {
270 return Error::success();
271 }
272
273 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
274 return Error::success();
275 }
276
277 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
278 ResourceKey SrcKey) override {}
279
280private:
281 std::mutex M;
282};
283
284LazyReexportsManager::Listener::~Listener() = default;
285
286Expected<std::unique_ptr<LazyReexportsManager>>
287LazyReexportsManager::Create(EmitTrampolinesFn EmitTrampolines,
288 RedirectableSymbolManager &RSMgr,
289 JITDylib &PlatformJD, Listener *L) {
290 Error Err = Error::success();
291 std::unique_ptr<LazyReexportsManager> LRM(new LazyReexportsManager(
292 std::move(EmitTrampolines), RSMgr, PlatformJD, L, Err));
293 if (Err)
294 return std::move(Err);
295 return std::move(LRM);
296}
297
298Error LazyReexportsManager::handleRemoveResources(JITDylib &JD, ResourceKey K) {
299 return JD.getExecutionSession().runSessionLocked(F: [&]() -> Error {
300 auto I = KeyToReentryAddrs.find(Val: K);
301 if (I == KeyToReentryAddrs.end())
302 return Error::success();
303
304 auto &ReentryAddrs = I->second;
305 for (auto &ReentryAddr : ReentryAddrs) {
306 assert(CallThroughs.count(ReentryAddr) && "CallTrhough missing");
307 CallThroughs.erase(Val: ReentryAddr);
308 }
309 KeyToReentryAddrs.erase(I);
310 return L ? L->onLazyReexportsRemoved(JD, K) : Error::success();
311 });
312}
313
314void LazyReexportsManager::handleTransferResources(JITDylib &JD,
315 ResourceKey DstK,
316 ResourceKey SrcK) {
317 auto I = KeyToReentryAddrs.find(Val: SrcK);
318 if (I != KeyToReentryAddrs.end()) {
319 auto J = KeyToReentryAddrs.find(Val: DstK);
320 if (J == KeyToReentryAddrs.end()) {
321 auto Tmp = std::move(I->second);
322 KeyToReentryAddrs.erase(I);
323 KeyToReentryAddrs[DstK] = std::move(Tmp);
324 } else {
325 auto &SrcAddrs = I->second;
326 auto &DstAddrs = J->second;
327 llvm::append_range(C&: DstAddrs, R&: SrcAddrs);
328 KeyToReentryAddrs.erase(I);
329 }
330 if (L)
331 L->onLazyReexportsTransfered(JD, DstK, SrcK);
332 }
333}
334
335LazyReexportsManager::LazyReexportsManager(EmitTrampolinesFn EmitTrampolines,
336 RedirectableSymbolManager &RSMgr,
337 JITDylib &PlatformJD, Listener *L,
338 Error &Err)
339 : ES(PlatformJD.getExecutionSession()),
340 EmitTrampolines(std::move(EmitTrampolines)), RSMgr(RSMgr), L(L) {
341
342 using namespace shared;
343 ErrorAsOutParameter _(&Err);
344 using ResolveSPSSig = SPSExpected<SPSExecutorSymbolDef>(SPSExecutorAddr);
345 Err = ES.registerCallControllerHandlers(
346 JD&: PlatformJD, Hs: bindCallControllerHandlerSPS<ResolveSPSSig>(
347 Name: SymbolNameSpec::c(Name: "__orc_rt_resolve_tag"), Instance: this,
348 Method: &LazyReexportsManager::resolve));
349}
350
351std::unique_ptr<MaterializationUnit>
352LazyReexportsManager::createLazyReexports(SymbolAliasMap Reexports) {
353 return std::make_unique<MU>(args&: *this, args: std::move(Reexports));
354}
355
356void LazyReexportsManager::emitReentryTrampolines(
357 std::unique_ptr<MaterializationResponsibility> MR,
358 SymbolAliasMap Reexports) {
359 size_t NumTrampolines = Reexports.size();
360 auto RT = MR->getResourceTracker();
361 EmitTrampolines(
362 std::move(RT), NumTrampolines,
363 [this, MR = std::move(MR), Reexports = std::move(Reexports)](
364 Expected<std::vector<ExecutorSymbolDef>> ReentryPoints) mutable {
365 emitRedirectableSymbols(MR: std::move(MR), Reexports: std::move(Reexports),
366 ReentryPoints: std::move(ReentryPoints));
367 });
368}
369
370void LazyReexportsManager::emitRedirectableSymbols(
371 std::unique_ptr<MaterializationResponsibility> MR, SymbolAliasMap Reexports,
372 Expected<std::vector<ExecutorSymbolDef>> ReentryPoints) {
373
374 if (!ReentryPoints) {
375 MR->getExecutionSession().reportError(Err: ReentryPoints.takeError());
376 MR->failMaterialization();
377 return;
378 }
379
380 assert(Reexports.size() == ReentryPoints->size() &&
381 "Number of reentry points doesn't match number of reexports");
382
383 // Bind entry points to names.
384 SymbolMap Redirs;
385 size_t I = 0;
386 for (auto &[Name, AI] : Reexports)
387 Redirs[Name] = {(*ReentryPoints)[I++].getAddress(), AI.AliasFlags};
388
389 I = 0;
390 if (!Reexports.empty()) {
391 if (auto Err = MR->withResourceKeyDo(F: [&](ResourceKey K) {
392 auto &JD = MR->getTargetJITDylib();
393 auto &ReentryAddrsForK = KeyToReentryAddrs[K];
394 for (auto &[Name, AI] : Reexports) {
395 const auto &ReentryPoint = (*ReentryPoints)[I++];
396 CallThroughs[ReentryPoint.getAddress()] = {.JD: &JD, .Name: Name, .BodyName: AI.Aliasee};
397 ReentryAddrsForK.push_back(x: ReentryPoint.getAddress());
398 }
399 if (L)
400 L->onLazyReexportsCreated(JD, K, Reexports);
401 })) {
402 MR->getExecutionSession().reportError(Err: std::move(Err));
403 MR->failMaterialization();
404 return;
405 }
406 }
407
408 RSMgr.emitRedirectableSymbols(MR: std::move(MR), InitialDests: std::move(Redirs));
409}
410
411void LazyReexportsManager::resolve(ResolveSendResultFn SendResult,
412 ExecutorAddr ReentryStubAddr) {
413
414 CallThroughInfo LandingInfo;
415
416 ES.runSessionLocked(F: [&]() {
417 auto I = CallThroughs.find(Val: ReentryStubAddr);
418 if (I == CallThroughs.end())
419 return SendResult(make_error<StringError>(
420 Args: "Reentry address " + formatv(Fmt: "{0:x}", Vals&: ReentryStubAddr) +
421 " not registered",
422 Args: inconvertibleErrorCode()));
423 LandingInfo = I->second;
424 });
425
426 if (L)
427 L->onLazyReexportCalled(CTI: LandingInfo);
428
429 ES.lookup(
430 K: LookupKind::Static,
431 SearchOrder: {{LandingInfo.JD.get(), JITDylibLookupFlags::MatchAllSymbols}},
432 Symbols: SymbolLookupSet(std::move(LandingInfo.BodyName)), RequiredState: SymbolState::Ready,
433 NotifyComplete: [this, JD = std::move(LandingInfo.JD),
434 ReentryName = std::move(LandingInfo.Name),
435 SendResult = std::move(SendResult)](Expected<SymbolMap> Result) mutable {
436 if (!Result)
437 return SendResult(Result.takeError());
438
439 assert(Result->size() == 1 && "Unexpected number of results");
440 auto BodySym = Result->begin()->second;
441 if (auto Err = RSMgr.redirect(JD&: *JD, Symbol: ReentryName, NewDest: BodySym))
442 SendResult(std::move(Err));
443 SendResult(BodySym);
444 },
445 RegisterDependencies: NoDependenciesToRegister);
446}
447
448class SimpleLazyReexportsSpeculator::SpeculateTask : public IdleTask {
449public:
450 SpeculateTask(std::weak_ptr<SimpleLazyReexportsSpeculator> Speculator)
451 : Speculator(std::move(Speculator)) {}
452
453 void printDescription(raw_ostream &OS) override {
454 OS << "Speculative Lookup Task";
455 }
456
457 void run() override {
458 if (auto S = Speculator.lock())
459 S->doNextSpeculativeLookup();
460 }
461
462private:
463 std::weak_ptr<SimpleLazyReexportsSpeculator> Speculator;
464};
465
466SimpleLazyReexportsSpeculator::~SimpleLazyReexportsSpeculator() {
467 for (auto &[JD, _] : LazyReexports)
468 JITDylibSP(JD)->Release();
469}
470
471void SimpleLazyReexportsSpeculator::onLazyReexportsCreated(
472 JITDylib &JD, ResourceKey K, const SymbolAliasMap &Reexports) {
473 if (!LazyReexports.count(Val: &JD))
474 JD.Retain();
475 auto &BodiesVec = LazyReexports[&JD][K];
476 for (auto &[Name, AI] : Reexports)
477 BodiesVec.push_back(x: AI.Aliasee);
478 if (!SpeculateTaskActive) {
479 SpeculateTaskActive = true;
480 ES.dispatchTask(T: std::make_unique<SpeculateTask>(args&: WeakThis));
481 }
482}
483
484void SimpleLazyReexportsSpeculator::onLazyReexportsTransfered(
485 JITDylib &JD, ResourceKey DstK, ResourceKey SrcK) {
486
487 auto I = LazyReexports.find(Val: &JD);
488 if (I == LazyReexports.end())
489 return;
490
491 auto &MapForJD = I->second;
492 auto J = MapForJD.find(Val: SrcK);
493 if (J == MapForJD.end())
494 return;
495
496 // We have something to transfer.
497 auto K = MapForJD.find(Val: DstK);
498 if (K == MapForJD.end()) {
499 auto Tmp = std::move(J->second);
500 MapForJD.erase(I: J);
501 MapForJD[DstK] = std::move(Tmp);
502 } else {
503 auto &SrcNames = J->second;
504 auto &DstNames = K->second;
505 llvm::append_range(C&: DstNames, R&: SrcNames);
506 MapForJD.erase(I: J);
507 }
508}
509
510Error SimpleLazyReexportsSpeculator::onLazyReexportsRemoved(JITDylib &JD,
511 ResourceKey K) {
512
513 auto I = LazyReexports.find(Val: &JD);
514 if (I == LazyReexports.end())
515 return Error::success();
516
517 auto &MapForJD = I->second;
518 MapForJD.erase(Val: K);
519
520 if (MapForJD.empty()) {
521 LazyReexports.erase(I);
522 JD.Release();
523 }
524
525 return Error::success();
526}
527
528void SimpleLazyReexportsSpeculator::onLazyReexportCalled(
529 const CallThroughInfo &CTI) {
530 if (RecordExec)
531 RecordExec(CTI);
532}
533
534void SimpleLazyReexportsSpeculator::addSpeculationSuggestions(
535 std::vector<std::pair<std::string, SymbolStringPtr>> NewSuggestions) {
536 ES.runSessionLocked(F: [&]() {
537 for (auto &[JDName, SymbolName] : NewSuggestions)
538 SpeculateSuggestions.push_back(
539 x: {std::move(JDName), std::move(SymbolName)});
540 });
541}
542
543bool SimpleLazyReexportsSpeculator::doNextSpeculativeLookup() {
544 // Use existing speculation queue if available, otherwise take the next
545 // element from LazyReexports.
546 JITDylibSP SpeculateJD = nullptr;
547 SymbolStringPtr SpeculateFn;
548
549 auto SpeculateAgain = ES.runSessionLocked(F: [&]() {
550 while (!SpeculateSuggestions.empty()) {
551 auto [JDName, SymbolName] = std::move(SpeculateSuggestions.front());
552 SpeculateSuggestions.pop_front();
553
554 if (auto *JD = ES.getJITDylibByName(Name: JDName)) {
555 SpeculateJD = JD;
556 SpeculateFn = std::move(SymbolName);
557 break;
558 }
559 }
560
561 if (!SpeculateJD) {
562 assert(!LazyReexports.empty() && "LazyReexports map is empty");
563 auto LRItr =
564 std::next(x: LazyReexports.begin(), n: rand() % LazyReexports.size());
565 auto &[JD, KeyToFnBodies] = *LRItr;
566
567 assert(!KeyToFnBodies.empty() && "Key to function bodies map empty");
568 auto KeyToFnBodiesItr =
569 std::next(x: KeyToFnBodies.begin(), n: rand() % KeyToFnBodies.size());
570 auto &[Key, FnBodies] = *KeyToFnBodiesItr;
571
572 assert(!FnBodies.empty() && "Function bodies list empty");
573 auto FnBodyItr = std::next(x: FnBodies.begin(), n: rand() % FnBodies.size());
574
575 SpeculateJD = JITDylibSP(JD);
576 SpeculateFn = std::move(*FnBodyItr);
577
578 FnBodies.erase(position: FnBodyItr);
579 if (FnBodies.empty()) {
580 KeyToFnBodies.erase(I: KeyToFnBodiesItr);
581 if (KeyToFnBodies.empty()) {
582 LRItr->first->Release();
583 LazyReexports.erase(I: LRItr);
584 }
585 }
586 }
587
588 SpeculateTaskActive =
589 !SpeculateSuggestions.empty() || !LazyReexports.empty();
590 return SpeculateTaskActive;
591 });
592
593 LLVM_DEBUG({
594 dbgs() << "Issuing speculative lookup for ( " << SpeculateJD->getName()
595 << ", " << SpeculateFn << " )...\n";
596 });
597
598 ES.lookup(
599 K: LookupKind::Static, SearchOrder: makeJITDylibSearchOrder(JDs: SpeculateJD.get()),
600 Symbols: {{std::move(SpeculateFn), SymbolLookupFlags::WeaklyReferencedSymbol}},
601 RequiredState: SymbolState::Ready,
602 NotifyComplete: [](Expected<SymbolMap> Result) { consumeError(Err: Result.takeError()); },
603 RegisterDependencies: NoDependenciesToRegister);
604
605 if (SpeculateAgain)
606 ES.dispatchTask(T: std::make_unique<SpeculateTask>(args&: WeakThis));
607
608 return false;
609}
610
611} // End namespace orc.
612} // End namespace llvm.
613