diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 70a5cf39b544a..897a3dcdf6eb9 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -21696,8 +21696,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; @@ -22164,7 +22174,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // if (pExactContextHandle != nullptr) { - *pExactContextHandle = MAKE_CLASSCONTEXT(derivedClass); + *pExactContextHandle = exactContext; } #ifdef FEATURE_READYTORUN @@ -22497,7 +22507,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; } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 94d7101094891..acc9f21bf6f41 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8517,7 +8517,19 @@ 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()) + { + // Could avoid this mode switch by using type handle's CanCastTo... + // + GCX_COOP(); + if (!pObjMT->CanCastTo(pBaseMT, nullptr)) + { + info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST; + return false; + } + } + else if (!pObjMT->CanCastToInterface(pBaseMT)) { info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST; return false; @@ -8627,8 +8639,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()) { @@ -8637,6 +8653,10 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) _ASSERTE(!pDevirtMD->HasClassInstantiation()); } + else if (pBaseMT->IsInterface() && pObjMT->IsArray()) + { + isArray = true; + } else { pExactMT = pDevirtMD->GetExactDeclaringType(pObjMT); @@ -8645,8 +8665,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;