Skip to content

Commit 6906730

Browse files
authored
JIT: Support for devirtualizing array interface methods (#108153)
Update JIT and runtime to devirtualize interface calls on arrays over non-shared element types. Shared types are not (yet) handled. Add intrinsic and inlining attributes to key methods in the BCL. This allows the JIT to devirtualize and inline enumerator creation and devirtualize and inline all methods that access the enumerator. And this in turn allows the enumerator to be stack allocated in some simple cases. However, the enumerator fields are not (yet) physically promoted, because of an optimization in the BCL to return a static empty array enumerator. So the object being accessed later is ambiguous. Alse ensure that since GDV resolves the virtual call twice, and expects to get similar results both times, things work for the array case by keeping track of the initial devirtualization inputs. Progress towards #62457.
1 parent 8611665 commit 6906730

32 files changed

+597
-216
lines changed

src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs

+2
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,8 @@ private SZArrayHelper()
740740
Debug.Fail("Hey! How'd I get here?");
741741
}
742742

743+
[Intrinsic]
744+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
743745
internal IEnumerator<T> GetEnumerator<T>()
744746
{
745747
// ! Warning: "this" is an array, not an SZArrayHelper. See comments above

src/coreclr/inc/corinfo.h

+11-2
Original file line numberDiff line numberDiff line change
@@ -1510,18 +1510,21 @@ struct CORINFO_DEVIRTUALIZATION_INFO
15101510
// [Out] results of resolveVirtualMethod.
15111511
// - devirtualizedMethod is set to MethodDesc of devirt'ed method iff we were able to devirtualize.
15121512
// invariant is `resolveVirtualMethod(...) == (devirtualizedMethod != nullptr)`.
1513-
// - requiresInstMethodTableArg is set to TRUE if the devirtualized method requires a type handle arg.
15141513
// - exactContext is set to wrapped CORINFO_CLASS_HANDLE of devirt'ed method table.
15151514
// - details on the computation done by the jit host
15161515
// - If pResolvedTokenDevirtualizedMethod is not set to NULL and targeting an R2R image
15171516
// use it as the parameter to getCallInfo
1517+
// - requiresInstMethodTableArg is set to TRUE if the devirtualized method requires a type handle arg.
1518+
// - wasArrayInterfaceDevirt is set TRUE for array interface method devirtualization
1519+
// (in which case the method handle and context will be a generic method)
15181520
//
15191521
CORINFO_METHOD_HANDLE devirtualizedMethod;
1520-
bool requiresInstMethodTableArg;
15211522
CORINFO_CONTEXT_HANDLE exactContext;
15221523
CORINFO_DEVIRTUALIZATION_DETAIL detail;
15231524
CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod;
15241525
CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod;
1526+
bool requiresInstMethodTableArg;
1527+
bool wasArrayInterfaceDevirt;
15251528
};
15261529

15271530
//----------------------------------------------------------------------------
@@ -2123,6 +2126,12 @@ class ICorStaticInfo
21232126
CORINFO_CLASS_HANDLE elemType
21242127
) = 0;
21252128

2129+
// Given T, return the type of the SZArrayHelper enumerator
2130+
// Returns null if the type can't be determined exactly.
2131+
virtual CORINFO_CLASS_HANDLE getSZArrayHelperEnumeratorClass(
2132+
CORINFO_CLASS_HANDLE elemType
2133+
) = 0;
2134+
21262135
// Given resolved token that corresponds to an intrinsic classified to
21272136
// get a raw handle (NI_System_Activator_AllocatorOf etc.), fetch the
21282137
// handle associated with the token. If this is not possible at

src/coreclr/inc/icorjitinfoimpl_generated.h

+3
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ CORINFO_CLASS_HANDLE getDefaultComparerClass(
105105
CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(
106106
CORINFO_CLASS_HANDLE elemType) override;
107107

108+
CORINFO_CLASS_HANDLE getSZArrayHelperEnumeratorClass(
109+
CORINFO_CLASS_HANDLE elemType) override;
110+
108111
void expandRawHandleIntrinsic(
109112
CORINFO_RESOLVED_TOKEN* pResolvedToken,
110113
CORINFO_METHOD_HANDLE callerHandle,

src/coreclr/inc/jiteeversionguid.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
4343
#define GUID_DEFINED
4444
#endif // !GUID_DEFINED
4545

46-
constexpr GUID JITEEVersionIdentifier = { /* b75a5475-ff22-4078-9551-2024ce03d383 */
47-
0xb75a5475,
48-
0xff22,
49-
0x4078,
50-
{0x95, 0x51, 0x20, 0x24, 0xce, 0x03, 0xd3, 0x83}
46+
constexpr GUID JITEEVersionIdentifier = { /* 9b8ef809-94d4-41b6-9d4c-dd61379abbe0 */
47+
0x9b8ef809,
48+
0x94d4,
49+
0x41b6,
50+
{0x9d, 0x4c, 0xdd, 0x61, 0x37, 0x9a, 0xbb, 0xe0}
5151
};
5252

5353
//////////////////////////////////////////////////////////////////////////////////////////////////////////

src/coreclr/jit/ICorJitInfo_names_generated.h

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ DEF_CLR_API(resolveVirtualMethod)
2424
DEF_CLR_API(getUnboxedEntry)
2525
DEF_CLR_API(getDefaultComparerClass)
2626
DEF_CLR_API(getDefaultEqualityComparerClass)
27+
DEF_CLR_API(getSZArrayHelperEnumeratorClass)
2728
DEF_CLR_API(expandRawHandleIntrinsic)
2829
DEF_CLR_API(isIntrinsicType)
2930
DEF_CLR_API(getUnmanagedCallConv)

src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,15 @@ CORINFO_CLASS_HANDLE WrapICorJitInfo::getDefaultEqualityComparerClass(
209209
return temp;
210210
}
211211

212+
CORINFO_CLASS_HANDLE WrapICorJitInfo::getSZArrayHelperEnumeratorClass(
213+
CORINFO_CLASS_HANDLE elemType)
214+
{
215+
API_ENTER(getSZArrayHelperEnumeratorClass);
216+
CORINFO_CLASS_HANDLE temp = wrapHnd->getSZArrayHelperEnumeratorClass(elemType);
217+
API_LEAVE(getSZArrayHelperEnumeratorClass);
218+
return temp;
219+
}
220+
212221
void WrapICorJitInfo::expandRawHandleIntrinsic(
213222
CORINFO_RESOLVED_TOKEN* pResolvedToken,
214223
CORINFO_METHOD_HANDLE callerHandle,

src/coreclr/jit/compiler.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -7573,7 +7573,9 @@ class Compiler
75737573
CORINFO_CONTEXT_HANDLE contextHandle,
75747574
unsigned methodAttr,
75757575
unsigned classAttr,
7576-
unsigned likelihood);
7576+
unsigned likelihood,
7577+
bool arrayInterface,
7578+
CORINFO_CONTEXT_HANDLE originalContextHandle);
75777579

75787580
int getGDVMaxTypeChecks()
75797581
{

src/coreclr/jit/fginline.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ bool Compiler::IsDisallowedRecursiveInline(InlineContext* ancestor, InlineInfo*
6969
{
7070
// We disallow inlining the exact same instantiation.
7171
if ((ancestor->GetCallee() == inlineInfo->fncHandle) &&
72-
(ancestor->GetRuntimeContext() == inlineInfo->inlineCandidateInfo->exactContextHnd))
72+
(ancestor->GetRuntimeContext() == inlineInfo->inlineCandidateInfo->exactContextHandle))
7373
{
7474
JITDUMP("Call site is trivially recursive\n");
7575
return true;
@@ -80,7 +80,7 @@ bool Compiler::IsDisallowedRecursiveInline(InlineContext* ancestor, InlineInfo*
8080
// involved this can quickly consume a large amount of resources, so try to
8181
// verify that we aren't inlining recursively with complex contexts.
8282
if (info.compCompHnd->haveSameMethodDefinition(inlineInfo->fncHandle, ancestor->GetCallee()) &&
83-
ContextComplexityExceeds(inlineInfo->inlineCandidateInfo->exactContextHnd, 64))
83+
ContextComplexityExceeds(inlineInfo->inlineCandidateInfo->exactContextHandle, 64))
8484
{
8585
JITDUMP("Call site is recursive with a complex generic context\n");
8686
return true;
@@ -1300,7 +1300,7 @@ void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* inlineRe
13001300
->NewContext(pParam->inlineInfo->inlineCandidateInfo->inlinersContext, pParam->inlineInfo->iciStmt,
13011301
pParam->inlineInfo->iciCall);
13021302
pParam->inlineInfo->argCnt = pParam->inlineCandidateInfo->methInfo.args.totalILArgs();
1303-
pParam->inlineInfo->tokenLookupContextHandle = pParam->inlineCandidateInfo->exactContextHnd;
1303+
pParam->inlineInfo->tokenLookupContextHandle = pParam->inlineCandidateInfo->exactContextHandle;
13041304

13051305
JITLOG_THIS(pParam->pThis,
13061306
(LL_INFO100000, "INLINER: inlineInfo.tokenLookupContextHandle for %s set to 0x%p:\n",
@@ -2042,7 +2042,7 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo)
20422042

20432043
if (inlineInfo->inlineCandidateInfo->initClassResult & CORINFO_INITCLASS_USE_HELPER)
20442044
{
2045-
CORINFO_CLASS_HANDLE exactClass = eeGetClassFromContext(inlineInfo->inlineCandidateInfo->exactContextHnd);
2045+
CORINFO_CLASS_HANDLE exactClass = eeGetClassFromContext(inlineInfo->inlineCandidateInfo->exactContextHandle);
20462046

20472047
tree = fgGetSharedCCtor(exactClass);
20482048
newStmt = gtNewStmt(tree, callDI);

src/coreclr/jit/gentree.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -12981,9 +12981,10 @@ void Compiler::gtDispTree(GenTree* tree,
1298112981
{
1298212982
inlineInfo = call->GetSingleInlineCandidateInfo();
1298312983
}
12984-
if ((inlineInfo != nullptr) && (inlineInfo->exactContextHnd != nullptr))
12984+
12985+
if ((inlineInfo != nullptr) && (inlineInfo->exactContextHandle != nullptr))
1298512986
{
12986-
printf(" (exactContextHnd=0x%p)", dspPtr(inlineInfo->exactContextHnd));
12987+
printf(" (exactContextHandle=0x%p)", dspPtr(inlineInfo->exactContextHandle));
1298712988
}
1298812989
}
1298912990

@@ -19048,7 +19049,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b
1904819049
// of the inlinee.
1904919050
if (eeIsSharedInst(objClass))
1905019051
{
19051-
CORINFO_CONTEXT_HANDLE context = inlInfo->exactContextHnd;
19052+
CORINFO_CONTEXT_HANDLE context = inlInfo->exactContextHandle;
1905219053

1905319054
if (context != nullptr)
1905419055
{

0 commit comments

Comments
 (0)