Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStephen Toub <stoub@microsoft.com>2022-09-29 14:37:41 +0300
committerGitHub <noreply@github.com>2022-09-29 14:37:41 +0300
commit4a302db0996faf2dadcfaacd1cf54e9a97b80f86 (patch)
tree73858effd3c336e1c7a4e5ea3f35eca34fb7b5f6 /src
parentef6cb3dfc868411efc9410ebb1b4725a2b83d5fc (diff)
Reduce Enum.GetEnumName overheads (#76162)
* Reduce Enum.GetEnumName overheads This also helps Enum.ToString(), Enum.IsDefined, etc. Many enums are composed of sequential values starting at 0 (half of all enums in corelib, for example, meet this criteria). Today when looking up a value, we search the array of values, but if an enum is known to have such sequential values, we can instead just index into the array at the appropriate location. * Address PR feedback
Diffstat (limited to 'src')
-rw-r--r--src/coreclr/System.Private.CoreLib/src/System/Enum.CoreCLR.cs13
-rw-r--r--src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/EnumInfo.cs11
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Enum.EnumInfo.cs12
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Enum.cs35
4 files changed, 57 insertions, 14 deletions
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Enum.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Enum.CoreCLR.cs
index fb1dd0a0349..18d9a6db206 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Enum.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Enum.CoreCLR.cs
@@ -72,11 +72,15 @@ namespace System
return underlyingType;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static EnumInfo GetEnumInfo(RuntimeType enumType, bool getNames = true)
{
- EnumInfo? entry = enumType.GenericCache as EnumInfo;
+ return enumType.GenericCache is EnumInfo info && (!getNames || info.Names is not null) ?
+ info :
+ InitializeEnumInfo(enumType, getNames);
- if (entry == null || (getNames && entry.Names == null))
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static EnumInfo InitializeEnumInfo(RuntimeType enumType, bool getNames)
{
ulong[]? values = null;
string[]? names = null;
@@ -88,11 +92,10 @@ namespace System
getNames ? Interop.BOOL.TRUE : Interop.BOOL.FALSE);
bool hasFlagsAttribute = enumType.IsDefined(typeof(FlagsAttribute), inherit: false);
- entry = new EnumInfo(hasFlagsAttribute, values!, names!);
+ var entry = new EnumInfo(hasFlagsAttribute, values!, names!);
enumType.GenericCache = entry;
+ return entry;
}
-
- return entry;
}
}
}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/EnumInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/EnumInfo.cs
index 761a38833bd..87509675a96 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/EnumInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/EnumInfo.cs
@@ -65,6 +65,16 @@ namespace System.Reflection
Array.Copy(rawValues, ValuesAsUnderlyingType, numValues);
HasFlagsAttribute = isFlags;
+
+ ValuesAreSequentialFromZero = true;
+ for (int i = 0; i < values.Length; i++)
+ {
+ if (values[i] != (ulong)i)
+ {
+ ValuesAreSequentialFromZero = false;
+ break;
+ }
+ }
}
internal Type UnderlyingType { get; }
@@ -72,5 +82,6 @@ namespace System.Reflection
internal ulong[] Values { get; }
internal Array ValuesAsUnderlyingType { get; }
internal bool HasFlagsAttribute { get; }
+ internal bool ValuesAreSequentialFromZero { get; }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.EnumInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.EnumInfo.cs
index 7ab48cfb11f..67f4d5860f6 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Enum.EnumInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Enum.EnumInfo.cs
@@ -8,6 +8,7 @@ namespace System
internal sealed class EnumInfo
{
public readonly bool HasFlagsAttribute;
+ public readonly bool ValuesAreSequentialFromZero;
public readonly ulong[] Values;
public readonly string[] Names;
@@ -17,6 +18,17 @@ namespace System
HasFlagsAttribute = hasFlagsAttribute;
Values = values;
Names = names;
+
+ // Store whether all of the values are sequential starting from zero.
+ ValuesAreSequentialFromZero = true;
+ for (int i = 0; i < values.Length; i++)
+ {
+ if (values[i] != (ulong)i)
+ {
+ ValuesAreSequentialFromZero = false;
+ break;
+ }
+ }
}
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs
index 7e1ac66a010..d35f3a46c46 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs
@@ -116,12 +116,24 @@ namespace System
return GetEnumName(GetEnumInfo(enumType), ulValue);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static string? GetEnumName(EnumInfo enumInfo, ulong ulValue)
{
- int index = FindDefinedIndex(enumInfo.Values, ulValue);
- if (index >= 0)
+ if (enumInfo.ValuesAreSequentialFromZero)
+ {
+ string[] names = enumInfo.Names;
+ if (ulValue < (ulong)names.Length)
+ {
+ return names[(uint)ulValue];
+ }
+ }
+ else
{
- return enumInfo.Names[index];
+ int index = FindDefinedIndex(enumInfo.Values, ulValue);
+ if (index >= 0)
+ {
+ return enumInfo.Names[index];
+ }
}
return null; // return null so the caller knows to .ToString() the input
@@ -302,7 +314,7 @@ namespace System
internal static string[] InternalGetNames(RuntimeType enumType) =>
// Get all of the names
- GetEnumInfo(enumType, true).Names;
+ GetEnumInfo(enumType).Names;
public static Type GetUnderlyingType(Type enumType)
{
@@ -411,16 +423,21 @@ namespace System
internal static ulong[] InternalGetValues(RuntimeType enumType)
{
// Get all of the values
- return GetEnumInfo(enumType, false).Values;
+ return GetEnumInfo(enumType, getNames: false).Values;
}
public static bool IsDefined<TEnum>(TEnum value) where TEnum : struct, Enum
{
RuntimeType enumType = (RuntimeType)typeof(TEnum);
- ulong[] ulValues = Enum.InternalGetValues(enumType);
- ulong ulValue = Enum.ToUInt64(value);
-
- return FindDefinedIndex(ulValues, ulValue) >= 0;
+ EnumInfo info = GetEnumInfo(enumType, getNames: false);
+ ulong ulValue = ToUInt64(value);
+ ulong[] ulValues = info.Values;
+
+ // If the enum's values are all sequentially numbered starting from 0, then we can
+ // just return if the requested index is in range. Otherwise, search for the value.
+ return
+ info.ValuesAreSequentialFromZero ? ulValue < (ulong)ulValues.Length :
+ FindDefinedIndex(ulValues, ulValue) >= 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]