Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: don't optimize calls to CORINFO_HELP_VIRTUAL_FUNC_PTR for interface class lookups #82209

Merged
merged 5 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -4185,6 +4185,7 @@ enum GenTreeCallFlags : unsigned int
GTF_CALL_M_STRESS_TAILCALL = 0x04000000, // the call is NOT "tail" prefixed but GTF_CALL_M_EXPLICIT_TAILCALL was added because of tail call stress mode
GTF_CALL_M_EXPANDED_EARLY = 0x08000000, // the Virtual Call target address is expanded and placed in gtControlExpr in Morph rather than in Lower
GTF_CALL_M_HAS_LATE_DEVIRT_INFO = 0x10000000, // this call has late devirtualzation info
GTF_CALL_M_LDVIRTFTN_INTERFACE = 0x20000000, // ldvirtftn on an interface type
};

inline constexpr GenTreeCallFlags operator ~(GenTreeCallFlags a)
Expand Down
61 changes: 39 additions & 22 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3116,58 +3116,75 @@ GenTree* Compiler::impImportLdvirtftn(GenTree* thisPtr,
CORINFO_RESOLVED_TOKEN* pResolvedToken,
CORINFO_CALL_INFO* pCallInfo)
{
if ((pCallInfo->methodFlags & CORINFO_FLG_EnC) && !(pCallInfo->classFlags & CORINFO_FLG_INTERFACE))
const bool isInterface = (pCallInfo->classFlags & CORINFO_FLG_INTERFACE) == CORINFO_FLG_INTERFACE;

if ((pCallInfo->methodFlags & CORINFO_FLG_EnC) && !isInterface)
{
NO_WAY("Virtual call to a function added via EnC is not supported");
}

GenTreeCall* call = nullptr;

// NativeAOT generic virtual method
if ((pCallInfo->sig.sigInst.methInstCount != 0) && IsTargetAbi(CORINFO_NATIVEAOT_ABI))
{
GenTree* runtimeMethodHandle =
impLookupToTree(pResolvedToken, &pCallInfo->codePointerLookup, GTF_ICON_METHOD_HDL, pCallInfo->hMethod);
return gtNewHelperCallNode(CORINFO_HELP_GVMLOOKUP_FOR_SLOT, TYP_I_IMPL, thisPtr, runtimeMethodHandle);
call = gtNewHelperCallNode(CORINFO_HELP_GVMLOOKUP_FOR_SLOT, TYP_I_IMPL, thisPtr, runtimeMethodHandle);
}

#ifdef FEATURE_READYTORUN
if (opts.IsReadyToRun())
else if (opts.IsReadyToRun())
{
if (!pCallInfo->exactContextNeedsRuntimeLookup)
{
GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, TYP_I_IMPL, thisPtr);

call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, TYP_I_IMPL, thisPtr);
call->setEntryPoint(pCallInfo->codePointerLookup.constLookup);

return call;
}

// We need a runtime lookup. NativeAOT has a ReadyToRun helper for that too.
if (IsTargetAbi(CORINFO_NATIVEAOT_ABI))
else if (IsTargetAbi(CORINFO_NATIVEAOT_ABI))
{
GenTree* ctxTree = getRuntimeContextTree(pCallInfo->codePointerLookup.lookupKind.runtimeLookupKind);

return impReadyToRunHelperToTree(pResolvedToken, CORINFO_HELP_READYTORUN_GENERIC_HANDLE, TYP_I_IMPL,
call = impReadyToRunHelperToTree(pResolvedToken, CORINFO_HELP_READYTORUN_GENERIC_HANDLE, TYP_I_IMPL,
&pCallInfo->codePointerLookup.lookupKind, ctxTree);
}
}
#endif

// Get the exact descriptor for the static callsite
GenTree* exactTypeDesc = impParentClassTokenToHandle(pResolvedToken);
if (exactTypeDesc == nullptr)
{ // compDonotInline()
return nullptr;
}
if (call == nullptr)
{
// Get the exact descriptor for the static callsite
GenTree* exactTypeDesc = impParentClassTokenToHandle(pResolvedToken);
if (exactTypeDesc == nullptr)
{
assert(compIsForInlining());
return nullptr;
}

GenTree* exactMethodDesc = impTokenToHandle(pResolvedToken);
if (exactMethodDesc == nullptr)
{ // compDonotInline()
return nullptr;
GenTree* exactMethodDesc = impTokenToHandle(pResolvedToken);
if (exactMethodDesc == nullptr)
{
assert(compIsForInlining());
return nullptr;
}

// Call helper function. This gets the target address of the final destination callsite.
//
call = gtNewHelperCallNode(CORINFO_HELP_VIRTUAL_FUNC_PTR, TYP_I_IMPL, thisPtr, exactTypeDesc, exactMethodDesc);
}

// Call helper function. This gets the target address of the final destination callsite.
assert(call != nullptr);

if (isInterface)
{
// Annotate helper so later on if helper result is unconsumed we know it is not sound
// to optimize the call into a null check.
//
call->gtCallMoreFlags |= GTF_CALL_M_LDVIRTFTN_INTERFACE;
}

return gtNewHelperCallNode(CORINFO_HELP_VIRTUAL_FUNC_PTR, TYP_I_IMPL, thisPtr, exactTypeDesc, exactMethodDesc);
return call;
}

//------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7802,7 +7802,7 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call)
#endif
}

if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) == 0 &&
if (((call->gtCallMoreFlags & (GTF_CALL_M_SPECIAL_INTRINSIC | GTF_CALL_M_LDVIRTFTN_INTERFACE)) == 0) &&
(call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR)
#ifdef FEATURE_READYTORUN
|| call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR)
Expand Down