Skip to content

Commit

Permalink
Support for devirtualizing array interface methods
Browse files Browse the repository at this point in the history
Update jit and runtime to devirtualize interface calls on arrays
over non-shared element types.

Shared types are not handled. The resulting enumerator calls
would not inline as they are on a different class.

This addresses the first two issues noted in dotnet#62457.
  • Loading branch information
AndyAyersMS committed May 10, 2022
1 parent 8b8229b commit f90bd19
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 7 deletions.
18 changes: 14 additions & 4 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21181,8 +21181,18 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
if (derivedMethod != nullptr)
{
assert(exactContext != nullptr);
assert(((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS);
derivedClass = (CORINFO_CLASS_HANDLE)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK);

if (((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
{
derivedClass = (CORINFO_CLASS_HANDLE)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK);
}
else
{
// Array interface devirt can return a generic method of the non-generic SZArrayHelper class.
//
assert(((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD);
derivedClass = info.compCompHnd->getMethodClass(derivedMethod);
}
}

DWORD derivedMethodAttribs = 0;
Expand Down Expand Up @@ -21603,7 +21613,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
//
if (pExactContextHandle != nullptr)
{
*pExactContextHandle = MAKE_CLASSCONTEXT(derivedClass);
*pExactContextHandle = exactContext;
}

#ifdef FEATURE_READYTORUN
Expand Down Expand Up @@ -21933,7 +21943,7 @@ void Compiler::considerGuardedDevirtualization(

if (!canResolve)
{
JITDUMP("Can't figure out which method would be invoked, sorry\n");
JITDUMP("Can't figure out which method would be invoked, sorry (reason %d)\n", dvInfo.detail);
return;
}

Expand Down
44 changes: 41 additions & 3 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8587,7 +8587,27 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
//
// We must ensure that pObjMT actually implements the
// interface corresponding to pBaseMD.
if (!pObjMT->CanCastToInterface(pBaseMT))
//
if (pObjMT->IsArray())
{
// If we're in a shared context we'll devirt to a shared
// generic method and won't be able to inline, so just bail.
//
if (pBaseMT->IsSharedByGenericInstantiations())
{
info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
return false;
}

// Ensure we can cast the array to the interface type
//
if (!TypeHandle(pObjMT).CanCastTo(TypeHandle(pBaseMT)))
{
info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST;
return false;
}
}
else if (!pObjMT->CanCastToInterface(pBaseMT))
{
info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST;
return false;
Expand Down Expand Up @@ -8697,8 +8717,12 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
// We may fail to get an exact context if the method is a default
// interface method. If so, we'll use the method's class.
//
// For array -> interface devirt, the devirtualized methods
// will be defined by SZArrayHelper.
//
MethodTable* pApproxMT = pDevirtMD->GetMethodTable();
MethodTable* pExactMT = pApproxMT;
bool isArray = false;

if (pApproxMT->IsInterface())
{
Expand All @@ -8707,6 +8731,10 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
_ASSERTE(!pDevirtMD->HasClassInstantiation());

}
else if (pBaseMT->IsInterface() && pObjMT->IsArray())
{
isArray = true;
}
else
{
pExactMT = pDevirtMD->GetExactDeclaringType(pObjMT);
Expand All @@ -8715,8 +8743,18 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
// Success! Pass back the results.
//
info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) pDevirtMD;
info->exactContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT);
info->requiresInstMethodTableArg = false;

if (isArray)
{
info->exactContext = MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pDevirtMD);
info->requiresInstMethodTableArg = pDevirtMD->RequiresInstMethodTableArg();
}
else
{
info->exactContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT);
info->requiresInstMethodTableArg = false;
}

info->detail = CORINFO_DEVIRTUALIZATION_SUCCESS;

return true;
Expand Down

0 comments on commit f90bd19

Please sign in to comment.