Skip to content

Commit f846c97

Browse files
authored
Avoid bool[] allocation in MemberInfoCache.PopulateProperties (#66912)
1 parent 103fb84 commit f846c97

File tree

1 file changed

+19
-8
lines changed

1 file changed

+19
-8
lines changed

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

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,20 +1252,30 @@ private RuntimePropertyInfo[] PopulateProperties(Filter filter)
12521252
Dictionary<string, List<RuntimePropertyInfo>>? csPropertyInfos = filter.CaseSensitive() ? null :
12531253
new Dictionary<string, List<RuntimePropertyInfo>>();
12541254

1255-
// All elements automatically initialized to false.
1256-
bool[] usedSlots = new bool[RuntimeTypeHandle.GetNumVirtuals(declaringType)];
1255+
// All elements initialized to false.
1256+
int numVirtuals = RuntimeTypeHandle.GetNumVirtuals(declaringType);
1257+
Span<bool> usedSlots = stackalloc bool[0];
1258+
if (numVirtuals <= 128) // arbitrary stack limit
1259+
{
1260+
usedSlots = stackalloc bool[numVirtuals];
1261+
usedSlots.Clear();
1262+
}
1263+
else
1264+
{
1265+
usedSlots = new bool[numVirtuals];
1266+
}
12571267

12581268
// Populate associates off of the class hierarchy
12591269
do
12601270
{
1261-
PopulateProperties(filter, declaringType, csPropertyInfos, usedSlots, ref list);
1271+
PopulateProperties(filter, declaringType, csPropertyInfos, usedSlots, isInterface: false, ref list);
12621272
declaringType = RuntimeTypeHandle.GetBaseType(declaringType);
12631273
} while (declaringType != null);
12641274
}
12651275
else
12661276
{
12671277
// Populate associates for this interface
1268-
PopulateProperties(filter, declaringType, null, null, ref list);
1278+
PopulateProperties(filter, declaringType, null, default, isInterface: true, ref list);
12691279
}
12701280

12711281
return list.ToArray();
@@ -1275,7 +1285,8 @@ private void PopulateProperties(
12751285
Filter filter,
12761286
RuntimeType declaringType,
12771287
Dictionary<string, List<RuntimePropertyInfo>>? csPropertyInfos,
1278-
bool[]? usedSlots,
1288+
Span<bool> usedSlots,
1289+
bool isInterface,
12791290
ref ListBuilder<RuntimePropertyInfo> list)
12801291
{
12811292
int tkDeclaringType = RuntimeTypeHandle.GetToken(declaringType);
@@ -1290,8 +1301,8 @@ private void PopulateProperties(
12901301

12911302
int numVirtuals = RuntimeTypeHandle.GetNumVirtuals(declaringType);
12921303

1293-
Debug.Assert((declaringType.IsInterface && usedSlots == null && csPropertyInfos == null) ||
1294-
(!declaringType.IsInterface && usedSlots != null && usedSlots.Length >= numVirtuals));
1304+
Debug.Assert((declaringType.IsInterface && isInterface && csPropertyInfos == null) ||
1305+
(!declaringType.IsInterface && !isInterface && usedSlots.Length >= numVirtuals));
12951306

12961307
for (int i = 0; i < tkProperties.Length; i++)
12971308
{
@@ -1313,7 +1324,7 @@ private void PopulateProperties(
13131324
tkProperty, declaringType, m_runtimeTypeCache, out bool isPrivate);
13141325

13151326
// If this is a class, not an interface
1316-
if (usedSlots != null)
1327+
if (!isInterface)
13171328
{
13181329
#region Remove Privates
13191330
if (declaringType != ReflectedType && isPrivate)

0 commit comments

Comments
 (0)