16#define DEBUG_TYPE "orc"
24 : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
29 assert(TP &&
"TrampolinePool not set");
31 std::lock_guard<std::mutex> Lock(LCTMMutex);
35 return Trampoline.takeError();
37 Reexports[*Trampoline] =
ReexportsEntry{&SourceJD, std::move(SymbolName)};
38 Notifiers[*Trampoline] = std::move(NotifyResolved);
44 return ErrorHandlerAddr;
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));
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);
70 return NotifyResolved ? NotifyResolved(ResolvedAddr) :
Error::success();
84 auto Callback = [
this, TrampolineAddr, SymbolName = Entry->SymbolName,
85 NotifyLandingResolved = std::move(NotifyLandingResolved)](
89 assert(
Result->count(SymbolName) &&
"Unexpected result value");
90 ExecutorAddr LandingAddr = (*Result)[SymbolName].getAddress();
95 NotifyLandingResolved(LandingAddr);
111 switch (
T.getArch()) {
113 return make_error<StringError>(
114 std::string(
"No callback manager available for ") +
T.str(),
119 return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
123 return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
126 return LocalLazyCallThroughManager::Create<OrcLoongArch64>(
127 ES, ErrorHandlerAddr);
130 return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
134 return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
139 return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
142 return LocalLazyCallThroughManager::Create<OrcRiscv64>(ES,
147 return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
148 ES, ErrorHandlerAddr);
150 return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
151 ES, ErrorHandlerAddr);
159 LCTManager(LCTManager), RSManager(RSManager), SourceJD(SourceJD),
160 CallableAliases(
std::
move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
163 return "<Lazy Reexports>";
166void LazyReexportsMaterializationUnit::materialize(
167 std::unique_ptr<MaterializationResponsibility> R) {
168 auto RequestedSymbols = R->getRequestedSymbols();
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);
178 if (!CallableAliases.
empty())
179 if (
auto Err = R->replace(
lazyReexports(LCTManager, RSManager, SourceJD,
180 std::move(CallableAliases),
182 R->getExecutionSession().reportError(std::move(Err));
183 R->failMaterialization();
188 for (
auto &Alias : RequestedAliases) {
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, {}));
197 if (!CallThroughTrampoline) {
198 R->getExecutionSession().reportError(CallThroughTrampoline.takeError());
199 R->failMaterialization();
203 Inits[Alias.first] = {*CallThroughTrampoline, Alias.second.AliasFlags};
206 if (AliaseeTable !=
nullptr && !RequestedAliases.empty())
207 AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
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();
216void LazyReexportsMaterializationUnit::discard(
const JITDylib &JD,
217 const SymbolStringPtr &
Name) {
219 "Symbol not covered by this MaterializationUnit");
220 CallableAliases.erase(
Name);
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");
231 return MaterializationUnit::Interface(std::move(SymbolFlags),
nullptr);
238 Reexports(
std::
move(Reexports)) {}
243 for (
auto &[Alias, AI] : Reexports)
244 SF[Alias] = AI.AliasFlags;
245 return {std::move(SF),
nullptr};
250 void materialize(std::unique_ptr<MaterializationResponsibility> R)
override {
251 LRMgr.emitReentryTrampolines(std::move(R), std::move(Reexports));
254 void discard(
const JITDylib &JD,
const SymbolStringPtr &
Name)
override {
258 LazyReexportsManager &LRMgr;
269 return Error::success();
273 return Error::success();
289 std::move(EmitTrampolines), RSMgr, PlatformJD, Err));
291 return std::move(Err);
292 return std::move(LRM);
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);
304 KeyToReentryAddr.erase(
I);
310void LazyReexportsManager::handleTransferResources(
JITDylib &JD,
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);
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);
330LazyReexportsManager::LazyReexportsManager(EmitTrampolinesFn EmitTrampolines,
333 : ES(PlatformJD.getExecutionSession()),
334 EmitTrampolines(
std::
move(EmitTrampolines)), RSMgr(RSMgr) {
336 using namespace shared;
342 WFs[ES.
intern(
"__orc_rt_resolve_tag")] =
344 this, &LazyReexportsManager::resolve);
349std::unique_ptr<MaterializationUnit>
350LazyReexportsManager::createLazyReexports(
SymbolAliasMap Reexports) {
351 return std::make_unique<MU>(*
this, std::move(Reexports));
354void LazyReexportsManager::emitReentryTrampolines(
355 std::unique_ptr<MaterializationResponsibility> MR,
357 size_t NumTrampolines = Reexports.size();
358 auto RT = MR->getResourceTracker();
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));
368void LazyReexportsManager::emitRedirectableSymbols(
369 std::unique_ptr<MaterializationResponsibility> MR,
SymbolAliasMap Reexports,
370 Expected<std::vector<ExecutorSymbolDef>> ReentryPoints) {
372 if (!ReentryPoints) {
373 MR->getExecutionSession().reportError(ReentryPoints.takeError());
374 MR->failMaterialization();
378 assert(Reexports.size() == ReentryPoints->size() &&
379 "Number of reentry points doesn't match number of reexports");
384 for (
auto &[
Name, AI] : Reexports)
385 Redirs[
Name] = (*ReentryPoints)[
I++];
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());
396 MR->getExecutionSession().reportError(std::move(Err));
397 MR->failMaterialization();
404void LazyReexportsManager::resolve(ResolveSendResultFn SendResult,
405 ExecutorAddr ReentryStubAddr) {
407 CallThroughInfo LandingInfo;
410 auto I = CallThroughs.find(ReentryStubAddr);
411 if (
I == CallThroughs.end())
412 return SendResult(make_error<StringError>(
413 "Reentry address " +
formatv(
"{0:x}", ReentryStubAddr) +
416 LandingInfo =
I->second;
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 {
427 if (auto Err = RSMgr.redirect(*JD, ReentryName, *Result))
428 SendResult(std::move(Err));
430 SendResult(std::move(Result));
432 SendResult(std::move(
Result));
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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.
StringRef - 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.
void reportError(Error Err)
Report a error for this execution session.
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H)
Wrap a handler that takes concrete argument types (and a sender for a concrete return type) to produc...
void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, SymbolLookupSet Symbols, SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete, RegisterDependenciesFunction RegisterDependencies)
Search the given JITDylibs for the given symbols.
Error registerJITDispatchHandlers(JITDylib &JD, JITDispatchHandlerAssociationMap WFs)
For each tag symbol name, associate the corresponding AsyncHandlerWrapperFunction with the address of...
decltype(auto) runSessionLocked(Func &&F)
Run the given lambda with the session mutex locked.
Represents an address in the executor process.
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.
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...
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.
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.
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...
DenseMap< SymbolStringPtr, SymbolAliasMapEntry > SymbolAliasMap
A map of Symbols to (Symbol, Flags) pairs.
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...
@ Ready
Emitted to memory, but waiting on transitive dependencies.
This is an optimization pass for GlobalISel generic memory operations.
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
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)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
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...