diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 56589cf6b793873dc02fbdf09205f98ebf91dc1f..79ecdefc60ceee2cd8e90f73adb9a870099eae6f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -1252,20 +1252,30 @@ private RuntimePropertyInfo[] PopulateProperties(Filter filter) Dictionary>? csPropertyInfos = filter.CaseSensitive() ? null : new Dictionary>(); - // All elements automatically initialized to false. - bool[] usedSlots = new bool[RuntimeTypeHandle.GetNumVirtuals(declaringType)]; + // All elements initialized to false. + int numVirtuals = RuntimeTypeHandle.GetNumVirtuals(declaringType); + Span usedSlots = stackalloc bool[0]; + if (numVirtuals <= 128) // arbitrary stack limit + { + usedSlots = stackalloc bool[numVirtuals]; + usedSlots.Clear(); + } + else + { + usedSlots = new bool[numVirtuals]; + } // Populate associates off of the class hierarchy do { - PopulateProperties(filter, declaringType, csPropertyInfos, usedSlots, ref list); + PopulateProperties(filter, declaringType, csPropertyInfos, usedSlots, isInterface: false, ref list); declaringType = RuntimeTypeHandle.GetBaseType(declaringType); } while (declaringType != null); } else { // Populate associates for this interface - PopulateProperties(filter, declaringType, null, null, ref list); + PopulateProperties(filter, declaringType, null, default, isInterface: true, ref list); } return list.ToArray(); @@ -1275,7 +1285,8 @@ private RuntimePropertyInfo[] PopulateProperties(Filter filter) Filter filter, RuntimeType declaringType, Dictionary>? csPropertyInfos, - bool[]? usedSlots, + Span usedSlots, + bool isInterface, ref ListBuilder list) { int tkDeclaringType = RuntimeTypeHandle.GetToken(declaringType); @@ -1290,8 +1301,8 @@ private RuntimePropertyInfo[] PopulateProperties(Filter filter) int numVirtuals = RuntimeTypeHandle.GetNumVirtuals(declaringType); - Debug.Assert((declaringType.IsInterface && usedSlots == null && csPropertyInfos == null) || - (!declaringType.IsInterface && usedSlots != null && usedSlots.Length >= numVirtuals)); + Debug.Assert((declaringType.IsInterface && isInterface && csPropertyInfos == null) || + (!declaringType.IsInterface && !isInterface && usedSlots.Length >= numVirtuals)); for (int i = 0; i < tkProperties.Length; i++) { @@ -1313,7 +1324,7 @@ private RuntimePropertyInfo[] PopulateProperties(Filter filter) tkProperty, declaringType, m_runtimeTypeCache, out bool isPrivate); // If this is a class, not an interface - if (usedSlots != null) + if (!isInterface) { #region Remove Privates if (declaringType != ReflectedType && isPrivate)