Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Interface devirt #10192

Merged
merged 3 commits into from
Mar 17, 2017
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
3 changes: 2 additions & 1 deletion src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@
// 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,
Expand Down
2 changes: 1 addition & 1 deletion src/ToolBox/superpmi/superpmi-shared/lwmlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ LWM(IsWriteBarrierHelperRequired, DWORDLONG, DWORD)
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)
Expand Down
33 changes: 20 additions & 13 deletions src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3296,33 +3296,40 @@ void MethodContext::repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, unsig
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));
Expand Down
15 changes: 12 additions & 3 deletions src/ToolBox/superpmi/superpmi-shared/methodcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,13 @@ class MethodContext
DWORD result;
};

struct Agnostic_ResolveVirtualMethod
{
DWORDLONG virtualMethod;
DWORDLONG implementingClass;
DWORDLONG ownerType;
};

#pragma pack(pop)

MethodContext();
Expand Down Expand Up @@ -698,9 +705,11 @@ class 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);
Expand Down
7 changes: 4 additions & 3 deletions src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,13 @@ void interceptor_ICJI::getMethodVTableOffset (
// 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;
}

Expand Down
5 changes: 3 additions & 2 deletions src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,12 @@ void interceptor_ICJI::getMethodVTableOffset (
// 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,
Expand Down
5 changes: 3 additions & 2 deletions src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,11 @@ void interceptor_ICJI::getMethodVTableOffset (
// 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,
Expand Down
5 changes: 3 additions & 2 deletions src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,12 @@ void MyICJI::getMethodVTableOffset (
// 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;
}

Expand Down
25 changes: 15 additions & 10 deletions src/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,11 @@ TODO: Talk about initializing strutures before use
#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
Expand Down Expand Up @@ -2117,12 +2117,17 @@ class ICorStaticInfo
) = 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,
Expand Down
7 changes: 3 additions & 4 deletions src/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18488,16 +18488,15 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
return;
}

// Bail (for now) if base class is an interface.
if (isInterface)
{
assert(call->IsVirtualStub());
JITDUMP("--- base class is interface, sorry\n");
return;
JITDUMP("--- base class is interface\n");
}

// Fetch the method that would be called based on the declared type of 'this'
CORINFO_METHOD_HANDLE derivedMethod = info.compCompHnd->resolveVirtualMethod(baseMethod, objClass);
CORINFO_CONTEXT_HANDLE ownerType = callInfo->contextHandle;
CORINFO_METHOD_HANDLE derivedMethod = info.compCompHnd->resolveVirtualMethod(baseMethod, objClass, ownerType);

// If we failed to get a handle, we can't devirtualize. This can
// happen when prejitting, if the devirtualization crosses
Expand Down
86 changes: 58 additions & 28 deletions src/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8716,7 +8716,8 @@ void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
/*********************************************************************/
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;

Expand All @@ -8729,15 +8730,11 @@ static CORINFO_METHOD_HANDLE resolveVirtualMethodHelper(MethodDesc* callerMethod
//@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());
Expand All @@ -8748,33 +8745,65 @@ static CORINFO_METHOD_HANDLE resolveVirtualMethodHelper(MethodDesc* callerMethod
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
Expand All @@ -8798,15 +8827,16 @@ static CORINFO_METHOD_HANDLE resolveVirtualMethodHelper(MethodDesc* callerMethod
}

CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
CORINFO_CLASS_HANDLE derivedClass)
CORINFO_CLASS_HANDLE derivedClass,
CORINFO_CONTEXT_HANDLE ownerType)
{
STANDARD_VM_CONTRACT;

CORINFO_METHOD_HANDLE result = nullptr;

JIT_TO_EE_TRANSITION();

result = resolveVirtualMethodHelper(m_pMethodBeingCompiled, methodHnd, derivedClass);
result = resolveVirtualMethodHelper(m_pMethodBeingCompiled, methodHnd, derivedClass, ownerType);

EE_TO_JIT_TRANSITION();

Expand Down
3 changes: 2 additions & 1 deletion src/vm/jitinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,8 @@ class CEEInfo : public ICorJitInfo

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,
Expand Down
5 changes: 3 additions & 2 deletions src/zap/zapinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3729,10 +3729,11 @@ void ZapInfo::getMethodVTableOffset(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,
Expand Down
3 changes: 2 additions & 1 deletion src/zap/zapinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,8 @@ class ZapInfo

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,
Expand Down
Loading