Skip to content

Commit bb62718

Browse files
authored
JIT: modify how jit determines when to update a type (dotnet#22618)
For single-def locals, the type of a reference seen at the assignment to the local may be a more specific type than the local's declared type. If so the jit would prefer to use the assignment type to describe the local's value, as this will lead to better optimization. For instance in ``` object x = "a string"; // only assignment to x ``` the jit can optimize better if it models the type of `x` as `string`. Instead of relying on `mergeClasses` plus some jit-side screening to decide if the assignment type is a more specific type, implement a new jit interface method `isMoreSpecificType` that tries to answer this question more directly. Added a test case with type equivalence that hit asserts. Closes #22583.
1 parent 6f1bdff commit bb62718

File tree

20 files changed

+339
-34
lines changed

20 files changed

+339
-34
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,9 +461,12 @@ TypeCompareState compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLA
461461
// equal, or the comparison needs to be resolved at runtime.
462462
TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
463463

464-
// returns is the intersection of cls1 and cls2.
464+
// returns the intersection of cls1 and cls2.
465465
CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
466466

467+
// Returns true if cls2 is known to be a more specific type than cls1.
468+
BOOL isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
469+
467470
// Given a class handle, returns the Parent type.
468471
// For COMObjectType, it returns Class Handle of System.Object.
469472
// Returns 0 if System.Object is passed in.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ LWM(IsValidToken, DLD, DWORD)
151151
LWM(IsValueClass, DWORDLONG, DWORD)
152152
LWM(IsWriteBarrierHelperRequired, DWORDLONG, DWORD)
153153
LWM(MergeClasses, DLDL, DWORDLONG)
154+
LWM(IsMoreSpecificType, DLDL, DWORD)
154155
LWM(PInvokeMarshalingRequired, PInvokeMarshalingRequiredValue, DWORD)
155156
LWM(ResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, ResolveTokenValue)
156157
LWM(ResolveVirtualMethod, Agnostic_ResolveVirtualMethod, DWORDLONG)

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5318,6 +5318,41 @@ CORINFO_CLASS_HANDLE MethodContext::repMergeClasses(CORINFO_CLASS_HANDLE cls1, C
53185318
return (CORINFO_CLASS_HANDLE)value;
53195319
}
53205320

5321+
void MethodContext::recIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, BOOL result)
5322+
{
5323+
if (IsMoreSpecificType == nullptr)
5324+
IsMoreSpecificType = new LightWeightMap<DLDL, DWORD>();
5325+
DLDL key;
5326+
ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
5327+
// out padding too
5328+
5329+
key.A = (DWORDLONG)cls1;
5330+
key.B = (DWORDLONG)cls2;
5331+
5332+
IsMoreSpecificType->Add(key, (DWORD)result);
5333+
}
5334+
void MethodContext::dmpIsMoreSpecificType(DLDL key, DWORD value)
5335+
{
5336+
printf("IsMoreSpecificType key cls1-%016llX cls2-%016llX, value %u", key.A, key.B, value);
5337+
}
5338+
BOOL MethodContext::repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
5339+
{
5340+
DLDL key;
5341+
ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
5342+
// out padding too
5343+
DWORD value;
5344+
5345+
key.A = (DWORDLONG)cls1;
5346+
key.B = (DWORDLONG)cls2;
5347+
5348+
AssertCodeMsg(IsMoreSpecificType->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX %016llX", (DWORDLONG)cls1,
5349+
(DWORDLONG)cls2);
5350+
5351+
value = IsMoreSpecificType->Get(key);
5352+
5353+
return (BOOL)value;
5354+
}
5355+
53215356
void MethodContext::recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result)
53225357
{
53235358
if (GetCookieForPInvokeCalliSig == nullptr)

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,10 @@ class MethodContext
12041204
void dmpMergeClasses(DLDL key, DWORDLONG value);
12051205
CORINFO_CLASS_HANDLE repMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
12061206

1207+
void recIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, BOOL result);
1208+
void dmpIsMoreSpecificType(DLDL key, DWORD value);
1209+
BOOL repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
1210+
12071211
void recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result);
12081212
void dmpGetCookieForPInvokeCalliSig(const GetCookieForPInvokeCalliSigValue& key, DLDL value);
12091213
LPVOID repGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection);
@@ -1348,7 +1352,7 @@ class MethodContext
13481352
};
13491353

13501354
// ********************* Please keep this up-to-date to ease adding more ***************
1351-
// Highest packet number: 173
1355+
// Highest packet number: 174
13521356
// *************************************************************************************
13531357
enum mcPackets
13541358
{
@@ -1494,6 +1498,7 @@ enum mcPackets
14941498
Packet_IsValueClass = 105,
14951499
Packet_IsWriteBarrierHelperRequired = 106,
14961500
Packet_MergeClasses = 107,
1501+
Packet_IsMoreSpecificType = 174, // Added 2/14/2019
14971502
Packet_PInvokeMarshalingRequired = 108,
14981503
Packet_ResolveToken = 109,
14991504
Packet_ResolveVirtualMethod = 160, // Added 2/13/17

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ TypeCompareState interceptor_ICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE
987987
return temp;
988988
}
989989

990-
// returns is the intersection of cls1 and cls2.
990+
// returns the intersection of cls1 and cls2.
991991
CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
992992
{
993993
mc->cr->AddCall("mergeClasses");
@@ -996,6 +996,15 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, C
996996
return temp;
997997
}
998998

999+
// Returns true if cls2 is known to be a more specific type than cls1.
1000+
BOOL interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
1001+
{
1002+
mc->cr->AddCall("isMoreSpecificType");
1003+
BOOL temp = original_ICorJitInfo->isMoreSpecificType(cls1, cls2);
1004+
mc->recIsMoreSpecificType(cls1, cls2, temp);
1005+
return temp;
1006+
}
1007+
9991008
// Given a class handle, returns the Parent type.
10001009
// For COMObjectType, it returns Class Handle of System.Object.
10011010
// Returns 0 if System.Object is passed in.

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,13 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, C
776776
return original_ICorJitInfo->mergeClasses(cls1, cls2);
777777
}
778778

779+
// Returns true if cls2 is known to be a more specific type than cls1.
780+
BOOL interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
781+
{
782+
mcs->AddCall("isMoreSpecificType");
783+
return original_ICorJitInfo->isMoreSpecificType(cls1, cls2);
784+
}
785+
779786
// Given a class handle, returns the Parent type.
780787
// For COMObjectType, it returns Class Handle of System.Object.
781788
// Returns 0 if System.Object is passed in.

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,12 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, C
692692
return original_ICorJitInfo->mergeClasses(cls1, cls2);
693693
}
694694

695+
// Returns true if cls2 is known to be a more specific type than cls1.
696+
BOOL interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
697+
{
698+
return original_ICorJitInfo->isMoreSpecificType(cls1, cls2);
699+
}
700+
695701
// Given a class handle, returns the Parent type.
696702
// For COMObjectType, it returns Class Handle of System.Object.
697703
// Returns 0 if System.Object is passed in.

src/ToolBox/superpmi/superpmi/icorjitinfo.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,13 +826,20 @@ TypeCompareState MyICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORI
826826
return jitInstance->mc->repCompareTypesForEquality(cls1, cls2);
827827
}
828828

829-
// returns is the intersection of cls1 and cls2.
829+
// returns the intersection of cls1 and cls2.
830830
CORINFO_CLASS_HANDLE MyICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
831831
{
832832
jitInstance->mc->cr->AddCall("mergeClasses");
833833
return jitInstance->mc->repMergeClasses(cls1, cls2);
834834
}
835835

836+
// Returns true if cls2 is known to be a more specific type than cls1
837+
BOOL MyICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
838+
{
839+
jitInstance->mc->cr->AddCall("isMoreSpecificType");
840+
return jitInstance->mc->repIsMoreSpecificType(cls1, cls2);
841+
}
842+
836843
// Given a class handle, returns the Parent type.
837844
// For COMObjectType, it returns Class Handle of System.Object.
838845
// Returns 0 if System.Object is passed in.

src/inc/corinfo.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,11 @@ TODO: Talk about initializing strutures before use
213213
#define SELECTANY extern __declspec(selectany)
214214
#endif
215215

216-
SELECTANY const GUID JITEEVersionIdentifier = { /* 8903fe7b-a82a-4e2e-b691-f58430b485d1 */
217-
0x8903fe7b,
218-
0xa82a,
219-
0x4e2e,
220-
{0xb6, 0x91, 0xf5, 0x84, 0x30, 0xb4, 0x85, 0xd1}
216+
SELECTANY const GUID JITEEVersionIdentifier = { /* d609bed1-7831-49fc-bd49-b6f054dd4d46 */
217+
0xd609bed1,
218+
0x7831,
219+
0x49fc,
220+
{0xbd, 0x49, 0xb6, 0xf0, 0x54, 0xdd, 0x4d, 0x46}
221221
};
222222

223223
//////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -2592,12 +2592,22 @@ class ICorStaticInfo
25922592
CORINFO_CLASS_HANDLE cls2
25932593
) = 0;
25942594

2595-
// returns is the intersection of cls1 and cls2.
2595+
// Returns the intersection of cls1 and cls2.
25962596
virtual CORINFO_CLASS_HANDLE mergeClasses(
25972597
CORINFO_CLASS_HANDLE cls1,
25982598
CORINFO_CLASS_HANDLE cls2
25992599
) = 0;
26002600

2601+
// Returns true if cls2 is known to be a more specific type
2602+
// than cls1 (a subtype or more restrictive shared type)
2603+
// for purposes of jit type tracking. This is a hint to the
2604+
// jit for optimization; it does not have correctness
2605+
// implications.
2606+
virtual BOOL isMoreSpecificType(
2607+
CORINFO_CLASS_HANDLE cls1,
2608+
CORINFO_CLASS_HANDLE cls2
2609+
) = 0;
2610+
26012611
// Given a class handle, returns the Parent type.
26022612
// For COMObjectType, it returns Class Handle of System.Object.
26032613
// Returns 0 if System.Object is passed in.

src/jit/lclvars.cpp

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2704,27 +2704,7 @@ void Compiler::lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool
27042704
// updating exact classes.
27052705
if (!varDsc->lvClassIsExact && isNewClass)
27062706
{
2707-
// Todo: improve this analysis by adding a new jit interface method
2708-
DWORD newAttrs = info.compCompHnd->getClassAttribs(clsHnd);
2709-
DWORD oldAttrs = info.compCompHnd->getClassAttribs(varDsc->lvClassHnd);
2710-
2711-
// Avoid funny things with __Canon by only merging if both shared or both unshared
2712-
if ((newAttrs & CORINFO_FLG_SHAREDINST) == (oldAttrs & CORINFO_FLG_SHAREDINST))
2713-
{
2714-
// If we merge types and we get back the old class, the new class is more
2715-
// specific and we should update to it.
2716-
CORINFO_CLASS_HANDLE mergeClass = info.compCompHnd->mergeClasses(clsHnd, varDsc->lvClassHnd);
2717-
2718-
if (mergeClass == varDsc->lvClassHnd)
2719-
{
2720-
shouldUpdate = true;
2721-
}
2722-
}
2723-
else if ((newAttrs & CORINFO_FLG_SHAREDINST) == 0)
2724-
{
2725-
// Update if we go from shared to unshared
2726-
shouldUpdate = true;
2727-
}
2707+
shouldUpdate = info.compCompHnd->isMoreSpecificType(varDsc->lvClassHnd, clsHnd);
27282708
}
27292709
// Else are we attempting to update exactness?
27302710
else if (isExact && !varDsc->lvClassIsExact && !isNewClass)
@@ -2736,9 +2716,9 @@ void Compiler::lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool
27362716
if (isNewClass || (isExact != varDsc->lvClassIsExact))
27372717
{
27382718
JITDUMP("\nlvaUpdateClass:%s Updating class for V%02u", shouldUpdate ? "" : " NOT", varNum);
2739-
JITDUMP(" from(%p) %s%s", dspPtr(varDsc->lvClassHnd), info.compCompHnd->getClassName(varDsc->lvClassHnd),
2719+
JITDUMP(" from (%p) %s%s", dspPtr(varDsc->lvClassHnd), info.compCompHnd->getClassName(varDsc->lvClassHnd),
27402720
varDsc->lvClassIsExact ? " [exact]" : "");
2741-
JITDUMP(" to(%p) %s%s\n", dspPtr(clsHnd), info.compCompHnd->getClassName(clsHnd), isExact ? " [exact]" : "");
2721+
JITDUMP(" to (%p) %s%s\n", dspPtr(clsHnd), info.compCompHnd->getClassName(clsHnd), isExact ? " [exact]" : "");
27422722
}
27432723
#endif // DEBUG
27442724

0 commit comments

Comments
 (0)