17#define DEBUG_TYPE "orc"
25 : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
30 assert(TP &&
"TrampolinePool not set");
32 std::lock_guard<std::mutex> Lock(LCTMMutex);
33 auto Trampoline = TP->getTrampoline();
36 return Trampoline.takeError();
38 Reexports[*Trampoline] =
ReexportsEntry{&SourceJD, std::move(SymbolName)};
39 Notifiers[*Trampoline] = std::move(NotifyResolved);
44 ES.reportError(std::move(Err));
45 return ErrorHandlerAddr;
50 std::lock_guard<std::mutex> Lock(LCTMMutex);
51 auto I = Reexports.find(TrampolineAddr);
52 if (
I == Reexports.end())
54 "Missing reexport for trampoline address %p" +
55 formatv(
"{0:x}", TrampolineAddr));
63 std::lock_guard<std::mutex> Lock(LCTMMutex);
64 auto I = Notifiers.find(TrampolineAddr);
65 if (
I != Notifiers.end()) {
66 NotifyResolved = std::move(
I->second);
71 return NotifyResolved ? NotifyResolved(ResolvedAddr) :
Error::success();
85 auto Callback = [
this, TrampolineAddr, SymbolName = Entry->SymbolName,
86 NotifyLandingResolved = std::move(NotifyLandingResolved)](
90 assert(
Result->count(SymbolName) &&
"Unexpected result value");
91 ExecutorAddr LandingAddr = (*Result)[SymbolName].getAddress();
96 NotifyLandingResolved(LandingAddr);
112 switch (
T.getArch()) {
115 std::string(
"No callback manager available for ") +
T.str(),
128 ES, ErrorHandlerAddr);
149 ES, ErrorHandlerAddr);
152 ES, ErrorHandlerAddr);
160 LCTManager(LCTManager), RSManager(RSManager), SourceJD(SourceJD),
161 CallableAliases(
std::
move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
164 return "<Lazy Reexports>";
167void LazyReexportsMaterializationUnit::materialize(
168 std::unique_ptr<MaterializationResponsibility> R) {
169 auto RequestedSymbols = R->getRequestedSymbols();
172 for (
auto &RequestedSymbol : RequestedSymbols) {
173 auto I = CallableAliases.
find(RequestedSymbol);
174 assert(
I != CallableAliases.
end() &&
"Symbol not found in alias map?");
175 RequestedAliases[
I->first] = std::move(
I->second);
179 if (!CallableAliases.
empty())
180 if (
auto Err = R->replace(
lazyReexports(LCTManager, RSManager, SourceJD,
181 std::move(CallableAliases),
183 R->getExecutionSession().reportError(std::move(Err));
184 R->failMaterialization();
189 for (
auto &Alias : RequestedAliases) {
191 SourceJD, Alias.second.Aliasee,
192 [&TargetJD = R->getTargetJITDylib(), &RSManager = this->RSManager,
193 StubSym = Alias.first](ExecutorAddr ResolvedAddr) -> Error {
194 return RSManager.redirect(TargetJD, StubSym,
195 ExecutorSymbolDef(ResolvedAddr, {}));
198 if (!CallThroughTrampoline) {
199 R->getExecutionSession().reportError(CallThroughTrampoline.takeError());
200 R->failMaterialization();
204 Inits[Alias.first] = {*CallThroughTrampoline, Alias.second.AliasFlags};
207 if (AliaseeTable !=
nullptr && !RequestedAliases.empty())
208 AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
210 if (
auto Err =
R->replace(std::make_unique<RedirectableMaterializationUnit>(
211 RSManager, std::move(Inits)))) {
212 R->getExecutionSession().reportError(std::move(Err));
213 return R->failMaterialization();
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(Name);
224MaterializationUnit::Interface
225LazyReexportsMaterializationUnit::extractFlags(
const SymbolAliasMap &Aliases) {
227 for (
auto &KV : Aliases) {
228 assert(KV.second.AliasFlags.isCallable() &&
229 "Lazy re-exports must be callable symbols");
232 return MaterializationUnit::Interface(std::move(SymbolFlags),
nullptr);
239 Reexports(
std::
move(Reexports)) {}
244 for (
auto &[Alias, AI] : Reexports)
245 SF[Alias] = AI.AliasFlags;
246 return {std::move(SF),
nullptr};
251 void materialize(std::unique_ptr<MaterializationResponsibility> R)
override {
252 LRMgr.emitReentryTrampolines(std::move(R), std::move(Reexports));
255 void discard(
const JITDylib &JD,
const SymbolStringPtr &Name)
override {
256 Reexports.
erase(Name);
259 LazyReexportsManager &LRMgr;
292 std::move(EmitTrampolines), RSMgr, PlatformJD, L, Err));
294 return std::move(Err);
295 return std::move(LRM);
300 auto I = KeyToReentryAddrs.find(
K);
301 if (
I == KeyToReentryAddrs.end())
304 auto &ReentryAddrs =
I->second;
305 for (
auto &ReentryAddr : ReentryAddrs) {
306 assert(CallThroughs.count(ReentryAddr) &&
"CallTrhough missing");
307 CallThroughs.erase(ReentryAddr);
309 KeyToReentryAddrs.erase(
I);
317 auto I = KeyToReentryAddrs.find(SrcK);
318 if (
I != KeyToReentryAddrs.end()) {
319 auto J = KeyToReentryAddrs.find(DstK);
320 if (J == KeyToReentryAddrs.end()) {
321 auto Tmp = std::move(
I->second);
322 KeyToReentryAddrs.erase(
I);
323 KeyToReentryAddrs[DstK] = std::move(Tmp);
325 auto &SrcAddrs =
I->second;
326 auto &DstAddrs = J->second;
328 KeyToReentryAddrs.erase(
I);
331 L->onLazyReexportsTransfered(JD, DstK, SrcK);
339 : ES(PlatformJD.getExecutionSession()),
340 EmitTrampolines(
std::
move(EmitTrampolines)), RSMgr(RSMgr), L(L) {
344 using ResolveSPSSig = SPSExpected<SPSExecutorSymbolDef>(SPSExecutorAddr);
348 &LazyReexportsManager::resolve));
351std::unique_ptr<MaterializationUnit>
352LazyReexportsManager::createLazyReexports(
SymbolAliasMap Reexports) {
353 return std::make_unique<MU>(*
this, std::move(Reexports));
356void LazyReexportsManager::emitReentryTrampolines(
357 std::unique_ptr<MaterializationResponsibility> MR,
359 size_t NumTrampolines = Reexports.size();
360 auto RT = MR->getResourceTracker();
362 std::move(RT), NumTrampolines,
363 [
this, MR = std::move(MR), Reexports = std::move(Reexports)](
364 Expected<std::vector<ExecutorSymbolDef>> ReentryPoints)
mutable {
365 emitRedirectableSymbols(std::move(MR), std::move(Reexports),
366 std::move(ReentryPoints));
370void LazyReexportsManager::emitRedirectableSymbols(
371 std::unique_ptr<MaterializationResponsibility> MR,
SymbolAliasMap Reexports,
372 Expected<std::vector<ExecutorSymbolDef>> ReentryPoints) {
374 if (!ReentryPoints) {
375 MR->getExecutionSession().reportError(ReentryPoints.takeError());
376 MR->failMaterialization();
380 assert(Reexports.size() == ReentryPoints->size() &&
381 "Number of reentry points doesn't match number of reexports");
386 for (
auto &[Name, AI] : Reexports)
387 Redirs[
Name] = {(*ReentryPoints)[
I++].getAddress(), AI.AliasFlags};
390 if (!Reexports.empty()) {
391 if (
auto Err = MR->withResourceKeyDo([&](
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, Name, AI.Aliasee};
397 ReentryAddrsForK.push_back(ReentryPoint.getAddress());
400 L->onLazyReexportsCreated(JD, K, Reexports);
402 MR->getExecutionSession().reportError(std::move(Err));
403 MR->failMaterialization();
411void LazyReexportsManager::resolve(ResolveSendResultFn SendResult,
412 ExecutorAddr ReentryStubAddr) {
414 CallThroughInfo LandingInfo;
416 ES.runSessionLocked([&]() {
417 auto I = CallThroughs.find(ReentryStubAddr);
418 if (
I == CallThroughs.end())
420 "Reentry address " +
formatv(
"{0:x}", ReentryStubAddr) +
423 LandingInfo =
I->second;
427 L->onLazyReexportCalled(LandingInfo);
431 {{LandingInfo.JD.get(), JITDylibLookupFlags::MatchAllSymbols}},
432 SymbolLookupSet(std::move(LandingInfo.BodyName)), SymbolState::Ready,
433 [
this, JD = std::move(LandingInfo.JD),
434 ReentryName = std::move(LandingInfo.Name),
437 return SendResult(
Result.takeError());
439 assert(
Result->size() == 1 &&
"Unexpected number of results");
440 auto BodySym =
Result->begin()->second;
441 if (
auto Err = RSMgr.
redirect(*JD, ReentryName, BodySym))
442 SendResult(std::move(Err));
451 : Speculator(
std::
move(Speculator)) {}
454 OS <<
"Speculative Lookup Task";
458 if (
auto S = Speculator.lock())
459 S->doNextSpeculativeLookup();
463 std::weak_ptr<SimpleLazyReexportsSpeculator>
Speculator;
467 for (
auto &[JD,
_] : LazyReexports)
473 if (!LazyReexports.count(&JD))
475 auto &BodiesVec = LazyReexports[&JD][
K];
476 for (
auto &[Name, AI] : Reexports)
477 BodiesVec.push_back(AI.Aliasee);
478 if (!SpeculateTaskActive) {
479 SpeculateTaskActive =
true;
480 ES.dispatchTask(std::make_unique<SpeculateTask>(WeakThis));
487 auto I = LazyReexports.find(&JD);
488 if (
I == LazyReexports.end())
491 auto &MapForJD =
I->second;
492 auto J = MapForJD.find(SrcK);
493 if (J == MapForJD.end())
497 auto K = MapForJD.find(DstK);
498 if (
K == MapForJD.end()) {
499 auto Tmp = std::move(J->second);
501 MapForJD[DstK] = std::move(Tmp);
503 auto &SrcNames = J->second;
504 auto &DstNames =
K->second;
513 auto I = LazyReexports.find(&JD);
514 if (
I == LazyReexports.end())
517 auto &MapForJD =
I->second;
520 if (MapForJD.empty()) {
521 LazyReexports.erase(
I);
535 std::vector<std::pair<std::string, SymbolStringPtr>> NewSuggestions) {
536 ES.runSessionLocked([&]() {
537 for (
auto &[JDName, SymbolName] : NewSuggestions)
538 SpeculateSuggestions.push_back(
539 {std::move(JDName), std::move(SymbolName)});
543bool SimpleLazyReexportsSpeculator::doNextSpeculativeLookup() {
549 auto SpeculateAgain = ES.runSessionLocked([&]() {
550 while (!SpeculateSuggestions.empty()) {
551 auto [JDName, SymbolName] = std::move(SpeculateSuggestions.front());
552 SpeculateSuggestions.pop_front();
554 if (
auto *JD = ES.getJITDylibByName(JDName)) {
556 SpeculateFn = std::move(SymbolName);
562 assert(!LazyReexports.empty() &&
"LazyReexports map is empty");
564 std::next(LazyReexports.begin(), rand() % LazyReexports.size());
565 auto &[JD, KeyToFnBodies] = *LRItr;
567 assert(!KeyToFnBodies.empty() &&
"Key to function bodies map empty");
568 auto KeyToFnBodiesItr =
569 std::next(KeyToFnBodies.begin(), rand() % KeyToFnBodies.size());
570 auto &[
Key, FnBodies] = *KeyToFnBodiesItr;
572 assert(!FnBodies.empty() &&
"Function bodies list empty");
573 auto FnBodyItr = std::next(FnBodies.begin(), rand() % FnBodies.size());
575 SpeculateJD = JITDylibSP(JD);
576 SpeculateFn = std::move(*FnBodyItr);
578 FnBodies.erase(FnBodyItr);
579 if (FnBodies.empty()) {
580 KeyToFnBodies.erase(KeyToFnBodiesItr);
581 if (KeyToFnBodies.empty()) {
582 LRItr->first->Release();
583 LazyReexports.erase(LRItr);
588 SpeculateTaskActive =
589 !SpeculateSuggestions.empty() || !LazyReexports.empty();
590 return SpeculateTaskActive;
594 dbgs() <<
"Issuing speculative lookup for ( " << SpeculateJD->getName()
595 <<
", " << SpeculateFn <<
" )...\n";
600 {{std::move(SpeculateFn), SymbolLookupFlags::WeaklyReferencedSymbol}},
606 ES.dispatchTask(std::make_unique<SpeculateTask>(WeakThis));
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static StringRef getName(Value *V)
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
Helper for Errors used as out-parameters.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Represent a constant reference to a string, i.e.
Triple - Helper class for working with autoconf configuration names.
An ExecutionSession represents a running JIT program.
LLVM_ABI Error registerCallControllerHandlers(JITDylib &JD, std::vector< CallControllerHandlerBinding > Hs)
For each binding, look up its tag symbol in JD and register the binding's call-controller handler for...
decltype(auto) runSessionLocked(Func &&F)
Run the given lambda with the session mutex locked.
Represents an address in the executor process.
IdleTask can be used as the basis for low-priority tasks, e.g.
Represents a JIT'd dynamic library.
ExecutionSession & getExecutionSession() const
Get a reference to the ExecutionSession for this JITDylib.
Manages a set of 'lazy call-through' trampolines.
LLVM_ABI ExecutorAddr reportCallThroughError(Error Err)
TrampolinePool::NotifyLandingResolvedFunction NotifyLandingResolvedFunction
LLVM_ABI Expected< ReexportsEntry > findReexport(ExecutorAddr TrampolineAddr)
LLVM_ABI Error notifyResolved(ExecutorAddr TrampolineAddr, ExecutorAddr ResolvedAddr)
LLVM_ABI void resolveTrampolineLandingAddress(ExecutorAddr TrampolineAddr, TrampolinePool::NotifyLandingResolvedFunction NotifyLandingResolved)
unique_function< Error(ExecutorAddr ResolvedAddr)> NotifyResolvedFunction
LLVM_ABI LazyCallThroughManager(ExecutionSession &ES, ExecutorAddr ErrorHandlerAddr, TrampolinePool *TP)
LLVM_ABI Expected< ExecutorAddr > getCallThroughTrampoline(JITDylib &SourceJD, SymbolStringPtr SymbolName, NotifyResolvedFunction NotifyResolved)
LazyReexportsManager::CallThroughInfo CallThroughInfo
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
void handleTransferResources(JITDylib &JD, ResourceKey DstK, ResourceKey SrcK) override
This function will be called inside the session lock.
Error handleRemoveResources(JITDylib &JD, ResourceKey K) override
This function will be called outside the session lock.
unique_function< void(ResourceTrackerSP RT, size_t NumTrampolines, OnTrampolinesReadyFn OnTrampolinesReady)> EmitTrampolinesFn
LazyReexportsManager(LazyReexportsManager &&)=delete
static Expected< std::unique_ptr< LazyReexportsManager > > Create(EmitTrampolinesFn EmitTrampolines, RedirectableSymbolManager &RSMgr, JITDylib &PlatformJD, Listener *L=nullptr)
Create a LazyReexportsManager that uses the ORC runtime for reentry.
LazyReexportsMaterializationUnit(LazyCallThroughManager &LCTManager, RedirectableSymbolManager &RSManager, JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
StringRef getName() const override
Return the name of this materialization unit.
Plugin instances can be added to the ObjectLinkingLayer to receive callbacks when code is loaded or e...
static Expected< std::unique_ptr< LocalLazyCallThroughManager > > Create(ExecutionSession &ES, ExecutorAddr ErrorHandlerAddr)
Create a LocalLazyCallThroughManager using the given ABI.
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
MaterializationUnit(Interface I)
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.
virtual Error redirect(JITDylib &JD, const SymbolMap &NewDests)=0
Change the redirection destination of given symbols to new destination symbols.
SpeculateTask(std::weak_ptr< SimpleLazyReexportsSpeculator > Speculator)
void printDescription(raw_ostream &OS) override
Error onLazyReexportsRemoved(JITDylib &JD, ResourceKey K) override
Called under the session lock when lazy reexports are removed.
~SimpleLazyReexportsSpeculator() override
void onLazyReexportsCreated(JITDylib &JD, ResourceKey K, const SymbolAliasMap &Reexports) override
Called under the session lock when new lazy reexports are created.
void onLazyReexportCalled(const CallThroughInfo &CTI) override
Called outside the session lock when a lazy reexport is called.
void onLazyReexportsTransfered(JITDylib &JD, ResourceKey DstK, ResourceKey SrcK) override
Called under the session lock when lazy reexports have their ownership transferred to a new ResourceK...
void addSpeculationSuggestions(std::vector< std::pair< std::string, SymbolStringPtr > > NewSuggestions)
A set of symbols to look up, each associated with a SymbolLookupFlags value.
static constexpr SymbolNameSpec c(StringRef Name)
Pointer to a pooled string representing a symbol name.
Base class for pools of compiler re-entry trampolines.
This class implements an extremely fast bulk output stream that can only output to a stream.
ExecutionSession::CallControllerHandlerBinding bindCallControllerHandlerSPS(SymbolNameSpec Name, HandlerT &&Handler, SymbolLookupFlags LF=SymbolLookupFlags::RequiredSymbol)
Bind a call-controller handler that takes concrete argument types (and a sender for a concrete return...
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...
IntrusiveRefCntPtr< JITDylib > JITDylibSP
DenseMap< SymbolStringPtr, ExecutorSymbolDef > SymbolMap
A map from symbol names (as SymbolStringPtrs) to JITSymbols (address/flags pairs).
LLVM_ABI 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.
LLVM_ABI RegisterDependenciesFunction NoDependenciesToRegister
This can be used as the value for a RegisterDependenciesFunction if there are no dependants to regist...
@ Ready
Emitted to memory, but waiting on transitive dependencies.
DenseMap< SymbolStringPtr, SymbolAliasMapEntry > SymbolAliasMap
A map of Symbols to (Symbol, Flags) pairs.
DenseMap< SymbolStringPtr, JITSymbolFlags > SymbolFlagsMap
A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
void consumeError(Error Err)
Consume a Error without doing anything.
Implement std::hash so that hash_code can be used in STL containers.
An LinkGraph pass configuration, consisting of a list of pre-prune, post-prune, and post-fixup passes...