18#define DEBUG_TYPE "orc"
26 : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
31 assert(TP &&
"TrampolinePool not set");
33 std::lock_guard<std::mutex> Lock(LCTMMutex);
34 auto Trampoline = TP->getTrampoline();
37 return Trampoline.takeError();
39 Reexports[*Trampoline] =
ReexportsEntry{&SourceJD, std::move(SymbolName)};
40 Notifiers[*Trampoline] = std::move(NotifyResolved);
45 ES.reportError(std::move(Err));
46 return ErrorHandlerAddr;
51 std::lock_guard<std::mutex> Lock(LCTMMutex);
52 auto I = Reexports.find(TrampolineAddr);
53 if (
I == Reexports.end())
55 "Missing reexport for trampoline address %p" +
56 formatv(
"{0:x}", TrampolineAddr));
64 std::lock_guard<std::mutex> Lock(LCTMMutex);
65 auto I = Notifiers.find(TrampolineAddr);
66 if (
I != Notifiers.end()) {
67 NotifyResolved = std::move(
I->second);
72 return NotifyResolved ? NotifyResolved(ResolvedAddr) :
Error::success();
86 auto Callback = [
this, TrampolineAddr, SymbolName = Entry->SymbolName,
87 NotifyLandingResolved = std::move(NotifyLandingResolved)](
91 assert(
Result->count(SymbolName) &&
"Unexpected result value");
92 ExecutorAddr LandingAddr = (*Result)[SymbolName].getAddress();
97 NotifyLandingResolved(LandingAddr);
113 switch (
T.getArch()) {
116 std::string(
"No callback manager available for ") +
T.str(),
129 ES, ErrorHandlerAddr);
150 ES, ErrorHandlerAddr);
153 ES, ErrorHandlerAddr);
161 LCTManager(LCTManager), RSManager(RSManager), SourceJD(SourceJD),
162 CallableAliases(
std::
move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
165 return "<Lazy Reexports>";
168void LazyReexportsMaterializationUnit::materialize(
169 std::unique_ptr<MaterializationResponsibility> R) {
170 auto RequestedSymbols = R->getRequestedSymbols();
173 for (
auto &RequestedSymbol : RequestedSymbols) {
174 auto I = CallableAliases.
find(RequestedSymbol);
175 assert(
I != CallableAliases.
end() &&
"Symbol not found in alias map?");
176 RequestedAliases[
I->first] = std::move(
I->second);
180 if (!CallableAliases.
empty())
181 if (
auto Err = R->replace(
lazyReexports(LCTManager, RSManager, SourceJD,
182 std::move(CallableAliases),
184 R->getExecutionSession().reportError(std::move(Err));
185 R->failMaterialization();
190 for (
auto &Alias : RequestedAliases) {
192 SourceJD, Alias.second.Aliasee,
193 [&TargetJD = R->getTargetJITDylib(), &RSManager = this->RSManager,
194 StubSym = Alias.first](ExecutorAddr ResolvedAddr) -> Error {
195 return RSManager.redirect(TargetJD, StubSym,
196 ExecutorSymbolDef(ResolvedAddr, {}));
199 if (!CallThroughTrampoline) {
200 R->getExecutionSession().reportError(CallThroughTrampoline.takeError());
201 R->failMaterialization();
205 Inits[Alias.first] = {*CallThroughTrampoline, Alias.second.AliasFlags};
208 if (AliaseeTable !=
nullptr && !RequestedAliases.empty())
209 AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
211 if (
auto Err =
R->replace(std::make_unique<RedirectableMaterializationUnit>(
212 RSManager, std::move(Inits)))) {
213 R->getExecutionSession().reportError(std::move(Err));
214 return R->failMaterialization();
218void LazyReexportsMaterializationUnit::discard(
const JITDylib &JD,
219 const SymbolStringPtr &Name) {
220 assert(CallableAliases.count(Name) &&
221 "Symbol not covered by this MaterializationUnit");
222 CallableAliases.erase(Name);
225MaterializationUnit::Interface
226LazyReexportsMaterializationUnit::extractFlags(
const SymbolAliasMap &Aliases) {
228 for (
auto &KV : Aliases) {
229 assert(KV.second.AliasFlags.isCallable() &&
230 "Lazy re-exports must be callable symbols");
233 return MaterializationUnit::Interface(std::move(SymbolFlags),
nullptr);
240 Reexports(
std::
move(Reexports)) {}
245 for (
auto &[Alias, AI] : Reexports)
246 SF[Alias] = AI.AliasFlags;
247 return {std::move(SF),
nullptr};
252 void materialize(std::unique_ptr<MaterializationResponsibility> R)
override {
253 LRMgr.emitReentryTrampolines(std::move(R), std::move(Reexports));
256 void discard(
const JITDylib &JD,
const SymbolStringPtr &Name)
override {
257 Reexports.
erase(Name);
260 LazyReexportsManager &LRMgr;
293 std::move(EmitTrampolines), RSMgr, PlatformJD, L, Err));
295 return std::move(Err);
296 return std::move(LRM);
301 auto I = KeyToReentryAddrs.find(
K);
302 if (
I == KeyToReentryAddrs.end())
305 auto &ReentryAddrs =
I->second;
306 for (
auto &ReentryAddr : ReentryAddrs) {
307 assert(CallThroughs.count(ReentryAddr) &&
"CallTrhough missing");
308 CallThroughs.erase(ReentryAddr);
310 KeyToReentryAddrs.erase(
I);
318 auto I = KeyToReentryAddrs.find(SrcK);
319 if (
I != KeyToReentryAddrs.end()) {
320 auto J = KeyToReentryAddrs.find(DstK);
321 if (J == KeyToReentryAddrs.end()) {
322 auto Tmp = std::move(
I->second);
323 KeyToReentryAddrs.erase(
I);
324 KeyToReentryAddrs[DstK] = std::move(Tmp);
326 auto &SrcAddrs =
I->second;
327 auto &DstAddrs = J->second;
329 KeyToReentryAddrs.erase(
I);
332 L->onLazyReexportsTransfered(JD, DstK, SrcK);
341 shared::SPSExecutorAddr)> {
351 : ES(PlatformJD.getExecutionSession()),
352 EmitTrampolines(
std::
move(EmitTrampolines)), RSMgr(RSMgr), L(L) {
356 Err = ES.registerCallControllerHandlers(
359 this, &LazyReexportsManager::resolve));
362std::unique_ptr<MaterializationUnit>
363LazyReexportsManager::createLazyReexports(
SymbolAliasMap Reexports) {
364 return std::make_unique<MU>(*
this, std::move(Reexports));
367void LazyReexportsManager::emitReentryTrampolines(
368 std::unique_ptr<MaterializationResponsibility> MR,
370 size_t NumTrampolines = Reexports.size();
371 auto RT = MR->getResourceTracker();
373 std::move(RT), NumTrampolines,
374 [
this, MR = std::move(MR), Reexports = std::move(Reexports)](
375 Expected<std::vector<ExecutorSymbolDef>> ReentryPoints)
mutable {
376 emitRedirectableSymbols(std::move(MR), std::move(Reexports),
377 std::move(ReentryPoints));
381void LazyReexportsManager::emitRedirectableSymbols(
382 std::unique_ptr<MaterializationResponsibility> MR,
SymbolAliasMap Reexports,
383 Expected<std::vector<ExecutorSymbolDef>> ReentryPoints) {
385 if (!ReentryPoints) {
386 MR->getExecutionSession().reportError(ReentryPoints.takeError());
387 MR->failMaterialization();
391 assert(Reexports.size() == ReentryPoints->size() &&
392 "Number of reentry points doesn't match number of reexports");
397 for (
auto &[Name, AI] : Reexports)
398 Redirs[
Name] = {(*ReentryPoints)[
I++].getAddress(), AI.AliasFlags};
401 if (!Reexports.empty()) {
402 if (
auto Err = MR->withResourceKeyDo([&](
ResourceKey K) {
403 auto &JD = MR->getTargetJITDylib();
404 auto &ReentryAddrsForK = KeyToReentryAddrs[K];
405 for (auto &[Name, AI] : Reexports) {
406 const auto &ReentryPoint = (*ReentryPoints)[I++];
407 CallThroughs[ReentryPoint.getAddress()] = {&JD, Name, AI.Aliasee};
408 ReentryAddrsForK.push_back(ReentryPoint.getAddress());
411 L->onLazyReexportsCreated(JD, K, Reexports);
413 MR->getExecutionSession().reportError(std::move(Err));
414 MR->failMaterialization();
422void LazyReexportsManager::resolve(ResolveSendResultFn SendResult,
427 ES.runSessionLocked([&]() {
428 auto I = CallThroughs.find(ReentryStubAddr);
429 if (
I == CallThroughs.end())
431 "Reentry address " +
formatv(
"{0:x}", ReentryStubAddr) +
434 LandingInfo =
I->second;
438 L->onLazyReexportCalled(LandingInfo);
444 [
this, JD = std::move(LandingInfo.JD),
445 ReentryName = std::move(LandingInfo.Name),
446 SendResult = std::move(SendResult)](Expected<SymbolMap>
Result)
mutable {
448 return SendResult(
Result.takeError());
450 assert(
Result->size() == 1 &&
"Unexpected number of results");
451 auto BodySym =
Result->begin()->second;
452 if (
auto Err = RSMgr.redirect(*JD, ReentryName, BodySym))
453 SendResult(std::move(Err));
462 : Speculator(
std::
move(Speculator)) {}
465 OS <<
"Speculative Lookup Task";
469 if (
auto S = Speculator.lock())
470 S->doNextSpeculativeLookup();
474 std::weak_ptr<SimpleLazyReexportsSpeculator>
Speculator;
478 for (
auto &[JD,
_] : LazyReexports)
484 if (!LazyReexports.count(&JD))
486 auto &BodiesVec = LazyReexports[&JD][
K];
487 for (
auto &[Name, AI] : Reexports)
488 BodiesVec.push_back(AI.Aliasee);
489 if (!SpeculateTaskActive) {
490 SpeculateTaskActive =
true;
491 ES.dispatchTask(std::make_unique<SpeculateTask>(WeakThis));
498 auto I = LazyReexports.find(&JD);
499 if (
I == LazyReexports.end())
502 auto &MapForJD =
I->second;
503 auto J = MapForJD.find(SrcK);
504 if (J == MapForJD.end())
508 auto K = MapForJD.find(DstK);
509 if (
K == MapForJD.end()) {
510 auto Tmp = std::move(J->second);
512 MapForJD[DstK] = std::move(Tmp);
514 auto &SrcNames = J->second;
515 auto &DstNames =
K->second;
524 auto I = LazyReexports.find(&JD);
525 if (
I == LazyReexports.end())
528 auto &MapForJD =
I->second;
531 if (MapForJD.empty()) {
532 LazyReexports.erase(
I);
546 std::vector<std::pair<std::string, SymbolStringPtr>> NewSuggestions) {
547 ES.runSessionLocked([&]() {
548 for (
auto &[JDName, SymbolName] : NewSuggestions)
549 SpeculateSuggestions.push_back(
550 {std::move(JDName), std::move(SymbolName)});
554bool SimpleLazyReexportsSpeculator::doNextSpeculativeLookup() {
561 while (!SpeculateSuggestions.empty()) {
562 auto [JDName, SymbolName] = std::move(SpeculateSuggestions.front());
563 SpeculateSuggestions.pop_front();
567 SpeculateFn = std::move(SymbolName);
573 assert(!LazyReexports.empty() &&
"LazyReexports map is empty");
575 std::next(LazyReexports.begin(), rand() % LazyReexports.size());
576 auto &[JD, KeyToFnBodies] = *LRItr;
578 assert(!KeyToFnBodies.empty() &&
"Key to function bodies map empty");
579 auto KeyToFnBodiesItr =
580 std::next(KeyToFnBodies.begin(), rand() % KeyToFnBodies.size());
581 auto &[
Key, FnBodies] = *KeyToFnBodiesItr;
583 assert(!FnBodies.empty() &&
"Function bodies list empty");
584 auto FnBodyItr = std::next(FnBodies.begin(), rand() % FnBodies.size());
587 SpeculateFn = std::move(*FnBodyItr);
589 FnBodies.erase(FnBodyItr);
590 if (FnBodies.empty()) {
591 KeyToFnBodies.erase(KeyToFnBodiesItr);
592 if (KeyToFnBodies.empty()) {
593 LRItr->first->Release();
594 LazyReexports.erase(LRItr);
599 SpeculateTaskActive =
600 !SpeculateSuggestions.empty() || !LazyReexports.empty();
601 return SpeculateTaskActive;
605 dbgs() <<
"Issuing speculative lookup for ( " << SpeculateJD->getName()
606 <<
", " << SpeculateFn <<
" )...\n";
611 {{std::move(SpeculateFn), SymbolLookupFlags::WeaklyReferencedSymbol}},
617 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 JITDylib * getJITDylibByName(StringRef Name)
Return a pointer to the "name" JITDylib.
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.
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.
A symbol name together with the naming level (SymbolNameKind) it is expressed in, so that a Mangler /...
static constexpr SymbolNameSpec c(StringRef Name)
Pointer to a pooled string representing a symbol name.
Base class for pools of compiler re-entry trampolines.
Base class for specs that bind handlers for calls with the SPS signature SPSSigT.
This class implements an extremely fast bulk output stream that can only output to a stream.
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
ExecutionSession::CallControllerHandlerBinding bindCallControllerHandler(HandlerT &&H, SymbolLookupFlags LF=SymbolLookupFlags::RequiredSymbol)
Bind H, using the given spec, to the tag with the spec's default name.
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...
static constexpr SymbolNameSpec Name