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

Commit 70cf442

Browse files
committed
Jit interface support for devirtualization
Add new method to jit interface so the jit can determine what derived method might be called for a given base method, derived class pair. Implement support in the VM and in other places (zap, spmi).
1 parent 8597adf commit 70cf442

File tree

13 files changed

+202
-8
lines changed

13 files changed

+202
-8
lines changed

src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@
125125
unsigned* offsetAfterIndirection /* OUT */
126126
);
127127

128+
// Find the virtual method in implementingClass that overrides virtualMethod.
129+
// Return null if devirtualization is not possible.
130+
CORINFO_METHOD_HANDLE resolveVirtualMethod(
131+
CORINFO_METHOD_HANDLE virtualMethod,
132+
CORINFO_CLASS_HANDLE implementingClass
133+
);
134+
128135
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
129136
// getIntrinsicID() returns the intrinsic ID.
130137
// *pMustExpand tells whether or not JIT must expand the intrinsic.

src/ToolBox/superpmi/superpmi-shared/lwmlist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ LWM(IsWriteBarrierHelperRequired, DWORDLONG, DWORD)
141141
LWM(MergeClasses, DLDL, DWORDLONG)
142142
LWM(PInvokeMarshalingRequired, Agnostic_PInvokeMarshalingRequired, DWORD)
143143
LWM(ResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, Agnostic_CORINFO_RESOLVED_TOKENout)
144+
LWM(ResolveVirtualMethod, DLDL, DWORDLONG)
144145
LWM(TryResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, Agnostic_CORINFO_RESOLVED_TOKENout)
145146
LWM(SatisfiesClassConstraints, DWORDLONG, DWORD)
146147
LWM(SatisfiesMethodConstraints, DLDL, DWORD)

src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3296,6 +3296,40 @@ void MethodContext::repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, unsig
32963296
DEBUG_REP(dmpGetMethodVTableOffset((DWORDLONG)method, value));
32973297
}
32983298

3299+
void MethodContext::recResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass, CORINFO_METHOD_HANDLE result)
3300+
{
3301+
if (ResolveVirtualMethod == nullptr)
3302+
{
3303+
ResolveVirtualMethod = new LightWeightMap<DLDL, DWORDLONG>();
3304+
}
3305+
3306+
DLDL key;
3307+
key.A = (DWORDLONG)virtMethod;
3308+
key.B = (DWORDLONG)implClass;
3309+
ResolveVirtualMethod->Add(key, (DWORDLONG) result);
3310+
DEBUG_REC(dmpResolveVirtualMethod(key, result));
3311+
}
3312+
3313+
void MethodContext::dmpResolveVirtualMethod(DLDL key, DWORDLONG value)
3314+
{
3315+
printf("ResolveVirtualMethod virtMethod-%016llX, implClass-%016llX, result-%016llX", key.A, key.B, value);
3316+
}
3317+
3318+
CORINFO_METHOD_HANDLE MethodContext::repResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass)
3319+
{
3320+
DLDL key;
3321+
key.A = (DWORDLONG)virtMethod;
3322+
key.B = (DWORDLONG)implClass;
3323+
3324+
AssertCodeMsg(ResolveVirtualMethod != nullptr, EXCEPTIONCODE_MC, "No ResolveVirtualMap map for %016llX-%016llX", key.A, key.B);
3325+
AssertCodeMsg(ResolveVirtualMethod->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX-%016llx", key.A, key.B);
3326+
DWORDLONG result = ResolveVirtualMethod->Get(key);
3327+
3328+
DEBUG_REP(dmpResolveVirtualMethod(key, result));
3329+
3330+
return (CORINFO_METHOD_HANDLE)result;
3331+
}
3332+
32993333
void MethodContext::recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_CLASS_HANDLE result)
33003334
{
33013335
if (GetTokenTypeAsHandle == nullptr)
@@ -6165,7 +6199,7 @@ mdMethodDef MethodContext::repGetMethodDefFromMethod(CORINFO_METHOD_HANDLE hMeth
61656199

61666200
int index = GetMethodDefFromMethod->GetIndex((DWORDLONG)hMethod);
61676201
if (index < 0)
6168-
return (mdMethodDef)0x06000001;
6202+
return (mdMethodDef)0x06000001;
61696203

61706204
return (mdMethodDef)GetMethodDefFromMethod->Get((DWORDLONG)hMethod);
61716205
}

src/ToolBox/superpmi/superpmi-shared/methodcontext.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,10 @@ class MethodContext
698698
void dmpGetMethodVTableOffset(DWORDLONG key, DD value);
699699
void repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, unsigned *offsetOfIndirection, unsigned* offsetAfterIndirection);
700700

701+
void recResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass, CORINFO_METHOD_HANDLE result);
702+
void dmpResolveVirtualMethod(DLDL key, DWORDLONG value);
703+
CORINFO_METHOD_HANDLE repResolveVirtualMethod(CORINFO_METHOD_HANDLE virtMethod, CORINFO_CLASS_HANDLE implClass);
704+
701705
void recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_CLASS_HANDLE result);
702706
void dmpGetTokenTypeAsHandle(const Agnostic_CORINFO_RESOLVED_TOKEN& key, DWORDLONG value);
703707
CORINFO_CLASS_HANDLE repGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken);
@@ -1016,7 +1020,7 @@ class MethodContext
10161020

10171021

10181022
// ********************* Please keep this up-to-date to ease adding more ***************
1019-
// Highest packet number: 159
1023+
// Highest packet number: 160
10201024
// *************************************************************************************
10211025
enum mcPackets
10221026
{
@@ -1151,6 +1155,7 @@ enum mcPackets
11511155
Packet_MergeClasses = 107,
11521156
Packet_PInvokeMarshalingRequired = 108,
11531157
Packet_ResolveToken = 109,
1158+
Packet_ResolveVirtualMethod = 160, // Added 2/13/17
11541159
Packet_TryResolveToken = 158, //Added 4/26/2016
11551160
Packet_SatisfiesClassConstraints = 110,
11561161
Packet_SatisfiesMethodConstraints = 111,

src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,19 @@ void interceptor_ICJI::getMethodVTableOffset (
236236
mc->recGetMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection);
237237
}
238238

239+
// Find the virtual method in implementingClass that overrides virtualMethod.
240+
// Return null if devirtualization is not possible.
241+
CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(
242+
CORINFO_METHOD_HANDLE virtualMethod,
243+
CORINFO_CLASS_HANDLE implementingClass
244+
)
245+
{
246+
mc->cr->AddCall("resolveVirtualMethod");
247+
CORINFO_METHOD_HANDLE result = original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass);
248+
mc->recResolveVirtualMethod(virtualMethod, implementingClass, result);
249+
return result;
250+
}
251+
239252
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
240253
// getIntrinsicID() returns the intrinsic ID.
241254
CorInfoIntrinsics interceptor_ICJI::getIntrinsicID(

src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,17 @@ void interceptor_ICJI::getMethodVTableOffset (
165165
original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection);
166166
}
167167

168+
// Find the virtual method in implementingClass that overrides virtualMethod.
169+
// Return null if devirtualization is not possible.
170+
CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(
171+
CORINFO_METHOD_HANDLE virtualMethod,
172+
CORINFO_CLASS_HANDLE implementingClass
173+
)
174+
{
175+
mcs->AddCall("resolveVirtualMethod");
176+
return original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass);
177+
}
178+
168179
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
169180
// getIntrinsicID() returns the intrinsic ID.
170181
CorInfoIntrinsics interceptor_ICJI::getIntrinsicID(

src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,16 @@ void interceptor_ICJI::getMethodVTableOffset (
153153
original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection);
154154
}
155155

156+
// Find the virtual method in implementingClass that overrides virtualMethod.
157+
// Return null if devirtualization is not possible.
158+
CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(
159+
CORINFO_METHOD_HANDLE virtualMethod,
160+
CORINFO_CLASS_HANDLE implementingClass
161+
)
162+
{
163+
return original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass);
164+
}
165+
156166
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
157167
// getIntrinsicID() returns the intrinsic ID.
158168
CorInfoIntrinsics interceptor_ICJI::getIntrinsicID(

src/ToolBox/superpmi/superpmi/icorjitinfo.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,18 @@ void MyICJI::getMethodVTableOffset (
185185
jitInstance->mc->repGetMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection);
186186
}
187187

188+
// Find the virtual method in implementingClass that overrides virtualMethod.
189+
// Return null if devirtualization is not possible.
190+
CORINFO_METHOD_HANDLE MyICJI::resolveVirtualMethod(
191+
CORINFO_METHOD_HANDLE virtualMethod,
192+
CORINFO_CLASS_HANDLE implementingClass
193+
)
194+
{
195+
jitInstance->mc->cr->AddCall("resolveVirtualMethod");
196+
CORINFO_METHOD_HANDLE result = jitInstance->mc->repResolveVirtualMethod(virtualMethod, implementingClass);
197+
return result;
198+
}
199+
188200
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
189201
// getIntrinsicID() returns the intrinsic ID.
190202
CorInfoIntrinsics MyICJI::getIntrinsicID(

src/inc/corinfo.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,12 @@ TODO: Talk about initializing strutures before use
231231
#if COR_JIT_EE_VERSION > 460
232232

233233
// Update this one
234-
SELECTANY const GUID JITEEVersionIdentifier = { /* 4bd06266-8ef7-4172-bec6-d3149fde7859 */
235-
0x4bd06266,
236-
0x8ef7,
237-
0x4172,
238-
{0xbe, 0xc6, 0xd3, 0x14, 0x9f, 0xde, 0x78, 0x59}
239-
};
234+
SELECTANY const GUID JITEEVersionIdentifier = { /* cda334f7-0020-4622-a4a5-8b8ac71ee5cf */
235+
0xcda334f7,
236+
0x0020,
237+
0x4622,
238+
{0xa4, 0xa5, 0x8b, 0x8a, 0xc7, 0x1e, 0xe5, 0xcf}
239+
};
240240

241241
#else
242242

@@ -2116,6 +2116,15 @@ class ICorStaticInfo
21162116
unsigned* offsetAfterIndirection /* OUT */
21172117
) = 0;
21182118

2119+
#if COR_JIT_EE_VERSION > 460
2120+
// Find the virtual method in implementingClass that overrides virtualMethod.
2121+
// Return null if devirtualization is not possible.
2122+
virtual CORINFO_METHOD_HANDLE resolveVirtualMethod(
2123+
CORINFO_METHOD_HANDLE virtualMethod, /* IN */
2124+
CORINFO_CLASS_HANDLE implementingClass /* IN */
2125+
) = 0;
2126+
#endif
2127+
21192128
// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set,
21202129
// getIntrinsicID() returns the intrinsic ID.
21212130
// *pMustExpand tells whether or not JIT must expand the intrinsic.

src/vm/jitinterface.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8700,6 +8700,80 @@ void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
87008700
EE_TO_JIT_TRANSITION_LEAF();
87018701
}
87028702

8703+
/*********************************************************************/
8704+
CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
8705+
CORINFO_CLASS_HANDLE derivedClass)
8706+
{
8707+
CONTRACTL {
8708+
SO_TOLERANT;
8709+
NOTHROW;
8710+
GC_NOTRIGGER;
8711+
MODE_PREEMPTIVE;
8712+
} CONTRACTL_END;
8713+
8714+
CORINFO_METHOD_HANDLE result = nullptr;
8715+
8716+
JIT_TO_EE_TRANSITION();
8717+
8718+
MethodDesc* method = GetMethod(methodHnd);
8719+
8720+
// Method better be from a fully loaded class
8721+
_ASSERTE(method->IsRestored() && method->GetMethodTable()->IsFullyLoaded());
8722+
8723+
// Method better be virtual
8724+
_ASSERTE(method->IsVirtual());
8725+
8726+
//@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8727+
_ASSERTE(!method->HasMethodInstantiation());
8728+
8729+
// Method's class better not be an interface
8730+
_ASSERTE(!method->GetMethodTable()->IsInterface());
8731+
8732+
// Method better be in the vtable
8733+
WORD slot = method->GetSlot();
8734+
_ASSERTE(slot < method->GetMethodTable()->GetNumVirtuals());
8735+
8736+
// TODO: Derived class should have base class as parent...
8737+
TypeHandle DerivedClsHnd(derivedClass);
8738+
8739+
// If derived class is _Canon, we can't devirtualize.
8740+
if (DerivedClsHnd != TypeHandle(g_pCanonMethodTableClass))
8741+
{
8742+
MethodTable* pMT = DerivedClsHnd.GetMethodTable();
8743+
8744+
// MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
8745+
_ASSERTE(pMT->IsRestored() && pMT->IsFullyLoaded());
8746+
8747+
MethodDesc* pDevirtMD = pMT->GetMethodDescForSlot(slot);
8748+
8749+
_ASSERTE(pDevirtMD->IsRestored());
8750+
8751+
// Allow devirtialization if jitting, or if prejitting and the
8752+
// method being jitted, the devirtualized class, and the
8753+
// devirtualized method are all in the same versioning bubble.
8754+
bool allowDevirt = true;
8755+
8756+
#ifdef FEATURE_READYTORUN_COMPILER
8757+
if (IsReadyToRunCompilation())
8758+
{
8759+
Assembly * pCallerAssembly = m_pMethodBeingCompiled->GetModule()->GetAssembly();
8760+
allowDevirt =
8761+
IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
8762+
&& IsInSameVersionBubble(pCallerAssembly , pMT->GetAssembly());
8763+
}
8764+
#endif
8765+
8766+
if (allowDevirt)
8767+
{
8768+
result = (CORINFO_METHOD_HANDLE) pDevirtMD;
8769+
}
8770+
}
8771+
8772+
EE_TO_JIT_TRANSITION();
8773+
8774+
return result;
8775+
}
8776+
87038777
/*********************************************************************/
87048778
void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
87058779
CORINFO_CONST_LOOKUP * pResult,

0 commit comments

Comments
 (0)