From 573aa508b851c9cdfe746e5bdab70541161e2dc1 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 30 Oct 2017 11:03:48 -0700 Subject: [PATCH] Simplify Comparer/EqualityComparers (#14737) - Make EnumEqualityComparer sealed. This helps with JIT optimizations. - Delete SByteEnumEqualityComparer and ShortEnumEqualityComparer because of they are not needed anymore. The optimization that they were introduced for is done by the JIT now. - Deleted ForwardedFrom attributes on types that do not need them --- .../src/System/Collections/Generic/Comparer.cs | 4 -- .../System/Collections/Generic/ComparerHelpers.cs | 8 +--- .../System/Collections/Generic/EqualityComparer.cs | 43 ++-------------------- src/vm/compile.cpp | 14 ++----- src/vm/jitinterface.cpp | 10 ----- src/vm/mscorlib.h | 2 - 6 files changed, 8 insertions(+), 73 deletions(-) diff --git a/src/mscorlib/src/System/Collections/Generic/Comparer.cs b/src/mscorlib/src/System/Collections/Generic/Comparer.cs index bb9e07d..cb4ad85 100644 --- a/src/mscorlib/src/System/Collections/Generic/Comparer.cs +++ b/src/mscorlib/src/System/Collections/Generic/Comparer.cs @@ -133,7 +133,6 @@ namespace System.Collections.Generic // since we want to serialize as ObjectComparer for // back-compat reasons (see below). [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] internal sealed class Int32EnumComparer : Comparer, ISerializable where T : struct { public Int32EnumComparer() @@ -169,7 +168,6 @@ namespace System.Collections.Generic } [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] internal sealed class UInt32EnumComparer : Comparer, ISerializable where T : struct { public UInt32EnumComparer() @@ -201,7 +199,6 @@ namespace System.Collections.Generic } [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] internal sealed class Int64EnumComparer : Comparer, ISerializable where T : struct { public Int64EnumComparer() @@ -230,7 +227,6 @@ namespace System.Collections.Generic } [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] internal sealed class UInt64EnumComparer : Comparer, ISerializable where T : struct { public UInt64EnumComparer() diff --git a/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs b/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs index 1c4b9bb..2575d4e 100644 --- a/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs +++ b/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs @@ -187,17 +187,13 @@ namespace System.Collections.Generic TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(enumType)); // Depending on the enum type, we need to special case the comparers so that we avoid boxing. - // Note: We have different comparers for short and sbyte, since for those types GetHashCode does not simply return the value. - // We need to preserve what they would return. switch (underlyingTypeCode) { - case TypeCode.Int16: - return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ShortEnumEqualityComparer), enumType); - case TypeCode.SByte: - return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(SByteEnumEqualityComparer), enumType); case TypeCode.Int32: case TypeCode.UInt32: + case TypeCode.SByte: case TypeCode.Byte: + case TypeCode.Int16: case TypeCode.UInt16: return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer), enumType); case TypeCode.Int64: diff --git a/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs b/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs index 3af0cf4..aad7c75 100644 --- a/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs +++ b/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs @@ -363,7 +363,7 @@ namespace System.Collections.Generic [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - internal class EnumEqualityComparer : EqualityComparer, ISerializable where T : struct + internal sealed class EnumEqualityComparer : EqualityComparer, ISerializable where T : struct { [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(T x, T y) @@ -376,8 +376,7 @@ namespace System.Collections.Generic [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode(T obj) { - int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj); - return x_final.GetHashCode(); + return obj.GetHashCode(); } public EnumEqualityComparer() { } @@ -426,41 +425,6 @@ namespace System.Collections.Generic } [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - internal sealed class SByteEnumEqualityComparer : EnumEqualityComparer where T : struct - { - public SByteEnumEqualityComparer() { } - - // This is used by the serialization engine. - public SByteEnumEqualityComparer(SerializationInfo information, StreamingContext context) { } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode(T obj) - { - int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj); - return ((sbyte)x_final).GetHashCode(); - } - } - - [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - internal sealed class ShortEnumEqualityComparer : EnumEqualityComparer, ISerializable where T : struct - { - public ShortEnumEqualityComparer() { } - - // This is used by the serialization engine. - public ShortEnumEqualityComparer(SerializationInfo information, StreamingContext context) { } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode(T obj) - { - int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj); - return ((short)x_final).GetHashCode(); - } - } - - [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] internal sealed class LongEnumEqualityComparer : EqualityComparer, ISerializable where T : struct { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -474,8 +438,7 @@ namespace System.Collections.Generic [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode(T obj) { - long x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong(obj); - return x_final.GetHashCode(); + return obj.GetHashCode(); } // Equals method for the comparer itself. diff --git a/src/vm/compile.cpp b/src/vm/compile.cpp index fb93a89..327f0f1 100644 --- a/src/vm/compile.cpp +++ b/src/vm/compile.cpp @@ -5205,21 +5205,13 @@ static void SpecializeEqualityComparer(SString& ss, Instantiation& inst) if (et == ELEMENT_TYPE_I4 || et == ELEMENT_TYPE_U4 || et == ELEMENT_TYPE_U2 || - et == ELEMENT_TYPE_U1) + et == ELEMENT_TYPE_I2 || + et == ELEMENT_TYPE_U1 || + et == ELEMENT_TYPE_I1) { ss.Set(W("System.Collections.Generic.EnumEqualityComparer`1")); return; } - else if (et == ELEMENT_TYPE_I2) - { - ss.Set(W("System.Collections.Generic.ShortEnumEqualityComparer`1")); - return; - } - else if (et == ELEMENT_TYPE_I1) - { - ss.Set(W("System.Collections.Generic.SByteEnumEqualityComparer`1")); - return; - } else if (et == ELEMENT_TYPE_I8 || et == ELEMENT_TYPE_U8) { diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp index 7c9fa17..bce81c4 100644 --- a/src/vm/jitinterface.cpp +++ b/src/vm/jitinterface.cpp @@ -8897,17 +8897,7 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS switch(normType) { case ELEMENT_TYPE_I1: - { - targetClass = MscorlibBinder::GetClass(CLASS__SBYTE_ENUM_EQUALITYCOMPARER); - break; - } - case ELEMENT_TYPE_I2: - { - targetClass = MscorlibBinder::GetClass(CLASS__SHORT_ENUM_EQUALITYCOMPARER); - break; - } - case ELEMENT_TYPE_U1: case ELEMENT_TYPE_U2: case ELEMENT_TYPE_I4: diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index e757624..f20e8d3 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -1449,8 +1449,6 @@ DEFINE_METHOD(UTF8BUFFERMARSHALER, CONVERT_TO_MANAGED, ConvertToManaged, NoSig) // Classes referenced in EqualityComparer.Default optimization DEFINE_CLASS(BYTE_EQUALITYCOMPARER, CollectionsGeneric, ByteEqualityComparer) -DEFINE_CLASS(SHORT_ENUM_EQUALITYCOMPARER, CollectionsGeneric, ShortEnumEqualityComparer`1) -DEFINE_CLASS(SBYTE_ENUM_EQUALITYCOMPARER, CollectionsGeneric, SByteEnumEqualityComparer`1) DEFINE_CLASS(ENUM_EQUALITYCOMPARER, CollectionsGeneric, EnumEqualityComparer`1) DEFINE_CLASS(LONG_ENUM_EQUALITYCOMPARER, CollectionsGeneric, LongEnumEqualityComparer`1) DEFINE_CLASS(NULLABLE_EQUALITYCOMPARER, CollectionsGeneric, NullableEqualityComparer`1) -- 2.7.4