// Return null if devirtualization is not possible.
CORINFO_METHOD_HANDLE resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
- CORINFO_CLASS_HANDLE implementingClass
+ CORINFO_CLASS_HANDLE implementingClass,
+ CORINFO_CONTEXT_HANDLE ownerType
);
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
LWM(MergeClasses, DLDL, DWORDLONG)
LWM(PInvokeMarshalingRequired, Agnostic_PInvokeMarshalingRequired, DWORD)
LWM(ResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, Agnostic_CORINFO_RESOLVED_TOKENout)
-LWM(ResolveVirtualMethod, DLDL, DWORDLONG)
+LWM(ResolveVirtualMethod, Agnostic_ResolveVirtualMethod, DWORDLONG)
LWM(TryResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, Agnostic_CORINFO_RESOLVED_TOKENout)
LWM(SatisfiesClassConstraints, DWORDLONG, DWORD)
LWM(SatisfiesMethodConstraints, DLDL, DWORD)
DEBUG_REP(dmpGetMethodVTableOffset((DWORDLONG)method, value));
}
-void MethodContext::recResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass, CORINFO_METHOD_HANDLE result)
+void MethodContext::recResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass,
+ CORINFO_CONTEXT_HANDLE ownerType, CORINFO_METHOD_HANDLE result)
{
if (ResolveVirtualMethod == nullptr)
{
- ResolveVirtualMethod = new LightWeightMap<DLDL, DWORDLONG>();
+ ResolveVirtualMethod = new LightWeightMap<Agnostic_ResolveVirtualMethod, DWORDLONG>();
}
- DLDL key;
- key.A = (DWORDLONG)virtMethod;
- key.B = (DWORDLONG)implClass;
+ Agnostic_ResolveVirtualMethod key;
+ key.virtualMethod = (DWORDLONG)virtMethod;
+ key.implementingClass = (DWORDLONG)implClass;
+ key.ownerType = (DWORDLONG)ownerType;
ResolveVirtualMethod->Add(key, (DWORDLONG) result);
DEBUG_REC(dmpResolveVirtualMethod(key, result));
}
-void MethodContext::dmpResolveVirtualMethod(DLDL key, DWORDLONG value)
+void MethodContext::dmpResolveVirtualMethod(const Agnostic_ResolveVirtualMethod& key, DWORDLONG value)
{
- printf("ResolveVirtualMethod virtMethod-%016llX, implClass-%016llX, result-%016llX", key.A, key.B, value);
+ printf("ResolveVirtualMethod virtMethod-%016llX, implClass-%016llX, ownerType--%01611X, result-%016llX",
+ key.virtualMethod, key.implementingClass, key.ownerType, value);
}
-CORINFO_METHOD_HANDLE MethodContext::repResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass)
+CORINFO_METHOD_HANDLE MethodContext::repResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass,
+ CORINFO_CONTEXT_HANDLE ownerType)
{
- DLDL key;
- key.A = (DWORDLONG)virtMethod;
- key.B = (DWORDLONG)implClass;
+ Agnostic_ResolveVirtualMethod key;
+ key.virtualMethod = (DWORDLONG)virtMethod;
+ key.implementingClass = (DWORDLONG)implClass;
+ key.ownerType = (DWORDLONG)ownerType;
- AssertCodeMsg(ResolveVirtualMethod != nullptr, EXCEPTIONCODE_MC, "No ResolveVirtualMap map for %016llX-%016llX", key.A, key.B);
- AssertCodeMsg(ResolveVirtualMethod->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX-%016llx", key.A, key.B);
+ AssertCodeMsg(ResolveVirtualMethod != nullptr, EXCEPTIONCODE_MC, "No ResolveVirtualMap map for %016llX-%016llX-%016llX",
+ key.virtualMethod, key.implementingClass, key.ownerType);
+ AssertCodeMsg(ResolveVirtualMethod->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX-%016llx-%016llX",
+ key.virtualMethod, key.implementingClass, key.ownerType);
DWORDLONG result = ResolveVirtualMethod->Get(key);
DEBUG_REP(dmpResolveVirtualMethod(key, result));
DWORD result;
};
+ struct Agnostic_ResolveVirtualMethod
+ {
+ DWORDLONG virtualMethod;
+ DWORDLONG implementingClass;
+ DWORDLONG ownerType;
+ };
+
#pragma pack(pop)
MethodContext();
void dmpGetMethodVTableOffset(DWORDLONG key, DD value);
void repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, unsigned *offsetOfIndirection, unsigned* offsetAfterIndirection);
- void recResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass, CORINFO_METHOD_HANDLE result);
- void dmpResolveVirtualMethod(DLDL key, DWORDLONG value);
- CORINFO_METHOD_HANDLE repResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass);
+ void recResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass,
+ CORINFO_CONTEXT_HANDLE ownerType, CORINFO_METHOD_HANDLE result);
+ void dmpResolveVirtualMethod(const Agnostic_ResolveVirtualMethod& key, DWORDLONG value);
+ CORINFO_METHOD_HANDLE repResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass,
+ CORINFO_CONTEXT_HANDLE ownerType);
void recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_CLASS_HANDLE result);
void dmpGetTokenTypeAsHandle(const Agnostic_CORINFO_RESOLVED_TOKEN& key, DWORDLONG value);
// Return null if devirtualization is not possible.
CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
- CORINFO_CLASS_HANDLE implementingClass
+ CORINFO_CLASS_HANDLE implementingClass,
+ CORINFO_CONTEXT_HANDLE ownerType
)
{
mc->cr->AddCall("resolveVirtualMethod");
- CORINFO_METHOD_HANDLE result = original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass);
- mc->recResolveVirtualMethod(virtualMethod, implementingClass, result);
+ CORINFO_METHOD_HANDLE result = original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass, ownerType);
+ mc->recResolveVirtualMethod(virtualMethod, implementingClass, ownerType, result);
return result;
}
// Return null if devirtualization is not possible.
CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
- CORINFO_CLASS_HANDLE implementingClass
+ CORINFO_CLASS_HANDLE implementingClass,
+ CORINFO_CONTEXT_HANDLE ownerType
)
{
mcs->AddCall("resolveVirtualMethod");
- return original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass);
+ return original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass, ownerType);
}
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
// Return null if devirtualization is not possible.
CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
- CORINFO_CLASS_HANDLE implementingClass
+ CORINFO_CLASS_HANDLE implementingClass,
+ CORINFO_CONTEXT_HANDLE ownerType
)
{
- return original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass);
+ return original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass, ownerType);
}
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
// Return null if devirtualization is not possible.
CORINFO_METHOD_HANDLE MyICJI::resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
- CORINFO_CLASS_HANDLE implementingClass
+ CORINFO_CLASS_HANDLE implementingClass,
+ CORINFO_CONTEXT_HANDLE ownerType
)
{
jitInstance->mc->cr->AddCall("resolveVirtualMethod");
- CORINFO_METHOD_HANDLE result = jitInstance->mc->repResolveVirtualMethod(virtualMethod, implementingClass);
+ CORINFO_METHOD_HANDLE result = jitInstance->mc->repResolveVirtualMethod(virtualMethod, implementingClass, ownerType);
return result;
}
#if COR_JIT_EE_VERSION > 460
// Update this one
-SELECTANY const GUID JITEEVersionIdentifier = { /* cda334f7-0020-4622-a4a5-8b8ac71ee5cf */
- 0xcda334f7,
- 0x0020,
- 0x4622,
- {0xa4, 0xa5, 0x8b, 0x8a, 0xc7, 0x1e, 0xe5, 0xcf}
+SELECTANY const GUID JITEEVersionIdentifier = { /* 3d43decb-a611-4413-a0af-a24278a00e2d */
+ 0x3d43decb,
+ 0xa611,
+ 0x4413,
+ {0xa0, 0xaf, 0xa2, 0x42, 0x78, 0xa0, 0x0e, 0x2d}
};
#else
) = 0;
#if COR_JIT_EE_VERSION > 460
- // Find the virtual method in implementingClass that overrides virtualMethod.
- // Return null if devirtualization is not possible.
+ // Find the virtual method in implementingClass that overrides virtualMethod,
+ // or the method in implementingClass that implements the interface method
+ // represented by virtualMethod.
+ //
+ // Return null if devirtualization is not possible. Owner type is optional
+ // and provides additional context for shared interface devirtualization.
virtual CORINFO_METHOD_HANDLE resolveVirtualMethod(
- CORINFO_METHOD_HANDLE virtualMethod, /* IN */
- CORINFO_CLASS_HANDLE implementingClass /* IN */
- ) = 0;
+ CORINFO_METHOD_HANDLE virtualMethod, /* IN */
+ CORINFO_CLASS_HANDLE implementingClass, /* IN */
+ CORINFO_CONTEXT_HANDLE ownerType = NULL /* IN */
+ ) = 0;
#endif
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
/*********************************************************************/
static CORINFO_METHOD_HANDLE resolveVirtualMethodHelper(MethodDesc* callerMethod,
CORINFO_METHOD_HANDLE baseMethod,
- CORINFO_CLASS_HANDLE derivedClass)
+ CORINFO_CLASS_HANDLE derivedClass,
+ CORINFO_CONTEXT_HANDLE ownerType)
{
STANDARD_VM_CONTRACT;
//@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
_ASSERTE(!pBaseMD->HasMethodInstantiation());
- // Interface call devirtualization is not yet supported.
- if (pBaseMT->IsInterface())
- {
- return nullptr;
- }
-
// Method better be virtual
_ASSERTE(pBaseMD->IsVirtual());
+ MethodDesc* pDevirtMD = nullptr;
+
TypeHandle DerivedClsHnd(derivedClass);
MethodTable* pDerivedMT = DerivedClsHnd.GetMethodTable();
_ASSERTE(pDerivedMT->IsRestored() && pDerivedMT->IsFullyLoaded());
return nullptr;
}
- // The derived class should be a subclass of the the base class.
- MethodTable* pCheckMT = pDerivedMT;
-
- while (pCheckMT != nullptr)
+ if (pBaseMT->IsInterface())
{
- if (pCheckMT->HasSameTypeDefAs(pBaseMT))
+ // Interface call devirtualization.
+ //
+ // We must ensure that pDerivedMT actually implements the
+ // interface corresponding to pBaseMD.
+ if (!pDerivedMT->CanCastToInterface(pBaseMT))
{
- break;
+ return nullptr;
}
- pCheckMT = pCheckMT->GetParentMethodTable();
+ // For generic interface methods we must have an ownerType to
+ // safely devirtualize.
+ if (ownerType != nullptr)
+ {
+ pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(GetTypeFromContext(ownerType), pBaseMD);
+ }
+ else if (!pBaseMD->HasClassOrMethodInstantiation())
+ {
+ pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(pBaseMD);
+ }
+ else
+ {
+ return nullptr;
+ }
}
-
- if (pCheckMT == nullptr)
+ else
{
- return nullptr;
+ // Virtual call devirtualization.
+ //
+ // The derived class should be a subclass of the the base class.
+ MethodTable* pCheckMT = pDerivedMT;
+
+ while (pCheckMT != nullptr)
+ {
+ if (pCheckMT->HasSameTypeDefAs(pBaseMT))
+ {
+ break;
+ }
+
+ pCheckMT = pCheckMT->GetParentMethodTable();
+ }
+
+ if (pCheckMT == nullptr)
+ {
+ return nullptr;
+ }
+
+ // The base method should be in the base vtable
+ WORD slot = pBaseMD->GetSlot();
+ _ASSERTE(slot < pBaseMT->GetNumVirtuals());
+ _ASSERTE(pBaseMD == pBaseMT->GetMethodDescForSlot(slot));
+
+ // Fetch the method that would be invoked if the class were
+ // exactly derived class. It is up to the jit to determine whether
+ // directly calling this method is correct.
+ pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
}
- // The base method should be in the base vtable
- WORD slot = pBaseMD->GetSlot();
- _ASSERTE(slot < pBaseMT->GetNumVirtuals());
- _ASSERTE(pBaseMD == pBaseMT->GetMethodDescForSlot(slot));
-
- // Fetch the method that would be invoked if the class were
- // exactly derived class. It is up to the jit to determine whether
- // directly calling this method is correct.
- MethodDesc* pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
_ASSERTE(pDevirtMD->IsRestored());
#ifdef FEATURE_READYTORUN_COMPILER
}
CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
- CORINFO_CLASS_HANDLE derivedClass)
+ CORINFO_CLASS_HANDLE derivedClass,
+ CORINFO_CONTEXT_HANDLE ownerType)
{
STANDARD_VM_CONTRACT;
JIT_TO_EE_TRANSITION();
- result = resolveVirtualMethodHelper(m_pMethodBeingCompiled, methodHnd, derivedClass);
+ result = resolveVirtualMethodHelper(m_pMethodBeingCompiled, methodHnd, derivedClass, ownerType);
EE_TO_JIT_TRANSITION();
CORINFO_METHOD_HANDLE resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
- CORINFO_CLASS_HANDLE implementingClass
+ CORINFO_CLASS_HANDLE implementingClass,
+ CORINFO_CONTEXT_HANDLE ownerType
);
CorInfoIntrinsics getIntrinsicID(CORINFO_METHOD_HANDLE method,
CORINFO_METHOD_HANDLE ZapInfo::resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
- CORINFO_CLASS_HANDLE implementingClass
+ CORINFO_CLASS_HANDLE implementingClass,
+ CORINFO_CONTEXT_HANDLE ownerType
)
{
- return m_pEEJitInfo->resolveVirtualMethod(virtualMethod, implementingClass);
+ return m_pEEJitInfo->resolveVirtualMethod(virtualMethod, implementingClass, ownerType);
}
CorInfoIntrinsics ZapInfo::getIntrinsicID(CORINFO_METHOD_HANDLE method,
CORINFO_METHOD_HANDLE resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
- CORINFO_CLASS_HANDLE implementingClass
+ CORINFO_CLASS_HANDLE implementingClass,
+ CORINFO_CONTEXT_HANDLE ownerType
);
CorInfoIntrinsics getIntrinsicID(CORINFO_METHOD_HANDLE method,