Skip to content

Commit ba53a92

Browse files
authored
JIT: switch escape analysis flagging to look for calls returning IEnumerator<T> (#116978)
Conditional Escape Analysis (CEA) is currently driven by flagging GDV calls made to `IEnumerable<T>.GetEnumerator`. Generalize this slightly to instead look for any call that returns an `IEnumerator<T>`, since there are some classes that return enumerators via other calls. These calls likely won't be GDVs; I will address adapting CEA to handle that in subsequent changes.
1 parent 27c8fe0 commit ba53a92

File tree

6 files changed

+23
-25
lines changed

6 files changed

+23
-25
lines changed

src/coreclr/jit/importer.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6929,30 +6929,33 @@ void Compiler::impImportBlockCode(BasicBlock* block)
69296929
}
69306930

69316931
// If we see a local being assigned the result of a GDV-inlineable
6932-
// IEnumerable<T>.GetEnumerator, keep track of both the local and the call.
6932+
// GetEnumerator call, keep track of both the local and the call.
69336933
//
69346934
if (op1->OperIs(GT_RET_EXPR))
69356935
{
6936-
JITDUMP(".... checking for GDV of IEnumerable<T>...\n");
6936+
JITDUMP(".... checking for GDV returning IEnumerator<T>...\n");
69376937

6938-
GenTreeCall* const call = op1->AsRetExpr()->gtInlineCandidate;
6939-
NamedIntrinsic ni = NI_Illegal;
6938+
bool isEnumeratorT = false;
6939+
GenTreeCall* const call = op1->AsRetExpr()->gtInlineCandidate;
6940+
bool isExact = false;
6941+
bool isNonNull = false;
6942+
CORINFO_CLASS_HANDLE retCls = gtGetClassHandle(call, &isExact, &isNonNull);
69406943

6941-
// TODO -- handle CT_INDIRECT virtuals here too
6942-
// but we don't have the right method handle
6943-
//
6944-
if (call->gtCallType == CT_USER_FUNC)
6945-
{
6946-
ni = lookupNamedIntrinsic(call->gtCallMethHnd);
6947-
}
6948-
else if (call->IsGuardedDevirtualizationCandidate())
6944+
if ((retCls != NO_CLASS_HANDLE) && info.compCompHnd->isIntrinsicType(retCls))
69496945
{
6950-
JITDUMP("No GDV IEnumerable<T> check for [%06u]\n", dspTreeID(call));
6946+
const char* namespaceName;
6947+
const char* className = info.compCompHnd->getClassNameFromMetadata(retCls, &namespaceName);
6948+
6949+
if ((strcmp(namespaceName, "System.Collections.Generic") == 0) &&
6950+
(strcmp(className, "IEnumerator`1") == 0))
6951+
{
6952+
isEnumeratorT = true;
6953+
}
69516954
}
69526955

6953-
if (ni == NI_System_Collections_Generic_IEnumerable_GetEnumerator)
6956+
if (isEnumeratorT)
69546957
{
6955-
JITDUMP("V%02u value is GDV of IEnumerable<T>.GetEnumerator\n", lclNum);
6958+
JITDUMP("V%02u value is IEnumerator<T> via GDV\n", lclNum);
69566959
lvaTable[lclNum].lvIsEnumerator = true;
69576960
JITDUMP("Flagging [%06u] for enumerator cloning via V%02u\n", dspTreeID(call), lclNum);
69586961
getImpEnumeratorGdvLocalMap()->Set(call, lclNum);

src/coreclr/jit/importercalls.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10342,13 +10342,6 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
1034210342
result = NI_System_Collections_Generic_EqualityComparer_get_Default;
1034310343
}
1034410344
}
10345-
else if (strcmp(className, "IEnumerable`1") == 0)
10346-
{
10347-
if (strcmp(methodName, "GetEnumerator") == 0)
10348-
{
10349-
result = NI_System_Collections_Generic_IEnumerable_GetEnumerator;
10350-
}
10351-
}
1035210345
}
1035310346
else if (strcmp(namespaceName, "Numerics") == 0)
1035410347
{

src/coreclr/jit/namedintrinsiclist.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@ enum NamedIntrinsic : unsigned short
259259
//
260260
NI_System_SZArrayHelper_GetEnumerator,
261261
NI_System_Array_T_GetEnumerator,
262-
NI_System_Collections_Generic_IEnumerable_GetEnumerator,
263262
};
264263

265264
#endif // _NAMEDINTRINSICLIST_H_

src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CompilerServices/IntrinsicAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace System.Runtime.CompilerServices
55
{
66
// This attribute is only for use in a Class Library
7-
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)]
7+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface, Inherited = false)]
88
internal sealed class IntrinsicAttribute : Attribute
99
{
1010
}

src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IEnumerator.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Runtime.CompilerServices;
5+
46
namespace System.Collections.Generic
57
{
68
// Base interface for all generic enumerators, providing a simple approach
79
// to iterating over a collection.
10+
[Intrinsic]
811
public interface IEnumerator<out T> : IDisposable, IEnumerator
912
where T : allows ref struct
1013
{

src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/IntrinsicAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace System.Runtime.CompilerServices
66
// Calls to methods or references to fields marked with this attribute may be replaced at
77
// some call sites with jit intrinsic expansions.
88
// Types marked with this attribute may be specially treated by the runtime/compiler.
9-
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)]
9+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface, Inherited = false)]
1010
internal sealed class IntrinsicAttribute : Attribute
1111
{
1212
}

0 commit comments

Comments
 (0)