From 560e4cbc808985d3e4f03c4998802153d6fdb2ea Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 28 Jul 2022 08:50:27 -0700 Subject: [PATCH 01/19] Equality check of type members after hot reload --- .../RuntimeTypeMetadataUpdateHandler.cs | 3 + .../RuntimeConstructorInfo.CoreCLR.cs | 10 +++ .../src/System/Reflection/RuntimeEventInfo.cs | 7 ++ .../src/System/Reflection/RuntimeFieldInfo.cs | 7 ++ .../Reflection/RuntimeMethodInfo.CoreCLR.cs | 60 ++++++++------- .../System/Reflection/RuntimeParameterInfo.cs | 9 +++ .../System/Reflection/RuntimePropertyInfo.cs | 7 ++ .../System/Reflection/ReflectionCacheTests.cs | 74 ++++++++++++++++++- 8 files changed, 147 insertions(+), 30 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs index e45e84efb60f01..697e5fa93bf05c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs @@ -11,11 +11,14 @@ namespace System.Reflection.Metadata /// Metadata update handler used to clear a Type's reflection cache in response to a metadata update notification. internal static class RuntimeTypeMetadataUpdateHandler { + public static bool HotReloadDeltaApplied { get; internal set; } + /// Clear type caches in response to an update notification. /// The specific types to be cleared, or null to clear everything. [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Clearing the caches on a Type isn't affected if a Type is trimmed, or has any of its members trimmed.")] public static void ClearCache(Type[]? types) { + HotReloadDeltaApplied = true; if (RequiresClearingAllTypes(types)) { // TODO: This should ideally be in a QCall in the runtime. As written here: diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index 51ee0061420e0f..4c3be145b92c4d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Text; using System.Threading; @@ -118,6 +119,15 @@ public override string ToString() return m_toString; } + + public override bool Equals(object? obj) => + obj == (object)this || + (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && + obj is RuntimeConstructorInfo m && + MetadataToken == m.MetadataToken && + RuntimeTypeHandle.GetModule(m_declaringType).Equals(RuntimeTypeHandle.GetModule(m.m_declaringType))); + + public override int GetHashCode() => base.GetHashCode(); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index 366c9288662bbf..24667fa5290f3d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Reflection.Metadata; using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache; namespace System.Reflection @@ -68,6 +69,12 @@ public override string ToString() return m_addMethod.GetParametersNoCopy()[0].ParameterType.FormatTypeName() + " " + Name; } + + public override bool Equals(object? obj) => + obj == (object)this || + (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && CacheEquals(obj)); + + public override int GetHashCode() => base.GetHashCode(); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index cf06b03d661a96..94771e63c05a2b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Reflection.Metadata; using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache; namespace System.Reflection @@ -46,6 +47,12 @@ internal RuntimeType GetDeclaringTypeInternal() public override Module Module => GetRuntimeModule(); public override bool IsCollectible => m_declaringType.IsCollectible; + + public override bool Equals(object? obj) => + obj == (object)this || + (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && CacheEquals(obj)); + + public override int GetHashCode() => base.GetHashCode(); #endregion #region Object Overrides diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 229e2981bb6f25..767c8e74d7533b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Security; using System.Text; @@ -168,44 +169,51 @@ public override int GetHashCode() public override bool Equals(object? obj) { - if (!IsGenericMethod) - return obj == (object)this; + if (IsGenericMethod) + { + // We cannot do simple object identity comparisons for generic methods. + // Equals will be called in CerHashTable when RuntimeType+RuntimeTypeCache.GetGenericMethodInfo() + // retrieve items from and insert items into s_methodInstantiations which is a CerHashtable. - // We cannot do simple object identity comparisons for generic methods. - // Equals will be called in CerHashTable when RuntimeType+RuntimeTypeCache.GetGenericMethodInfo() - // retrieve items from and insert items into s_methodInstantiations which is a CerHashtable. + RuntimeMethodInfo? mi = obj as RuntimeMethodInfo; - RuntimeMethodInfo? mi = obj as RuntimeMethodInfo; + if (mi == null || !mi.IsGenericMethod) + return false; - if (mi == null || !mi.IsGenericMethod) - return false; + // now we know that both operands are generic methods - // now we know that both operands are generic methods + IRuntimeMethodInfo handle1 = RuntimeMethodHandle.StripMethodInstantiation(this); + IRuntimeMethodInfo handle2 = RuntimeMethodHandle.StripMethodInstantiation(mi); + if (handle1.Value.Value != handle2.Value.Value) + return false; - IRuntimeMethodInfo handle1 = RuntimeMethodHandle.StripMethodInstantiation(this); - IRuntimeMethodInfo handle2 = RuntimeMethodHandle.StripMethodInstantiation(mi); - if (handle1.Value.Value != handle2.Value.Value) - return false; + Type[] lhs = GetGenericArguments(); + Type[] rhs = mi.GetGenericArguments(); - Type[] lhs = GetGenericArguments(); - Type[] rhs = mi.GetGenericArguments(); + if (lhs.Length != rhs.Length) + return false; - if (lhs.Length != rhs.Length) - return false; + for (int i = 0; i < lhs.Length; i++) + { + if (lhs[i] != rhs[i]) + return false; + } - for (int i = 0; i < lhs.Length; i++) - { - if (lhs[i] != rhs[i]) + if (DeclaringType != mi.DeclaringType) return false; - } - if (DeclaringType != mi.DeclaringType) - return false; + if (ReflectedType != mi.ReflectedType) + return false; - if (ReflectedType != mi.ReflectedType) - return false; + return true; + } + + return obj == (object)this || + (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && + obj is RuntimeMethodInfo m && + m.MetadataToken == MetadataToken && + RuntimeTypeHandle.GetModule(m_declaringType).Equals(RuntimeTypeHandle.GetModule(m.m_declaringType))); - return true; } #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 434a821715caf8..94d7dc9c388750 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Reflection.Metadata; using System.Runtime.CompilerServices; using MdToken = System.Reflection.MetadataToken; @@ -496,6 +497,14 @@ public override Type[] GetOptionalCustomModifiers() m_signature.GetCustomModifiers(PositionImpl + 1, false); } + public override bool Equals(object? obj) => + obj == (object)this || + (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && + obj is RuntimeParameterInfo m && + m_tkParamDef == m.m_tkParamDef && + GetRuntimeModule()!.Equals(m.GetRuntimeModule())); + + public override int GetHashCode() => base.GetHashCode(); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 82c582a3386659..3881da2cbe8a65 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.Reflection.Metadata; using System.Text; using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache; @@ -179,6 +180,12 @@ public override IList GetCustomAttributesData() public override Module Module => GetRuntimeModule(); internal RuntimeModule GetRuntimeModule() { return m_declaringType.GetRuntimeModule(); } public override bool IsCollectible => m_declaringType.IsCollectible; + + public override bool Equals(object? obj) => + obj == (object)this || + (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && CacheEquals(obj)); + + public override int GetHashCode() => base.GetHashCode(); #endregion #region PropertyInfo Overrides diff --git a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs index 4833893eb3dfe6..2dab9ac8f397bb 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs @@ -9,16 +9,44 @@ namespace System.Reflection.Tests [Collection(nameof(DisableParallelization))] public class ReflectionCacheTests { + private static readonly Type s_type = typeof(ReflectionCacheTests); + + public string Property { get; set; } + + public int Field1; + + private void Method() + { + Event1(null, EventArgs.Empty); + } + + public event EventHandler Event1; + [Fact] public void GetMethod_MultipleCalls_SameObjects() { - MethodInfo mi1 = typeof(ReflectionCacheTests).GetMethod(nameof(GetMethod_MultipleCalls_SameObjects)); + MethodInfo mi1 = s_type.GetMethod(nameof(GetMethod_MultipleCalls_SameObjects)); + PropertyInfo pi1 = s_type.GetProperty(nameof(Property)); + FieldInfo fi1 = s_type.GetField(nameof(Field1)); + EventInfo ei1 = s_type.GetEvent(nameof(Event1)); Assert.NotNull(mi1); + Assert.NotNull(pi1); + Assert.NotNull(fi1); - MethodInfo mi2 = typeof(ReflectionCacheTests).GetMethod(nameof(GetMethod_MultipleCalls_SameObjects)); + MethodInfo mi2 = s_type.GetMethod(nameof(GetMethod_MultipleCalls_SameObjects)); + PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); + FieldInfo fi2 = s_type.GetField(nameof(Field1)); Assert.NotNull(mi2); + Assert.NotNull(pi2); + Assert.NotNull(fi2); + Assert.False(HotReloadDeltaApplied()); Assert.Same(mi1, mi2); + Assert.Same(pi1, pi2); + Assert.Same(fi1, fi2); + Assert.Equal(mi1, mi2); + Assert.Equal(pi1, pi2); + Assert.Equal(fi1, fi2); } [ActiveIssue("https://github.com/dotnet/runtime/issues/50978", TestRuntimes.Mono)] @@ -40,17 +68,47 @@ public void GetMethod_MultipleCalls_ClearCache_DifferentObjects(bool justSpecifi { Action clearCache = GetClearCacheMethod(); - MethodInfo mi1 = typeof(ReflectionCacheTests).GetMethod(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects)); + MethodInfo mi1 = s_type.GetMethod(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects)); + PropertyInfo pi1 = s_type.GetProperty(nameof(Property)); + FieldInfo fi1 = s_type.GetField(nameof(Field1)); + EventInfo ei1 = s_type.GetEvent(nameof(Event1)); + ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); + ParameterInfo pai1 = mi1.GetParameters()[0]; Assert.NotNull(mi1); + Assert.NotNull(pi1); + Assert.NotNull(fi1); Assert.Equal(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects), mi1.Name); + Assert.Equal(nameof(Property), pi1.Name); + Assert.Equal(nameof(Field1), fi1.Name); clearCache(justSpecificType ? new[] { typeof(ReflectionCacheTests) } : null); + Assert.True(HotReloadDeltaApplied()); - MethodInfo mi2 = typeof(ReflectionCacheTests).GetMethod(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects)); + MethodInfo mi2 = s_type.GetMethod(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects)); + PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); + FieldInfo fi2 = s_type.GetField(nameof(Field1)); + EventInfo ei2 = s_type.GetEvent(nameof(Event1)); + ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); + ParameterInfo pai2 = mi2.GetParameters()[0]; Assert.NotNull(mi2); + Assert.NotNull(pi2); + Assert.NotNull(fi2); Assert.Equal(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects), mi2.Name); + Assert.Equal(nameof(Property), pi2.Name); + Assert.Equal(nameof(Field1), fi2.Name); Assert.NotSame(mi1, mi2); + Assert.NotSame(pi1, pi2); + Assert.NotSame(fi1, fi2); + Assert.NotSame(ei1, ei2); + Assert.NotSame(ci1, ci2); + Assert.NotSame(pai1, pai2); + Assert.Equal(mi1, mi2); + Assert.Equal(pi1, pi2); + Assert.Equal(fi1, fi2); + Assert.Equal(ei1, ei2); + Assert.Equal(ci1, ci2); + Assert.Equal(pai1, pai2); } private static Action GetClearCacheMethod() @@ -60,5 +118,13 @@ private static Action GetClearCacheMethod() Assert.NotNull(clearCache); return clearCache.CreateDelegate>(); } + + private static bool HotReloadDeltaApplied() + { + Type updateHandler = typeof(Type).Assembly.GetType("System.Reflection.Metadata.RuntimeTypeMetadataUpdateHandler", throwOnError: true, ignoreCase: false); + PropertyInfo hotReloadApplied = updateHandler.GetProperty("HotReloadDeltaApplied", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + Assert.NotNull(hotReloadApplied); + return (bool)hotReloadApplied.GetValue(null); + } } } From bfe943b583aa14dfcc0c5a823aa3cdf76591fe9e Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Fri, 29 Jul 2022 14:28:56 -0700 Subject: [PATCH 02/19] Apply comments --- .../RuntimeTypeMetadataUpdateHandler.cs | 3 ++- .../RuntimeConstructorInfo.CoreCLR.cs | 2 +- .../src/System/Reflection/RuntimeEventInfo.cs | 2 +- .../src/System/Reflection/RuntimeFieldInfo.cs | 2 +- .../Reflection/RuntimeMethodInfo.CoreCLR.cs | 2 +- .../System/Reflection/RuntimeParameterInfo.cs | 2 +- .../System/Reflection/RuntimePropertyInfo.cs | 2 +- .../ILLink/ILLink.Substitutions.Shared.xml | 3 +++ .../System/Reflection/ReflectionCacheTests.cs | 27 +++++++++++++++++-- 9 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs index 697e5fa93bf05c..970e6a628f0f77 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs @@ -11,7 +11,7 @@ namespace System.Reflection.Metadata /// Metadata update handler used to clear a Type's reflection cache in response to a metadata update notification. internal static class RuntimeTypeMetadataUpdateHandler { - public static bool HotReloadDeltaApplied { get; internal set; } + public static bool HotReloadDeltaApplied { get; private set; } /// Clear type caches in response to an update notification. /// The specific types to be cleared, or null to clear everything. @@ -19,6 +19,7 @@ internal static class RuntimeTypeMetadataUpdateHandler public static void ClearCache(Type[]? types) { HotReloadDeltaApplied = true; + if (RequiresClearingAllTypes(types)) { // TODO: This should ideally be in a QCall in the runtime. As written here: diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index 4c3be145b92c4d..edefa04a879e72 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -127,7 +127,7 @@ obj is RuntimeConstructorInfo m && MetadataToken == m.MetadataToken && RuntimeTypeHandle.GetModule(m_declaringType).Equals(RuntimeTypeHandle.GetModule(m.m_declaringType))); - public override int GetHashCode() => base.GetHashCode(); + public override int GetHashCode() => m_handle.GetHashCode(); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index 24667fa5290f3d..e07d81f1f6f5ab 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -74,7 +74,7 @@ public override bool Equals(object? obj) => obj == (object)this || (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && CacheEquals(obj)); - public override int GetHashCode() => base.GetHashCode(); + public override int GetHashCode() => HashCode.Combine(m_token.GetHashCode(), RuntimeTypeHandle.GetModule(m_declaringType).GetHashCode()); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index 94771e63c05a2b..c0eb785b9440e0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -52,7 +52,7 @@ public override bool Equals(object? obj) => obj == (object)this || (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && CacheEquals(obj)); - public override int GetHashCode() => base.GetHashCode(); + public override int GetHashCode() => HashCode.Combine(MetadataToken.GetHashCode(), Module.GetHashCode()); #endregion #region Object Overrides diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 767c8e74d7533b..f83124388f1f4c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -164,7 +164,7 @@ public override int GetHashCode() if (IsGenericMethod) return ValueType.GetHashCodeOfPtr(m_handle); else - return base.GetHashCode(); + return m_handle.GetHashCode(); } public override bool Equals(object? obj) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 94d7dc9c388750..74b84830783a55 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -504,7 +504,7 @@ obj is RuntimeParameterInfo m && m_tkParamDef == m.m_tkParamDef && GetRuntimeModule()!.Equals(m.GetRuntimeModule())); - public override int GetHashCode() => base.GetHashCode(); + public override int GetHashCode() => HashCode.Combine(m_tkParamDef.GetHashCode(), GetRuntimeModule()!.GetHashCode()); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 3881da2cbe8a65..dd2ba21b18b0fd 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -185,7 +185,7 @@ public override bool Equals(object? obj) => obj == (object)this || (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && CacheEquals(obj)); - public override int GetHashCode() => base.GetHashCode(); + public override int GetHashCode() => HashCode.Combine(m_token.GetHashCode(), Module.GetHashCode()); #endregion #region PropertyInfo Overrides diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml index 9765f3ab4f662e..1b6596e82601c6 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml @@ -37,5 +37,8 @@ + + + diff --git a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs index 2dab9ac8f397bb..d6a039aede6af0 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs @@ -40,7 +40,6 @@ public void GetMethod_MultipleCalls_SameObjects() Assert.NotNull(pi2); Assert.NotNull(fi2); - Assert.False(HotReloadDeltaApplied()); Assert.Same(mi1, mi2); Assert.Same(pi1, pi2); Assert.Same(fi1, fi2); @@ -74,6 +73,13 @@ public void GetMethod_MultipleCalls_ClearCache_DifferentObjects(bool justSpecifi EventInfo ei1 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); ParameterInfo pai1 = mi1.GetParameters()[0]; + int mi1Hash = mi1.GetHashCode(); + int pi1Hash = pi1.GetHashCode(); + int fi1Hash = fi1.GetHashCode(); + int ei1Hash = ei1.GetHashCode(); + int ci1Hash = ci1.GetHashCode(); + int pai1Hash = pai1.GetHashCode(); + Assert.NotNull(mi1); Assert.NotNull(pi1); Assert.NotNull(fi1); @@ -83,13 +89,19 @@ public void GetMethod_MultipleCalls_ClearCache_DifferentObjects(bool justSpecifi clearCache(justSpecificType ? new[] { typeof(ReflectionCacheTests) } : null); Assert.True(HotReloadDeltaApplied()); - MethodInfo mi2 = s_type.GetMethod(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects)); PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); FieldInfo fi2 = s_type.GetField(nameof(Field1)); EventInfo ei2 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); ParameterInfo pai2 = mi2.GetParameters()[0]; + int mi2Hash = mi2.GetHashCode(); + int pi2Hash = pi2.GetHashCode(); + int fi2Hash = fi2.GetHashCode(); + int ei2Hash = ei2.GetHashCode(); + int ci2Hash = ci2.GetHashCode(); + int pai2Hash = pai2.GetHashCode(); + Assert.NotNull(mi2); Assert.NotNull(pi2); Assert.NotNull(fi2); @@ -97,18 +109,29 @@ public void GetMethod_MultipleCalls_ClearCache_DifferentObjects(bool justSpecifi Assert.Equal(nameof(Property), pi2.Name); Assert.Equal(nameof(Field1), fi2.Name); + // After the Cache cleared the references of same member will be diffenet Assert.NotSame(mi1, mi2); Assert.NotSame(pi1, pi2); Assert.NotSame(fi1, fi2); Assert.NotSame(ei1, ei2); Assert.NotSame(ci1, ci2); Assert.NotSame(pai1, pai2); + + // But they should be evaluated as Equal so that there were no issue using the same member after hot reload Assert.Equal(mi1, mi2); Assert.Equal(pi1, pi2); Assert.Equal(fi1, fi2); Assert.Equal(ei1, ei2); Assert.Equal(ci1, ci2); Assert.Equal(pai1, pai2); + + // And the HashCode of a member before and after hot reload should produce same result + Assert.Equal(mi1Hash, mi2Hash); + Assert.Equal(pi1Hash, pi2Hash); + Assert.Equal(fi1Hash, fi2Hash); + Assert.Equal(ei1Hash, ei2Hash); + Assert.Equal(ci1Hash, ci2Hash); + Assert.Equal(pai1Hash, pai2Hash); } private static Action GetClearCacheMethod() From 76e2b02b831a107ee889d7bca6d94526509dbd49 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Mon, 1 Aug 2022 12:40:36 -0700 Subject: [PATCH 03/19] Apply feedback --- .../RuntimeTypeMetadataUpdateHandler.cs | 5 +- .../RuntimeConstructorInfo.CoreCLR.cs | 2 +- .../src/System/Reflection/RuntimeEventInfo.cs | 2 +- .../src/System/Reflection/RuntimeFieldInfo.cs | 2 +- .../Reflection/RuntimeMethodInfo.CoreCLR.cs | 2 +- .../System/Reflection/RuntimeParameterInfo.cs | 2 +- .../System/Reflection/RuntimePropertyInfo.cs | 2 +- .../ILLink/ILLink.Substitutions.Shared.xml | 3 - .../System/Reflection/ReflectionCacheTests.cs | 195 ++++++++++++------ 9 files changed, 138 insertions(+), 77 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs index 970e6a628f0f77..2a8d966d8895d5 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs @@ -11,14 +11,15 @@ namespace System.Reflection.Metadata /// Metadata update handler used to clear a Type's reflection cache in response to a metadata update notification. internal static class RuntimeTypeMetadataUpdateHandler { - public static bool HotReloadDeltaApplied { get; private set; } + private static bool s_cacheCleared; + public static bool MetadataUpdaterSupportedAndCacheCleared => MetadataUpdater.IsSupported && s_cacheCleared; /// Clear type caches in response to an update notification. /// The specific types to be cleared, or null to clear everything. [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Clearing the caches on a Type isn't affected if a Type is trimmed, or has any of its members trimmed.")] public static void ClearCache(Type[]? types) { - HotReloadDeltaApplied = true; + s_cacheCleared = true; if (RequiresClearingAllTypes(types)) { diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index edefa04a879e72..019f6f5ab2b838 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -122,7 +122,7 @@ public override string ToString() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && + (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && obj is RuntimeConstructorInfo m && MetadataToken == m.MetadataToken && RuntimeTypeHandle.GetModule(m_declaringType).Equals(RuntimeTypeHandle.GetModule(m.m_declaringType))); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index e07d81f1f6f5ab..1b663ebca81aab 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -72,7 +72,7 @@ public override string ToString() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && CacheEquals(obj)); + (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && CacheEquals(obj)); public override int GetHashCode() => HashCode.Combine(m_token.GetHashCode(), RuntimeTypeHandle.GetModule(m_declaringType).GetHashCode()); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index c0eb785b9440e0..8c0b02b53b6118 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -50,7 +50,7 @@ internal RuntimeType GetDeclaringTypeInternal() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && CacheEquals(obj)); + (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && CacheEquals(obj)); public override int GetHashCode() => HashCode.Combine(MetadataToken.GetHashCode(), Module.GetHashCode()); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index f83124388f1f4c..57d5fcee12a2a6 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -209,7 +209,7 @@ public override bool Equals(object? obj) } return obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && + (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && obj is RuntimeMethodInfo m && m.MetadataToken == MetadataToken && RuntimeTypeHandle.GetModule(m_declaringType).Equals(RuntimeTypeHandle.GetModule(m.m_declaringType))); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 74b84830783a55..042b7ad0ad8c33 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -499,7 +499,7 @@ public override Type[] GetOptionalCustomModifiers() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && + (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && obj is RuntimeParameterInfo m && m_tkParamDef == m.m_tkParamDef && GetRuntimeModule()!.Equals(m.GetRuntimeModule())); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index dd2ba21b18b0fd..08203f03f42ca2 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -183,7 +183,7 @@ public override IList GetCustomAttributesData() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.HotReloadDeltaApplied && CacheEquals(obj)); + (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && CacheEquals(obj)); public override int GetHashCode() => HashCode.Combine(m_token.GetHashCode(), Module.GetHashCode()); #endregion diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml index 1b6596e82601c6..9765f3ab4f662e 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml @@ -37,8 +37,5 @@ - - - diff --git a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs index d6a039aede6af0..366ae2037fb7cc 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Tests; +using Microsoft.DotNet.RemoteExecutor; using Xunit; namespace System.Reflection.Tests @@ -9,13 +10,18 @@ namespace System.Reflection.Tests [Collection(nameof(DisableParallelization))] public class ReflectionCacheTests { + private static bool IsMetadataUpdateAndRemoteExecutorSupported => PlatformDetection.IsMetadataUpdateSupported && RemoteExecutor.IsSupported; + private static readonly Type s_type = typeof(ReflectionCacheTests); + //private BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; public string Property { get; set; } public int Field1; - private void Method() +#pragma warning disable xUnit1013 // Public method should be marked as test + public void Method(bool param) +#pragma warning restore xUnit1013 // Public method should be marked as test { Event1(null, EventArgs.Empty); } @@ -23,29 +29,39 @@ private void Method() public event EventHandler Event1; [Fact] - public void GetMethod_MultipleCalls_SameObjects() + public void GetMembers_MultipleCalls_SameObjects() { - MethodInfo mi1 = s_type.GetMethod(nameof(GetMethod_MultipleCalls_SameObjects)); + MethodInfo mi1 = s_type.GetMethod(nameof(Method)); PropertyInfo pi1 = s_type.GetProperty(nameof(Property)); FieldInfo fi1 = s_type.GetField(nameof(Field1)); EventInfo ei1 = s_type.GetEvent(nameof(Event1)); - Assert.NotNull(mi1); - Assert.NotNull(pi1); - Assert.NotNull(fi1); + ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); + ParameterInfo pai1 = mi1.GetParameters()[0]; - MethodInfo mi2 = s_type.GetMethod(nameof(GetMethod_MultipleCalls_SameObjects)); + AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); + + MethodInfo mi2 = s_type.GetMethod(nameof(Method)); PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); FieldInfo fi2 = s_type.GetField(nameof(Field1)); - Assert.NotNull(mi2); - Assert.NotNull(pi2); - Assert.NotNull(fi2); + EventInfo ei2 = s_type.GetEvent(nameof(Event1)); + ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); + ParameterInfo pai2 = mi2.GetParameters()[0]; + + AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2, pai2); Assert.Same(mi1, mi2); Assert.Same(pi1, pi2); Assert.Same(fi1, fi2); + Assert.Same(ei1, ei2); + Assert.Same(ci1, ci2); + Assert.Same(pai1, pai2); + Assert.Equal(mi1, mi2); Assert.Equal(pi1, pi2); Assert.Equal(fi1, fi2); + Assert.Equal(ei1, ei2); + Assert.Equal(ci1, ci2); + Assert.Equal(pai1, pai2); } [ActiveIssue("https://github.com/dotnet/runtime/issues/50978", TestRuntimes.Mono)] @@ -60,56 +76,71 @@ public void InvokeClearCache_NoExceptions() } [ActiveIssue("https://github.com/dotnet/runtime/issues/50978", TestRuntimes.Mono)] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsMetadataUpdateSupported))] - [InlineData(false)] - [InlineData(true)] - public void GetMethod_MultipleCalls_ClearCache_DifferentObjects(bool justSpecificType) + [ConditionalFact(typeof(ReflectionCacheTests), nameof(IsMetadataUpdateAndRemoteExecutorSupported))] + public void GetMembers_MultipleCalls_ClearCache_SpecificType() { - Action clearCache = GetClearCacheMethod(); + RemoteInvokeOptions options = new RemoteInvokeOptions(); + options.StartInfo.EnvironmentVariables.Add("DOTNET_MODIFIABLE_ASSEMBLIES", "debug"); + + using RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(() => + { + Action clearCache = GetClearCacheMethod(); + + MethodInfo mi1 = s_type.GetMethod(nameof(Method)); + PropertyInfo pi1 = s_type.GetProperty(nameof(Property)); + FieldInfo fi1 = s_type.GetField(nameof(Field1)); + EventInfo ei1 = s_type.GetEvent(nameof(Event1)); + ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); + ParameterInfo pai1 = mi1.GetParameters()[0]; + + AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); + + clearCache(new[] { typeof(ReflectionCacheTests) }); + Assert.True(HotReloadDeltaApplied()); + + MethodInfo mi2 = s_type.GetMethod(nameof(Method)); + PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); + FieldInfo fi2 = s_type.GetField(nameof(Field1)); + EventInfo ei2 = s_type.GetEvent(nameof(Event1)); + ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); + ParameterInfo pai2 = mi2.GetParameters()[0]; + + AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2, pai2); + + // After the Cache cleared the references of the same member of same type will be diffenet + // But they should be evaluated as Equal so that there were no issue using the same member after hot reload + AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, pai1, mi2, pi2, fi2, ei2, ci2, pai2); + + // And the HashCode of a member before and after hot reload should produce same result + AssertHashCodesAreEqual(mi1.GetHashCode(), pi1.GetHashCode(), fi1.GetHashCode(), ei1.GetHashCode(), ci1.GetHashCode(), pai1.GetHashCode(), + mi2.GetHashCode(), pi2.GetHashCode(), fi2.GetHashCode(), ei2.GetHashCode(), ci2.GetHashCode(), pai2.GetHashCode()); + }, options); + } - MethodInfo mi1 = s_type.GetMethod(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects)); - PropertyInfo pi1 = s_type.GetProperty(nameof(Property)); - FieldInfo fi1 = s_type.GetField(nameof(Field1)); - EventInfo ei1 = s_type.GetEvent(nameof(Event1)); - ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); - ParameterInfo pai1 = mi1.GetParameters()[0]; - int mi1Hash = mi1.GetHashCode(); - int pi1Hash = pi1.GetHashCode(); - int fi1Hash = fi1.GetHashCode(); - int ei1Hash = ei1.GetHashCode(); - int ci1Hash = ci1.GetHashCode(); - int pai1Hash = pai1.GetHashCode(); - - Assert.NotNull(mi1); - Assert.NotNull(pi1); - Assert.NotNull(fi1); - Assert.Equal(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects), mi1.Name); - Assert.Equal(nameof(Property), pi1.Name); - Assert.Equal(nameof(Field1), fi1.Name); - - clearCache(justSpecificType ? new[] { typeof(ReflectionCacheTests) } : null); - Assert.True(HotReloadDeltaApplied()); - MethodInfo mi2 = s_type.GetMethod(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects)); - PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); - FieldInfo fi2 = s_type.GetField(nameof(Field1)); - EventInfo ei2 = s_type.GetEvent(nameof(Event1)); - ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); - ParameterInfo pai2 = mi2.GetParameters()[0]; - int mi2Hash = mi2.GetHashCode(); - int pi2Hash = pi2.GetHashCode(); - int fi2Hash = fi2.GetHashCode(); - int ei2Hash = ei2.GetHashCode(); - int ci2Hash = ci2.GetHashCode(); - int pai2Hash = pai2.GetHashCode(); - - Assert.NotNull(mi2); - Assert.NotNull(pi2); - Assert.NotNull(fi2); - Assert.Equal(nameof(GetMethod_MultipleCalls_ClearCache_DifferentObjects), mi2.Name); - Assert.Equal(nameof(Property), pi2.Name); - Assert.Equal(nameof(Field1), fi2.Name); - - // After the Cache cleared the references of same member will be diffenet + private static void AssertMembersAreNotNull(MethodInfo mi, PropertyInfo pi, FieldInfo fi, EventInfo ei, ConstructorInfo ci, ParameterInfo pai) + { + Assert.NotNull(mi); + Assert.NotNull(pi); + Assert.NotNull(fi); + Assert.NotNull(ei); + Assert.NotNull(ci); + Assert.NotNull(pai); + } + + private static void AssertHashCodesAreEqual(int mi1Hash, int pi1Hash, int fi1Hash, int ei1Hash, int ci1Hash, int pai1Hash, + int mi2Hash, int pi2Hash, int fi2Hash, int ei2Hash, int ci2Hash, int pai2Hash) + { + Assert.Equal(mi1Hash, mi2Hash); + Assert.Equal(pi1Hash, pi2Hash); + Assert.Equal(fi1Hash, fi2Hash); + Assert.Equal(ei1Hash, ei2Hash); + Assert.Equal(ci1Hash, ci2Hash); + Assert.Equal(pai1Hash, pai2Hash); + } + + private static void AssertMemberReferencesNotSameButEqual(MethodInfo mi1, PropertyInfo pi1, FieldInfo fi1, EventInfo ei1, ConstructorInfo ci1, ParameterInfo pai1, + MethodInfo mi2, PropertyInfo pi2, FieldInfo fi2, EventInfo ei2, ConstructorInfo ci2, ParameterInfo pai2) + { Assert.NotSame(mi1, mi2); Assert.NotSame(pi1, pi2); Assert.NotSame(fi1, fi2); @@ -117,21 +148,53 @@ public void GetMethod_MultipleCalls_ClearCache_DifferentObjects(bool justSpecifi Assert.NotSame(ci1, ci2); Assert.NotSame(pai1, pai2); - // But they should be evaluated as Equal so that there were no issue using the same member after hot reload Assert.Equal(mi1, mi2); Assert.Equal(pi1, pi2); Assert.Equal(fi1, fi2); Assert.Equal(ei1, ei2); Assert.Equal(ci1, ci2); Assert.Equal(pai1, pai2); + } - // And the HashCode of a member before and after hot reload should produce same result - Assert.Equal(mi1Hash, mi2Hash); - Assert.Equal(pi1Hash, pi2Hash); - Assert.Equal(fi1Hash, fi2Hash); - Assert.Equal(ei1Hash, ei2Hash); - Assert.Equal(ci1Hash, ci2Hash); - Assert.Equal(pai1Hash, pai2Hash); + [ActiveIssue("https://github.com/dotnet/runtime/issues/50978", TestRuntimes.Mono)] + [ConditionalFact(typeof(ReflectionCacheTests), nameof(IsMetadataUpdateAndRemoteExecutorSupported))] + public void GetMembers_MultipleCalls_ClearCache_All() + { + RemoteInvokeOptions options = new RemoteInvokeOptions(); + options.StartInfo.EnvironmentVariables.Add("DOTNET_MODIFIABLE_ASSEMBLIES", "debug"); + + using RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(() => + { + Action clearCache = GetClearCacheMethod(); + + MethodInfo mi1 = s_type.GetMethod(nameof(Method)); + PropertyInfo pi1 = s_type.GetProperty(nameof(Property)); + FieldInfo fi1 = s_type.GetField(nameof(Field1)); + EventInfo ei1 = s_type.GetEvent(nameof(Event1)); + ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); + ParameterInfo pai1 = mi1.GetParameters()[0]; + + AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); + + clearCache(null); + Assert.True(HotReloadDeltaApplied()); + MethodInfo mi2 = s_type.GetMethod(nameof(Method)); + PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); + FieldInfo fi2 = s_type.GetField(nameof(Field1)); + EventInfo ei2 = s_type.GetEvent(nameof(Event1)); + ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); + ParameterInfo pai2 = mi2.GetParameters()[0]; + + AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2, pai2); + + // After the Cache cleared the references of the same member of same type will be diffenet + // But they should be evaluated as Equal so that there were no issue using the same member after hot reload + AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, pai1, mi2, pi2, fi2, ei2, ci2, pai2); + + // And the HashCode of a member before and after hot reload should produce same result + AssertHashCodesAreEqual(mi1.GetHashCode(), pi1.GetHashCode(), fi1.GetHashCode(), ei1.GetHashCode(), ci1.GetHashCode(), pai1.GetHashCode(), + mi2.GetHashCode(), pi2.GetHashCode(), fi2.GetHashCode(), ei2.GetHashCode(), ci2.GetHashCode(), pai2.GetHashCode()); + }, options); } private static Action GetClearCacheMethod() From 71e176df6e46548f1e7cf5b786c1236de8b00042 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Mon, 1 Aug 2022 16:13:50 -0700 Subject: [PATCH 04/19] Renamed the propertyName in test --- .../tests/System/Reflection/ReflectionCacheTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs index 366ae2037fb7cc..5e330bbf5a2003 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs @@ -96,7 +96,7 @@ public void GetMembers_MultipleCalls_ClearCache_SpecificType() AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); clearCache(new[] { typeof(ReflectionCacheTests) }); - Assert.True(HotReloadDeltaApplied()); + Assert.True(CacheCleared()); MethodInfo mi2 = s_type.GetMethod(nameof(Method)); PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); @@ -177,7 +177,7 @@ public void GetMembers_MultipleCalls_ClearCache_All() AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); clearCache(null); - Assert.True(HotReloadDeltaApplied()); + Assert.True(CacheCleared()); MethodInfo mi2 = s_type.GetMethod(nameof(Method)); PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); FieldInfo fi2 = s_type.GetField(nameof(Field1)); @@ -205,12 +205,12 @@ private static Action GetClearCacheMethod() return clearCache.CreateDelegate>(); } - private static bool HotReloadDeltaApplied() + private static bool CacheCleared() { Type updateHandler = typeof(Type).Assembly.GetType("System.Reflection.Metadata.RuntimeTypeMetadataUpdateHandler", throwOnError: true, ignoreCase: false); - PropertyInfo hotReloadApplied = updateHandler.GetProperty("HotReloadDeltaApplied", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - Assert.NotNull(hotReloadApplied); - return (bool)hotReloadApplied.GetValue(null); + PropertyInfo metadataUpdaterSupportedAndCacheCleared = updateHandler.GetProperty("MetadataUpdaterSupportedAndCacheCleared", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + Assert.NotNull(metadataUpdaterSupportedAndCacheCleared); + return (bool)metadataUpdaterSupportedAndCacheCleared.GetValue(null); } } } From 1b0d414a969fdf5fee2384c42ef3c9c9fc5700b5 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Mon, 1 Aug 2022 18:08:55 -0700 Subject: [PATCH 05/19] Compare type instead of module, check MetadataUpdater.IsSupported in HashCode --- .../Metadata/RuntimeTypeMetadataUpdateHandler.cs | 2 +- .../Reflection/RuntimeConstructorInfo.CoreCLR.cs | 8 ++++---- .../src/System/Reflection/RuntimeEventInfo.cs | 8 ++++++-- .../src/System/Reflection/RuntimeFieldInfo.cs | 8 ++++++-- .../System/Reflection/RuntimeMethodInfo.CoreCLR.cs | 4 ++-- .../src/System/Reflection/RuntimeParameterInfo.cs | 11 ++++++----- .../src/System/Reflection/RuntimePropertyInfo.cs | 8 ++++++-- .../tests/System/Reflection/ReflectionCacheTests.cs | 2 +- 8 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs index 2a8d966d8895d5..5939df61811305 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs @@ -12,7 +12,7 @@ namespace System.Reflection.Metadata internal static class RuntimeTypeMetadataUpdateHandler { private static bool s_cacheCleared; - public static bool MetadataUpdaterSupportedAndCacheCleared => MetadataUpdater.IsSupported && s_cacheCleared; + public static bool UpdateSupportedAndCacheCleared => MetadataUpdater.IsSupported && s_cacheCleared; /// Clear type caches in response to an update notification. /// The specific types to be cleared, or null to clear everything. diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index 019f6f5ab2b838..f6e8984f26ebca 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -122,10 +122,10 @@ public override string ToString() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && - obj is RuntimeConstructorInfo m && - MetadataToken == m.MetadataToken && - RuntimeTypeHandle.GetModule(m_declaringType).Equals(RuntimeTypeHandle.GetModule(m.m_declaringType))); + (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && + obj is RuntimeConstructorInfo ci && + MetadataToken == ci.MetadataToken && + m_declaringType.Equals(ci.m_declaringType)); public override int GetHashCode() => m_handle.GetHashCode(); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index 1b663ebca81aab..e601b591701272 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -72,9 +72,13 @@ public override string ToString() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && CacheEquals(obj)); + (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && + obj is RuntimeEventInfo ei && + m_token == ei.m_token && + m_declaringType.Equals(ei.m_declaringType)); - public override int GetHashCode() => HashCode.Combine(m_token.GetHashCode(), RuntimeTypeHandle.GetModule(m_declaringType).GetHashCode()); + public override int GetHashCode() => MetadataUpdater.IsSupported ? + HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index 8c0b02b53b6118..cdffda4edf428b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -50,9 +50,13 @@ internal RuntimeType GetDeclaringTypeInternal() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && CacheEquals(obj)); + (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && + obj is RuntimeFieldInfo fi && + MetadataToken == fi.MetadataToken && + m_declaringType.Equals(fi.m_declaringType)); - public override int GetHashCode() => HashCode.Combine(MetadataToken.GetHashCode(), Module.GetHashCode()); + public override int GetHashCode() => MetadataUpdater.IsSupported ? + HashCode.Combine(MetadataToken.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); #endregion #region Object Overrides diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 57d5fcee12a2a6..b5d3c4c4ae5b68 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -209,10 +209,10 @@ public override bool Equals(object? obj) } return obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && + (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && obj is RuntimeMethodInfo m && m.MetadataToken == MetadataToken && - RuntimeTypeHandle.GetModule(m_declaringType).Equals(RuntimeTypeHandle.GetModule(m.m_declaringType))); + m_declaringType.Equals(m.m_declaringType)); } #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 042b7ad0ad8c33..8ce8a7315b2ebd 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -499,12 +499,13 @@ public override Type[] GetOptionalCustomModifiers() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && - obj is RuntimeParameterInfo m && - m_tkParamDef == m.m_tkParamDef && - GetRuntimeModule()!.Equals(m.GetRuntimeModule())); + (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && + obj is RuntimeParameterInfo pi && + m_tkParamDef == pi.m_tkParamDef && + DefiningMethod.DeclaringType!.Equals(pi.DefiningMethod.DeclaringType)); - public override int GetHashCode() => HashCode.Combine(m_tkParamDef.GetHashCode(), GetRuntimeModule()!.GetHashCode()); + public override int GetHashCode() => MetadataUpdater.IsSupported ? + HashCode.Combine(m_tkParamDef.GetHashCode(), DefiningMethod.DeclaringType!.GetHashCode()) : base.GetHashCode(); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 08203f03f42ca2..e103b118a7e4fb 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -183,9 +183,13 @@ public override IList GetCustomAttributesData() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.MetadataUpdaterSupportedAndCacheCleared && CacheEquals(obj)); + (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && + obj is RuntimePropertyInfo pi && + m_token == pi.m_token && + m_declaringType.Equals(pi.m_declaringType)); - public override int GetHashCode() => HashCode.Combine(m_token.GetHashCode(), Module.GetHashCode()); + public override int GetHashCode() => MetadataUpdater.IsSupported ? + HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); #endregion #region PropertyInfo Overrides diff --git a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs index 5e330bbf5a2003..817adf7e901b08 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs @@ -208,7 +208,7 @@ private static Action GetClearCacheMethod() private static bool CacheCleared() { Type updateHandler = typeof(Type).Assembly.GetType("System.Reflection.Metadata.RuntimeTypeMetadataUpdateHandler", throwOnError: true, ignoreCase: false); - PropertyInfo metadataUpdaterSupportedAndCacheCleared = updateHandler.GetProperty("MetadataUpdaterSupportedAndCacheCleared", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + PropertyInfo metadataUpdaterSupportedAndCacheCleared = updateHandler.GetProperty("UpdateSupportedAndCacheCleared", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); Assert.NotNull(metadataUpdaterSupportedAndCacheCleared); return (bool)metadataUpdaterSupportedAndCacheCleared.GetValue(null); } From 621d6f705a3315dbb58645e1259feba94eeb88f2 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Mon, 1 Aug 2022 18:16:59 -0700 Subject: [PATCH 06/19] Update and use CacheEquals --- .../src/System/Reflection/MdFieldInfo.cs | 3 +-- .../src/System/Reflection/RuntimeEventInfo.cs | 8 ++------ .../src/System/Reflection/RuntimeFieldInfo.cs | 5 +---- .../src/System/Reflection/RuntimePropertyInfo.cs | 8 ++------ 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs index fcc1845bdf90a6..48d65316398348 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs @@ -33,8 +33,7 @@ internal override bool CacheEquals(object? o) return o is MdFieldInfo m && m.m_tkField == m_tkField && - m_declaringType.TypeHandle.GetModuleHandle().Equals( - m.m_declaringType.TypeHandle.GetModuleHandle()); + m_declaringType.Equals(m.m_declaringType); } #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index e601b591701272..5c9fc1c88e2e7a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -54,8 +54,7 @@ internal override bool CacheEquals(object? o) return o is RuntimeEventInfo m && m.m_token == m_token && - RuntimeTypeHandle.GetModule(m_declaringType).Equals( - RuntimeTypeHandle.GetModule(m.m_declaringType)); + m_declaringType.Equals(m.m_declaringType); } internal BindingFlags BindingFlags => m_bindingFlags; @@ -72,10 +71,7 @@ public override string ToString() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && - obj is RuntimeEventInfo ei && - m_token == ei.m_token && - m_declaringType.Equals(ei.m_declaringType)); + (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index cdffda4edf428b..fe597fbbdb9cfb 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -50,10 +50,7 @@ internal RuntimeType GetDeclaringTypeInternal() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && - obj is RuntimeFieldInfo fi && - MetadataToken == fi.MetadataToken && - m_declaringType.Equals(fi.m_declaringType)); + (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? HashCode.Combine(MetadataToken.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index e103b118a7e4fb..2589b254b10ed8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -56,8 +56,7 @@ internal override bool CacheEquals(object? o) return o is RuntimePropertyInfo m && m.m_token == m_token && - RuntimeTypeHandle.GetModule(m_declaringType).Equals( - RuntimeTypeHandle.GetModule(m.m_declaringType)); + m_declaringType.Equals(m.m_declaringType); } internal Signature Signature @@ -183,10 +182,7 @@ public override IList GetCustomAttributesData() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && - obj is RuntimePropertyInfo pi && - m_token == pi.m_token && - m_declaringType.Equals(pi.m_declaringType)); + (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); From 97bde09add5cc5713d11d2a0169921d127f7eaee Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Tue, 2 Aug 2022 10:12:27 -0700 Subject: [PATCH 07/19] Apply feedbacks --- .../Metadata/RuntimeTypeMetadataUpdateHandler.cs | 5 ----- .../Reflection/RuntimeConstructorInfo.CoreCLR.cs | 4 ++-- .../src/System/Reflection/RuntimeEventInfo.cs | 2 +- .../src/System/Reflection/RuntimeFieldInfo.cs | 2 +- .../Reflection/RuntimeMethodInfo.CoreCLR.cs | 11 ++--------- .../System/Reflection/RuntimeParameterInfo.cs | 2 +- .../src/System/Reflection/RuntimePropertyInfo.cs | 2 +- .../System/Reflection/ReflectionCacheTests.cs | 16 +++------------- 8 files changed, 11 insertions(+), 33 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs index 5939df61811305..e45e84efb60f01 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/RuntimeTypeMetadataUpdateHandler.cs @@ -11,16 +11,11 @@ namespace System.Reflection.Metadata /// Metadata update handler used to clear a Type's reflection cache in response to a metadata update notification. internal static class RuntimeTypeMetadataUpdateHandler { - private static bool s_cacheCleared; - public static bool UpdateSupportedAndCacheCleared => MetadataUpdater.IsSupported && s_cacheCleared; - /// Clear type caches in response to an update notification. /// The specific types to be cleared, or null to clear everything. [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Clearing the caches on a Type isn't affected if a Type is trimmed, or has any of its members trimmed.")] public static void ClearCache(Type[]? types) { - s_cacheCleared = true; - if (RequiresClearingAllTypes(types)) { // TODO: This should ideally be in a QCall in the runtime. As written here: diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index f6e8984f26ebca..c11025b681a27d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -122,12 +122,12 @@ public override string ToString() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && + (MetadataUpdater.IsSupported && obj is RuntimeConstructorInfo ci && MetadataToken == ci.MetadataToken && m_declaringType.Equals(ci.m_declaringType)); - public override int GetHashCode() => m_handle.GetHashCode(); + public override int GetHashCode() => ValueType.GetHashCodeOfPtr(m_handle); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index 5c9fc1c88e2e7a..8ff37c39861e38 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -71,7 +71,7 @@ public override string ToString() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && CacheEquals(obj)); + (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index fe597fbbdb9cfb..5d76d5002eafae 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -50,7 +50,7 @@ internal RuntimeType GetDeclaringTypeInternal() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && CacheEquals(obj)); + (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? HashCode.Combine(MetadataToken.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index b5d3c4c4ae5b68..9f065911b2d689 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -158,14 +158,7 @@ public override string ToString() return m_toString; } - public override int GetHashCode() - { - // See RuntimeMethodInfo.Equals() below. - if (IsGenericMethod) - return ValueType.GetHashCodeOfPtr(m_handle); - else - return m_handle.GetHashCode(); - } + public override int GetHashCode() => ValueType.GetHashCodeOfPtr(m_handle); public override bool Equals(object? obj) { @@ -209,7 +202,7 @@ public override bool Equals(object? obj) } return obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && + (MetadataUpdater.IsSupported && obj is RuntimeMethodInfo m && m.MetadataToken == MetadataToken && m_declaringType.Equals(m.m_declaringType)); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 8ce8a7315b2ebd..56c287b8793ae2 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -499,7 +499,7 @@ public override Type[] GetOptionalCustomModifiers() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && + (MetadataUpdater.IsSupported && obj is RuntimeParameterInfo pi && m_tkParamDef == pi.m_tkParamDef && DefiningMethod.DeclaringType!.Equals(pi.DefiningMethod.DeclaringType)); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 2589b254b10ed8..61f1fcee887f4d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -182,7 +182,7 @@ public override IList GetCustomAttributesData() public override bool Equals(object? obj) => obj == (object)this || - (RuntimeTypeMetadataUpdateHandler.UpdateSupportedAndCacheCleared && CacheEquals(obj)); + (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); diff --git a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs index 817adf7e901b08..8aedc87db99785 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs @@ -13,7 +13,6 @@ public class ReflectionCacheTests private static bool IsMetadataUpdateAndRemoteExecutorSupported => PlatformDetection.IsMetadataUpdateSupported && RemoteExecutor.IsSupported; private static readonly Type s_type = typeof(ReflectionCacheTests); - //private BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; public string Property { get; set; } @@ -96,7 +95,6 @@ public void GetMembers_MultipleCalls_ClearCache_SpecificType() AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); clearCache(new[] { typeof(ReflectionCacheTests) }); - Assert.True(CacheCleared()); MethodInfo mi2 = s_type.GetMethod(nameof(Method)); PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); @@ -107,7 +105,7 @@ public void GetMembers_MultipleCalls_ClearCache_SpecificType() AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2, pai2); - // After the Cache cleared the references of the same member of same type will be diffenet + // After the Cache cleared the references of the same members of the same type will be different // But they should be evaluated as Equal so that there were no issue using the same member after hot reload AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, pai1, mi2, pi2, fi2, ei2, ci2, pai2); @@ -177,7 +175,7 @@ public void GetMembers_MultipleCalls_ClearCache_All() AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); clearCache(null); - Assert.True(CacheCleared()); + MethodInfo mi2 = s_type.GetMethod(nameof(Method)); PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); FieldInfo fi2 = s_type.GetField(nameof(Field1)); @@ -187,7 +185,7 @@ public void GetMembers_MultipleCalls_ClearCache_All() AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2, pai2); - // After the Cache cleared the references of the same member of same type will be diffenet + // After the Cache cleared the references of the same members of the same type will be different // But they should be evaluated as Equal so that there were no issue using the same member after hot reload AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, pai1, mi2, pi2, fi2, ei2, ci2, pai2); @@ -204,13 +202,5 @@ private static Action GetClearCacheMethod() Assert.NotNull(clearCache); return clearCache.CreateDelegate>(); } - - private static bool CacheCleared() - { - Type updateHandler = typeof(Type).Assembly.GetType("System.Reflection.Metadata.RuntimeTypeMetadataUpdateHandler", throwOnError: true, ignoreCase: false); - PropertyInfo metadataUpdaterSupportedAndCacheCleared = updateHandler.GetProperty("UpdateSupportedAndCacheCleared", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - Assert.NotNull(metadataUpdaterSupportedAndCacheCleared); - return (bool)metadataUpdaterSupportedAndCacheCleared.GetValue(null); - } } } From 11355a40c60a98fbb7690fab9fa7e456c41389ae Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Tue, 2 Aug 2022 10:33:00 -0700 Subject: [PATCH 08/19] Use ReferenceEquals --- .../src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs | 2 +- .../src/System/Reflection/RuntimeEventInfo.cs | 2 +- .../src/System/Reflection/RuntimeFieldInfo.cs | 2 +- .../src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs | 4 ++-- .../src/System/Reflection/RuntimeParameterInfo.cs | 2 +- .../src/System/Reflection/RuntimePropertyInfo.cs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index c11025b681a27d..75eb10e4ea605a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -121,7 +121,7 @@ public override string ToString() } public override bool Equals(object? obj) => - obj == (object)this || + object.ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && obj is RuntimeConstructorInfo ci && MetadataToken == ci.MetadataToken && diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index 8ff37c39861e38..aad2edea77da28 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -70,7 +70,7 @@ public override string ToString() } public override bool Equals(object? obj) => - obj == (object)this || + object.ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index 5d76d5002eafae..852c5d367db9d0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -49,7 +49,7 @@ internal RuntimeType GetDeclaringTypeInternal() public override bool IsCollectible => m_declaringType.IsCollectible; public override bool Equals(object? obj) => - obj == (object)this || + object.ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 9f065911b2d689..2e8e9eea4543cd 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -201,8 +201,8 @@ public override bool Equals(object? obj) return true; } - return obj == (object)this || - (MetadataUpdater.IsSupported && + return object.ReferenceEquals(this, obj) || + (MetadataUpdater.IsSupported && obj is RuntimeMethodInfo m && m.MetadataToken == MetadataToken && m_declaringType.Equals(m.m_declaringType)); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 56c287b8793ae2..68637d4c9c1156 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -498,7 +498,7 @@ public override Type[] GetOptionalCustomModifiers() } public override bool Equals(object? obj) => - obj == (object)this || + object.ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && obj is RuntimeParameterInfo pi && m_tkParamDef == pi.m_tkParamDef && diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 61f1fcee887f4d..1b3d145305c3ba 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -181,7 +181,7 @@ public override IList GetCustomAttributesData() public override bool IsCollectible => m_declaringType.IsCollectible; public override bool Equals(object? obj) => - obj == (object)this || + object.ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? From 9d30a9510f76884a3543428ad43af275992f24b2 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Tue, 2 Aug 2022 14:41:10 -0700 Subject: [PATCH 09/19] apply more feedback --- .../src/System/Reflection/MdFieldInfo.cs | 2 +- .../RuntimeConstructorInfo.CoreCLR.cs | 6 +-- .../src/System/Reflection/RuntimeEventInfo.cs | 4 +- .../src/System/Reflection/RuntimeFieldInfo.cs | 2 +- .../Reflection/RuntimeMethodInfo.CoreCLR.cs | 46 +------------------ .../System/Reflection/RuntimeParameterInfo.cs | 6 +-- .../System/Reflection/RuntimePropertyInfo.cs | 4 +- 7 files changed, 11 insertions(+), 59 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs index 48d65316398348..ef97899581195d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs @@ -33,7 +33,7 @@ internal override bool CacheEquals(object? o) return o is MdFieldInfo m && m.m_tkField == m_tkField && - m_declaringType.Equals(m.m_declaringType); + ReferenceEquals(m_declaringType, m.m_declaringType); } #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index 29ffa38db24783..b9145526273a2c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -121,11 +121,7 @@ public override string ToString() } public override bool Equals(object? obj) => - object.ReferenceEquals(this, obj) || - (MetadataUpdater.IsSupported && - obj is RuntimeConstructorInfo ci && - MetadataToken == ci.MetadataToken && - m_declaringType.Equals(ci.m_declaringType)); + obj is RuntimeConstructorInfo ci && m_handle == ci.m_handle; public override int GetHashCode() => RuntimeHelpers.GetHashCodeOfPtr(m_handle); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index aad2edea77da28..97b1ceecb8c6c9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -54,7 +54,7 @@ internal override bool CacheEquals(object? o) return o is RuntimeEventInfo m && m.m_token == m_token && - m_declaringType.Equals(m.m_declaringType); + ReferenceEquals(m_declaringType, m.m_declaringType); } internal BindingFlags BindingFlags => m_bindingFlags; @@ -70,7 +70,7 @@ public override string ToString() } public override bool Equals(object? obj) => - object.ReferenceEquals(this, obj) || + ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index 852c5d367db9d0..dff871114a52d0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -49,7 +49,7 @@ internal RuntimeType GetDeclaringTypeInternal() public override bool IsCollectible => m_declaringType.IsCollectible; public override bool Equals(object? obj) => - object.ReferenceEquals(this, obj) || + ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 3850ad7ea76cf0..212ecc62f8f602 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -162,51 +162,7 @@ public override string ToString() public override bool Equals(object? obj) { - if (IsGenericMethod) - { - // We cannot do simple object identity comparisons for generic methods. - // Equals will be called in CerHashTable when RuntimeType+RuntimeTypeCache.GetGenericMethodInfo() - // retrieve items from and insert items into s_methodInstantiations which is a CerHashtable. - - RuntimeMethodInfo? mi = obj as RuntimeMethodInfo; - - if (mi == null || !mi.IsGenericMethod) - return false; - - // now we know that both operands are generic methods - - IRuntimeMethodInfo handle1 = RuntimeMethodHandle.StripMethodInstantiation(this); - IRuntimeMethodInfo handle2 = RuntimeMethodHandle.StripMethodInstantiation(mi); - if (handle1.Value.Value != handle2.Value.Value) - return false; - - Type[] lhs = GetGenericArguments(); - Type[] rhs = mi.GetGenericArguments(); - - if (lhs.Length != rhs.Length) - return false; - - for (int i = 0; i < lhs.Length; i++) - { - if (lhs[i] != rhs[i]) - return false; - } - - if (DeclaringType != mi.DeclaringType) - return false; - - if (ReflectedType != mi.ReflectedType) - return false; - - return true; - } - - return object.ReferenceEquals(this, obj) || - (MetadataUpdater.IsSupported && - obj is RuntimeMethodInfo m && - m.MetadataToken == MetadataToken && - m_declaringType.Equals(m.m_declaringType)); - + return obj is RuntimeMethodInfo m && m_handle == m.m_handle; } #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 68637d4c9c1156..b5a4a5c7c2f4f3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -498,14 +498,14 @@ public override Type[] GetOptionalCustomModifiers() } public override bool Equals(object? obj) => - object.ReferenceEquals(this, obj) || + ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && obj is RuntimeParameterInfo pi && m_tkParamDef == pi.m_tkParamDef && - DefiningMethod.DeclaringType!.Equals(pi.DefiningMethod.DeclaringType)); + ReferenceEquals(DefiningMethod.DeclaringType, pi.DefiningMethod.DeclaringType)); public override int GetHashCode() => MetadataUpdater.IsSupported ? - HashCode.Combine(m_tkParamDef.GetHashCode(), DefiningMethod.DeclaringType!.GetHashCode()) : base.GetHashCode(); + HashCode.Combine(m_tkParamDef.GetHashCode(), DefiningMethod.DeclaringType?.GetHashCode()) : base.GetHashCode(); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 1b3d145305c3ba..80f41a77e2cb6d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -56,7 +56,7 @@ internal override bool CacheEquals(object? o) return o is RuntimePropertyInfo m && m.m_token == m_token && - m_declaringType.Equals(m.m_declaringType); + ReferenceEquals(m_declaringType, m.m_declaringType); } internal Signature Signature @@ -181,7 +181,7 @@ public override IList GetCustomAttributesData() public override bool IsCollectible => m_declaringType.IsCollectible; public override bool Equals(object? obj) => - object.ReferenceEquals(this, obj) || + ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => MetadataUpdater.IsSupported ? From 74c8563c8c2a3c8dece18d0e0f477785d494a4a8 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Tue, 2 Aug 2022 16:46:54 -0700 Subject: [PATCH 10/19] Exclude RuntimeParameterInfo --- .../System/Reflection/RuntimeParameterInfo.cs | 9 ---- .../System/Reflection/ReflectionCacheTests.cs | 48 +++++++------------ 2 files changed, 18 insertions(+), 39 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index b5a4a5c7c2f4f3..3989276a64f425 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -497,15 +497,6 @@ public override Type[] GetOptionalCustomModifiers() m_signature.GetCustomModifiers(PositionImpl + 1, false); } - public override bool Equals(object? obj) => - ReferenceEquals(this, obj) || - (MetadataUpdater.IsSupported && - obj is RuntimeParameterInfo pi && - m_tkParamDef == pi.m_tkParamDef && - ReferenceEquals(DefiningMethod.DeclaringType, pi.DefiningMethod.DeclaringType)); - - public override int GetHashCode() => MetadataUpdater.IsSupported ? - HashCode.Combine(m_tkParamDef.GetHashCode(), DefiningMethod.DeclaringType?.GetHashCode()) : base.GetHashCode(); #endregion #region ICustomAttributeProvider diff --git a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs index 8aedc87db99785..93ce44732c1bf4 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs @@ -35,32 +35,28 @@ public void GetMembers_MultipleCalls_SameObjects() FieldInfo fi1 = s_type.GetField(nameof(Field1)); EventInfo ei1 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); - ParameterInfo pai1 = mi1.GetParameters()[0]; - AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); + AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1); MethodInfo mi2 = s_type.GetMethod(nameof(Method)); PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); FieldInfo fi2 = s_type.GetField(nameof(Field1)); EventInfo ei2 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); - ParameterInfo pai2 = mi2.GetParameters()[0]; - AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2, pai2); + AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2); Assert.Same(mi1, mi2); Assert.Same(pi1, pi2); Assert.Same(fi1, fi2); Assert.Same(ei1, ei2); Assert.Same(ci1, ci2); - Assert.Same(pai1, pai2); Assert.Equal(mi1, mi2); Assert.Equal(pi1, pi2); Assert.Equal(fi1, fi2); Assert.Equal(ei1, ei2); Assert.Equal(ci1, ci2); - Assert.Equal(pai1, pai2); } [ActiveIssue("https://github.com/dotnet/runtime/issues/50978", TestRuntimes.Mono)] @@ -90,9 +86,8 @@ public void GetMembers_MultipleCalls_ClearCache_SpecificType() FieldInfo fi1 = s_type.GetField(nameof(Field1)); EventInfo ei1 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); - ParameterInfo pai1 = mi1.GetParameters()[0]; - AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); + AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1); clearCache(new[] { typeof(ReflectionCacheTests) }); @@ -101,57 +96,52 @@ public void GetMembers_MultipleCalls_ClearCache_SpecificType() FieldInfo fi2 = s_type.GetField(nameof(Field1)); EventInfo ei2 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); - ParameterInfo pai2 = mi2.GetParameters()[0]; - AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2, pai2); + AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2); // After the Cache cleared the references of the same members of the same type will be different // But they should be evaluated as Equal so that there were no issue using the same member after hot reload - AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, pai1, mi2, pi2, fi2, ei2, ci2, pai2); + AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, mi2, pi2, fi2, ei2, ci2); // And the HashCode of a member before and after hot reload should produce same result - AssertHashCodesAreEqual(mi1.GetHashCode(), pi1.GetHashCode(), fi1.GetHashCode(), ei1.GetHashCode(), ci1.GetHashCode(), pai1.GetHashCode(), - mi2.GetHashCode(), pi2.GetHashCode(), fi2.GetHashCode(), ei2.GetHashCode(), ci2.GetHashCode(), pai2.GetHashCode()); + AssertHashCodesAreEqual(mi1.GetHashCode(), pi1.GetHashCode(), fi1.GetHashCode(), ei1.GetHashCode(), ci1.GetHashCode(), + mi2.GetHashCode(), pi2.GetHashCode(), fi2.GetHashCode(), ei2.GetHashCode(), ci2.GetHashCode()); }, options); } - private static void AssertMembersAreNotNull(MethodInfo mi, PropertyInfo pi, FieldInfo fi, EventInfo ei, ConstructorInfo ci, ParameterInfo pai) + private static void AssertMembersAreNotNull(MethodInfo mi, PropertyInfo pi, FieldInfo fi, EventInfo ei, ConstructorInfo ci) { Assert.NotNull(mi); Assert.NotNull(pi); Assert.NotNull(fi); Assert.NotNull(ei); Assert.NotNull(ci); - Assert.NotNull(pai); } - private static void AssertHashCodesAreEqual(int mi1Hash, int pi1Hash, int fi1Hash, int ei1Hash, int ci1Hash, int pai1Hash, - int mi2Hash, int pi2Hash, int fi2Hash, int ei2Hash, int ci2Hash, int pai2Hash) + private static void AssertHashCodesAreEqual(int mi1Hash, int pi1Hash, int fi1Hash, int ei1Hash, int ci1Hash, + int mi2Hash, int pi2Hash, int fi2Hash, int ei2Hash, int ci2Hash) { Assert.Equal(mi1Hash, mi2Hash); Assert.Equal(pi1Hash, pi2Hash); Assert.Equal(fi1Hash, fi2Hash); Assert.Equal(ei1Hash, ei2Hash); Assert.Equal(ci1Hash, ci2Hash); - Assert.Equal(pai1Hash, pai2Hash); } - private static void AssertMemberReferencesNotSameButEqual(MethodInfo mi1, PropertyInfo pi1, FieldInfo fi1, EventInfo ei1, ConstructorInfo ci1, ParameterInfo pai1, - MethodInfo mi2, PropertyInfo pi2, FieldInfo fi2, EventInfo ei2, ConstructorInfo ci2, ParameterInfo pai2) + private static void AssertMemberReferencesNotSameButEqual(MethodInfo mi1, PropertyInfo pi1, FieldInfo fi1, EventInfo ei1, ConstructorInfo ci1, + MethodInfo mi2, PropertyInfo pi2, FieldInfo fi2, EventInfo ei2, ConstructorInfo ci2) { Assert.NotSame(mi1, mi2); Assert.NotSame(pi1, pi2); Assert.NotSame(fi1, fi2); Assert.NotSame(ei1, ei2); - Assert.NotSame(ci1, ci2); - Assert.NotSame(pai1, pai2); + Assert.NotSame(ci1, ci2);; Assert.Equal(mi1, mi2); Assert.Equal(pi1, pi2); Assert.Equal(fi1, fi2); Assert.Equal(ei1, ei2); Assert.Equal(ci1, ci2); - Assert.Equal(pai1, pai2); } [ActiveIssue("https://github.com/dotnet/runtime/issues/50978", TestRuntimes.Mono)] @@ -170,9 +160,8 @@ public void GetMembers_MultipleCalls_ClearCache_All() FieldInfo fi1 = s_type.GetField(nameof(Field1)); EventInfo ei1 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); - ParameterInfo pai1 = mi1.GetParameters()[0]; - AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1, pai1); + AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1); clearCache(null); @@ -181,17 +170,16 @@ public void GetMembers_MultipleCalls_ClearCache_All() FieldInfo fi2 = s_type.GetField(nameof(Field1)); EventInfo ei2 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); - ParameterInfo pai2 = mi2.GetParameters()[0]; - AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2, pai2); + AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2); // After the Cache cleared the references of the same members of the same type will be different // But they should be evaluated as Equal so that there were no issue using the same member after hot reload - AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, pai1, mi2, pi2, fi2, ei2, ci2, pai2); + AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, mi2, pi2, fi2, ei2, ci2); // And the HashCode of a member before and after hot reload should produce same result - AssertHashCodesAreEqual(mi1.GetHashCode(), pi1.GetHashCode(), fi1.GetHashCode(), ei1.GetHashCode(), ci1.GetHashCode(), pai1.GetHashCode(), - mi2.GetHashCode(), pi2.GetHashCode(), fi2.GetHashCode(), ei2.GetHashCode(), ci2.GetHashCode(), pai2.GetHashCode()); + AssertHashCodesAreEqual(mi1.GetHashCode(), pi1.GetHashCode(), fi1.GetHashCode(), ei1.GetHashCode(), ci1.GetHashCode(), + mi2.GetHashCode(), pi2.GetHashCode(), fi2.GetHashCode(), ei2.GetHashCode(), ci2.GetHashCode()); }, options); } From 8ee9566312ebee7438e2dc8c2ff6192240dec941 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Tue, 2 Aug 2022 19:01:20 -0700 Subject: [PATCH 11/19] Update assert methods in test --- .../System/Reflection/RuntimeParameterInfo.cs | 1 - .../System/Reflection/ReflectionCacheTests.cs | 104 ++++++------------ 2 files changed, 35 insertions(+), 70 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 3989276a64f425..434a821715caf8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Reflection.Metadata; using System.Runtime.CompilerServices; using MdToken = System.Reflection.MetadataToken; diff --git a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs index 93ce44732c1bf4..40ce236003222a 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/ReflectionCacheTests.cs @@ -36,27 +36,27 @@ public void GetMembers_MultipleCalls_SameObjects() EventInfo ei1 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); - AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1); - MethodInfo mi2 = s_type.GetMethod(nameof(Method)); PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); FieldInfo fi2 = s_type.GetField(nameof(Field1)); EventInfo ei2 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); - AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2); - - Assert.Same(mi1, mi2); - Assert.Same(pi1, pi2); - Assert.Same(fi1, fi2); - Assert.Same(ei1, ei2); - Assert.Same(ci1, ci2); + AssertSameEqualAndHashCodeEqual(mi1, mi2); + AssertSameEqualAndHashCodeEqual(pi1, pi2); + AssertSameEqualAndHashCodeEqual(fi1, fi2); + AssertSameEqualAndHashCodeEqual(ei1, ei2); + AssertSameEqualAndHashCodeEqual(ci1, ci2); + } - Assert.Equal(mi1, mi2); - Assert.Equal(pi1, pi2); - Assert.Equal(fi1, fi2); - Assert.Equal(ei1, ei2); - Assert.Equal(ci1, ci2); + void AssertSameEqualAndHashCodeEqual(object o1, object o2) + { + // When cache not cleared the references of the same members are Same and Equal, and Hashcodes Equal. + Assert.NotNull(o1); + Assert.NotNull(o2); + Assert.Same(o1, o2); + Assert.Equal(o1, o2); + Assert.Equal(o1.GetHashCode(), o2.GetHashCode()); } [ActiveIssue("https://github.com/dotnet/runtime/issues/50978", TestRuntimes.Mono)] @@ -72,7 +72,7 @@ public void InvokeClearCache_NoExceptions() [ActiveIssue("https://github.com/dotnet/runtime/issues/50978", TestRuntimes.Mono)] [ConditionalFact(typeof(ReflectionCacheTests), nameof(IsMetadataUpdateAndRemoteExecutorSupported))] - public void GetMembers_MultipleCalls_ClearCache_SpecificType() + public void GetMembers_MultipleCalls_ClearCache_ReflectionCacheTestsType() { RemoteInvokeOptions options = new RemoteInvokeOptions(); options.StartInfo.EnvironmentVariables.Add("DOTNET_MODIFIABLE_ASSEMBLIES", "debug"); @@ -87,8 +87,6 @@ public void GetMembers_MultipleCalls_ClearCache_SpecificType() EventInfo ei1 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); - AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1); - clearCache(new[] { typeof(ReflectionCacheTests) }); MethodInfo mi2 = s_type.GetMethod(nameof(Method)); @@ -97,51 +95,25 @@ public void GetMembers_MultipleCalls_ClearCache_SpecificType() EventInfo ei2 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); - AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2); - - // After the Cache cleared the references of the same members of the same type will be different - // But they should be evaluated as Equal so that there were no issue using the same member after hot reload - AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, mi2, pi2, fi2, ei2, ci2); - - // And the HashCode of a member before and after hot reload should produce same result - AssertHashCodesAreEqual(mi1.GetHashCode(), pi1.GetHashCode(), fi1.GetHashCode(), ei1.GetHashCode(), ci1.GetHashCode(), - mi2.GetHashCode(), pi2.GetHashCode(), fi2.GetHashCode(), ei2.GetHashCode(), ci2.GetHashCode()); + AssertNotSameSameButEqualAndHashCodeEqual(mi1, mi2); + AssertNotSameSameButEqualAndHashCodeEqual(pi1, pi2); + AssertNotSameSameButEqualAndHashCodeEqual(fi1, fi2); + AssertNotSameSameButEqualAndHashCodeEqual(ci1, ci2); + AssertNotSameSameButEqualAndHashCodeEqual(ei1, ei2); }, options); } - private static void AssertMembersAreNotNull(MethodInfo mi, PropertyInfo pi, FieldInfo fi, EventInfo ei, ConstructorInfo ci) - { - Assert.NotNull(mi); - Assert.NotNull(pi); - Assert.NotNull(fi); - Assert.NotNull(ei); - Assert.NotNull(ci); - } - - private static void AssertHashCodesAreEqual(int mi1Hash, int pi1Hash, int fi1Hash, int ei1Hash, int ci1Hash, - int mi2Hash, int pi2Hash, int fi2Hash, int ei2Hash, int ci2Hash) - { - Assert.Equal(mi1Hash, mi2Hash); - Assert.Equal(pi1Hash, pi2Hash); - Assert.Equal(fi1Hash, fi2Hash); - Assert.Equal(ei1Hash, ei2Hash); - Assert.Equal(ci1Hash, ci2Hash); - } - - private static void AssertMemberReferencesNotSameButEqual(MethodInfo mi1, PropertyInfo pi1, FieldInfo fi1, EventInfo ei1, ConstructorInfo ci1, - MethodInfo mi2, PropertyInfo pi2, FieldInfo fi2, EventInfo ei2, ConstructorInfo ci2) + private static void AssertNotSameSameButEqualAndHashCodeEqual(object o1, object o2) { - Assert.NotSame(mi1, mi2); - Assert.NotSame(pi1, pi2); - Assert.NotSame(fi1, fi2); - Assert.NotSame(ei1, ei2); - Assert.NotSame(ci1, ci2);; - - Assert.Equal(mi1, mi2); - Assert.Equal(pi1, pi2); - Assert.Equal(fi1, fi2); - Assert.Equal(ei1, ei2); - Assert.Equal(ci1, ci2); + // After the cache cleared the references of the same members will be Not Same. + // But they should be evaluated as Equal so that there were no issue using the same member after hot reload. + // And the member HashCode before and after hot reload should produce the same result. + + Assert.NotNull(o1); + Assert.NotNull(o2); + Assert.NotSame(o1, o2); + Assert.Equal(o1, o2); + Assert.Equal(o1.GetHashCode(), o2.GetHashCode()); } [ActiveIssue("https://github.com/dotnet/runtime/issues/50978", TestRuntimes.Mono)] @@ -161,8 +133,6 @@ public void GetMembers_MultipleCalls_ClearCache_All() EventInfo ei1 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); - AssertMembersAreNotNull(mi1, pi1, fi1, ei1, ci1); - clearCache(null); MethodInfo mi2 = s_type.GetMethod(nameof(Method)); @@ -171,15 +141,11 @@ public void GetMembers_MultipleCalls_ClearCache_All() EventInfo ei2 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); - AssertMembersAreNotNull(mi2, pi2, fi2, ei2, ci2); - - // After the Cache cleared the references of the same members of the same type will be different - // But they should be evaluated as Equal so that there were no issue using the same member after hot reload - AssertMemberReferencesNotSameButEqual(mi1, pi1, fi1, ei1, ci1, mi2, pi2, fi2, ei2, ci2); - - // And the HashCode of a member before and after hot reload should produce same result - AssertHashCodesAreEqual(mi1.GetHashCode(), pi1.GetHashCode(), fi1.GetHashCode(), ei1.GetHashCode(), ci1.GetHashCode(), - mi2.GetHashCode(), pi2.GetHashCode(), fi2.GetHashCode(), ei2.GetHashCode(), ci2.GetHashCode()); + AssertNotSameSameButEqualAndHashCodeEqual(mi1, mi2); + AssertNotSameSameButEqualAndHashCodeEqual(pi1, pi2); + AssertNotSameSameButEqualAndHashCodeEqual(fi1, fi2); + AssertNotSameSameButEqualAndHashCodeEqual(ci1, ci2); + AssertNotSameSameButEqualAndHashCodeEqual(ei1, ei2); }, options); } From d4d961c81db83df4e9631c02782791baef4c6eea Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Wed, 3 Aug 2022 16:35:29 -0700 Subject: [PATCH 12/19] Update RMethodInfo RConstructorInfo Equals override to fix CI test failures --- .../Reflection/RuntimeConstructorInfo.CoreCLR.cs | 6 +++++- .../src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs | 10 ++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index b9145526273a2c..8815eeca439826 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -121,7 +121,11 @@ public override string ToString() } public override bool Equals(object? obj) => - obj is RuntimeConstructorInfo ci && m_handle == ci.m_handle; + ReferenceEquals(this, obj) || + (MetadataUpdater.IsSupported && + obj is RuntimeConstructorInfo ci && + MetadataToken == ci.MetadataToken && + m_declaringType.Equals(ci.m_declaringType)); public override int GetHashCode() => RuntimeHelpers.GetHashCodeOfPtr(m_handle); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 212ecc62f8f602..4f643dd827b78a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -160,10 +160,12 @@ public override string ToString() public override int GetHashCode() => RuntimeHelpers.GetHashCodeOfPtr(m_handle); - public override bool Equals(object? obj) - { - return obj is RuntimeMethodInfo m && m_handle == m.m_handle; - } + public override bool Equals(object? obj) => + ReferenceEquals(this, obj) || + (MetadataUpdater.IsSupported && + obj is RuntimeMethodInfo m && + m.MetadataToken == MetadataToken && + m_declaringType.Equals(m.m_declaringType)); #endregion #region ICustomAttributeProvider From b9dc38895fc6a6cda7d587626ea0df4382c51476 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 4 Aug 2022 13:26:28 -0700 Subject: [PATCH 13/19] Revert "Update RMethodInfo RConstructorInfo Equals override to fix CI test failures" This reverts commit d4d961c81db83df4e9631c02782791baef4c6eea. --- .../Reflection/RuntimeConstructorInfo.CoreCLR.cs | 6 +----- .../src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs | 10 ++++------ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index 8815eeca439826..b9145526273a2c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -121,11 +121,7 @@ public override string ToString() } public override bool Equals(object? obj) => - ReferenceEquals(this, obj) || - (MetadataUpdater.IsSupported && - obj is RuntimeConstructorInfo ci && - MetadataToken == ci.MetadataToken && - m_declaringType.Equals(ci.m_declaringType)); + obj is RuntimeConstructorInfo ci && m_handle == ci.m_handle; public override int GetHashCode() => RuntimeHelpers.GetHashCodeOfPtr(m_handle); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 4f643dd827b78a..212ecc62f8f602 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -160,12 +160,10 @@ public override string ToString() public override int GetHashCode() => RuntimeHelpers.GetHashCodeOfPtr(m_handle); - public override bool Equals(object? obj) => - ReferenceEquals(this, obj) || - (MetadataUpdater.IsSupported && - obj is RuntimeMethodInfo m && - m.MetadataToken == MetadataToken && - m_declaringType.Equals(m.m_declaringType)); + public override bool Equals(object? obj) + { + return obj is RuntimeMethodInfo m && m_handle == m.m_handle; + } #endregion #region ICustomAttributeProvider From ea07c6f7baab87bd9dbe4f7e138549802e291717 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 4 Aug 2022 14:13:46 -0700 Subject: [PATCH 14/19] Fix tests --- .../src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 212ecc62f8f602..a7aabf10472d65 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -158,12 +158,12 @@ public override string ToString() return m_toString; } - public override int GetHashCode() => RuntimeHelpers.GetHashCodeOfPtr(m_handle); + public override int GetHashCode() => + HashCode.Combine(RuntimeHelpers.GetHashCodeOfPtr(m_handle), m_declaringType.GetHashCode()); + + public override bool Equals(object? obj) => + obj is RuntimeMethodInfo m && m_handle == m.m_handle && ReferenceEquals(m_declaringType, m.m_declaringType); - public override bool Equals(object? obj) - { - return obj is RuntimeMethodInfo m && m_handle == m.m_handle; - } #endregion #region ICustomAttributeProvider From 06681a8ee83327c60e0b9d283514d5195938f875 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 4 Aug 2022 14:38:16 -0700 Subject: [PATCH 15/19] Update RuntimeConstructorInfo Equals, HashCode similarly --- .../src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index b9145526273a2c..4981fbae094b53 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -121,9 +121,9 @@ public override string ToString() } public override bool Equals(object? obj) => - obj is RuntimeConstructorInfo ci && m_handle == ci.m_handle; + obj is RuntimeConstructorInfo ci && m_handle == ci.m_handle && ReferenceEquals(m_declaringType, ci.m_declaringType); - public override int GetHashCode() => RuntimeHelpers.GetHashCodeOfPtr(m_handle); + public override int GetHashCode() => HashCode.Combine(RuntimeHelpers.GetHashCodeOfPtr(m_handle), m_declaringType.GetHashCode()); #endregion #region ICustomAttributeProvider From eb9d1976e410ec37c68e567c8f3b4bd47d1335af Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Fri, 5 Aug 2022 17:54:07 -0700 Subject: [PATCH 16/19] Add reflected type into Equals, check MetadataUpdater.IsSupported in GetHashCode --- .../System/Reflection/RuntimeConstructorInfo.CoreCLR.cs | 3 ++- .../src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs | 8 +++++--- .../System.Runtime/tests/System/DelegateTests.cs | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index 4981fbae094b53..b86503c3fb4176 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -123,7 +123,8 @@ public override string ToString() public override bool Equals(object? obj) => obj is RuntimeConstructorInfo ci && m_handle == ci.m_handle && ReferenceEquals(m_declaringType, ci.m_declaringType); - public override int GetHashCode() => HashCode.Combine(RuntimeHelpers.GetHashCodeOfPtr(m_handle), m_declaringType.GetHashCode()); + public override int GetHashCode() => MetadataUpdater.IsSupported ? + HashCode.Combine(RuntimeHelpers.GetHashCodeOfPtr(m_handle), m_declaringType.GetHashCode()) : base.GetHashCode(); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index a7aabf10472d65..26d6e2ac984069 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -158,11 +158,13 @@ public override string ToString() return m_toString; } - public override int GetHashCode() => - HashCode.Combine(RuntimeHelpers.GetHashCodeOfPtr(m_handle), m_declaringType.GetHashCode()); + public override int GetHashCode() => (MetadataUpdater.IsSupported || IsGenericMethod) ? + HashCode.Combine(RuntimeHelpers.GetHashCodeOfPtr(m_handle), m_declaringType.GetHashCode()) : base.GetHashCode(); public override bool Equals(object? obj) => - obj is RuntimeMethodInfo m && m_handle == m.m_handle && ReferenceEquals(m_declaringType, m.m_declaringType); + obj is RuntimeMethodInfo m && m_handle == m.m_handle && + ReferenceEquals(m_declaringType, m.m_declaringType) && + ReferenceEquals(ReflectedType, m.ReflectedType); #endregion diff --git a/src/libraries/System.Runtime/tests/System/DelegateTests.cs b/src/libraries/System.Runtime/tests/System/DelegateTests.cs index 6675d90ccd258e..e24d5478fddc17 100644 --- a/src/libraries/System.Runtime/tests/System/DelegateTests.cs +++ b/src/libraries/System.Runtime/tests/System/DelegateTests.cs @@ -458,7 +458,7 @@ public static void SameGenericMethodObtainedViaDelegateAndReflectionAreSameForCl var m1 = ((MethodCallExpression)((Expression)(() => new ClassG().M())).Body).Method; var m2 = new Action(new ClassG().M).Method; Assert.True(m1.Equals(m2)); - Assert.True(m1.GetHashCode().Equals(m2.GetHashCode())); + Assert.Equal(m1.GetHashCode(), m2.GetHashCode()); Assert.Equal(m1.MethodHandle.Value, m2.MethodHandle.Value); } @@ -468,7 +468,7 @@ public static void SameGenericMethodObtainedViaDelegateAndReflectionAreSameForSt var m1 = ((MethodCallExpression)((Expression)(() => new StructG().M())).Body).Method; var m2 = new Action(new StructG().M).Method; Assert.True(m1.Equals(m2)); - Assert.True(m1.GetHashCode().Equals(m2.GetHashCode())); + Assert.Equal(m1.GetHashCode(), m2.GetHashCode()); Assert.Equal(m1.MethodHandle.Value, m2.MethodHandle.Value); } From 72d21c66d8e297f5f75bfb53d2deb43e80b798ad Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sat, 6 Aug 2022 06:17:57 -0700 Subject: [PATCH 17/19] Perf tweaks for Equals and GetHashCode - No need to use GetHashCodeOfPtr when we are wrapping the hashcode using HashCode.Combine that takes care of the randomization - Use underlying type handle for type hashcodes. It is faster than the default object hashcode. - Delete special casing for MetadataUpdater.IsSupported from RuntimeMethodInfo.GetHashCode. It is actually a de-optimization for RuntimeMethodInfo with the two changes above, and about neutral for the rest. - Avoid virtual call for ReflectedType comparison - Restore comment for RuntimeMethodInfo --- .../Reflection/RuntimeConstructorInfo.CoreCLR.cs | 4 ++-- .../src/System/Reflection/RuntimeEventInfo.cs | 4 ++-- .../src/System/Reflection/RuntimeFieldInfo.cs | 4 ++-- .../src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs | 10 +++++++--- .../src/System/Reflection/RuntimePropertyInfo.cs | 4 ++-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index b86503c3fb4176..0de3fc4262554e 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -123,8 +123,8 @@ public override string ToString() public override bool Equals(object? obj) => obj is RuntimeConstructorInfo ci && m_handle == ci.m_handle && ReferenceEquals(m_declaringType, ci.m_declaringType); - public override int GetHashCode() => MetadataUpdater.IsSupported ? - HashCode.Combine(RuntimeHelpers.GetHashCodeOfPtr(m_handle), m_declaringType.GetHashCode()) : base.GetHashCode(); + public override int GetHashCode() => + HashCode.Combine(m_handle.GetHashCode(), m_declaringType.GetUnderlyingNativeHandle().GetHashCode()); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index 97b1ceecb8c6c9..09adb05fc289c3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -73,8 +73,8 @@ public override bool Equals(object? obj) => ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && CacheEquals(obj)); - public override int GetHashCode() => MetadataUpdater.IsSupported ? - HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); + public override int GetHashCode() => + HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetUnderlyingNativeHandle().GetHashCode()); #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index dff871114a52d0..1d0a1c61a83322 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -52,8 +52,8 @@ public override bool Equals(object? obj) => ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && CacheEquals(obj)); - public override int GetHashCode() => MetadataUpdater.IsSupported ? - HashCode.Combine(MetadataToken.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); + public override int GetHashCode() => + HashCode.Combine(MetadataToken.GetHashCode(), m_declaringType.GetUnderlyingNativeHandle().GetHashCode()); #endregion #region Object Overrides diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 26d6e2ac984069..d6278efa15cdd6 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -158,13 +158,17 @@ public override string ToString() return m_toString; } - public override int GetHashCode() => (MetadataUpdater.IsSupported || IsGenericMethod) ? - HashCode.Combine(RuntimeHelpers.GetHashCodeOfPtr(m_handle), m_declaringType.GetHashCode()) : base.GetHashCode(); + // We cannot do simple object identity comparisons due to generic methods. + // Equals and GetHashCode will be called in CerHashTable when RuntimeType+RuntimeTypeCache.GetGenericMethodInfo() + // retrieve items from and insert items into s_methodInstantiations. + + public override int GetHashCode() => + HashCode.Combine(m_handle.GetHashCode(), m_declaringType.GetUnderlyingNativeHandle().GetHashCode()); public override bool Equals(object? obj) => obj is RuntimeMethodInfo m && m_handle == m.m_handle && ReferenceEquals(m_declaringType, m.m_declaringType) && - ReferenceEquals(ReflectedType, m.ReflectedType); + ReferenceEquals(m_reflectedTypeCache.GetRuntimeType(), m_reflectedTypeCache.GetRuntimeType()); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 80f41a77e2cb6d..b844b6eaa0d752 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -184,8 +184,8 @@ public override bool Equals(object? obj) => ReferenceEquals(this, obj) || (MetadataUpdater.IsSupported && CacheEquals(obj)); - public override int GetHashCode() => MetadataUpdater.IsSupported ? - HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetHashCode()) : base.GetHashCode(); + public override int GetHashCode() => + HashCode.Combine(m_token.GetHashCode(), m_declaringType.GetUnderlyingNativeHandle().GetHashCode()); #endregion #region PropertyInfo Overrides From cbeb099c66200a99a1b3b6380998ca0e226625a4 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Sat, 6 Aug 2022 10:08:33 -0700 Subject: [PATCH 18/19] Apply suggestions from code review Co-authored-by: Jan Kotas --- .../src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs | 3 ++- .../src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index 0de3fc4262554e..c5297a3ab8b486 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -121,7 +121,8 @@ public override string ToString() } public override bool Equals(object? obj) => - obj is RuntimeConstructorInfo ci && m_handle == ci.m_handle && ReferenceEquals(m_declaringType, ci.m_declaringType); + ReferenceEquals(this, obj) || + (MetadataUpdater.IsSupported && CacheEquals(obj)); public override int GetHashCode() => HashCode.Combine(m_handle.GetHashCode(), m_declaringType.GetUnderlyingNativeHandle().GetHashCode()); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index d6278efa15cdd6..53388ccf2c7554 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -168,7 +168,7 @@ public override int GetHashCode() => public override bool Equals(object? obj) => obj is RuntimeMethodInfo m && m_handle == m.m_handle && ReferenceEquals(m_declaringType, m.m_declaringType) && - ReferenceEquals(m_reflectedTypeCache.GetRuntimeType(), m_reflectedTypeCache.GetRuntimeType()); + ReferenceEquals(m_reflectedTypeCache.GetRuntimeType(), m.m_reflectedTypeCache.GetRuntimeType()); #endregion From 4730c9fd862adfbe5f43f8896ae03e23b3493f4a Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Sun, 7 Aug 2022 23:10:45 -0700 Subject: [PATCH 19/19] Apply feedback --- .../src/System/Reflection/MdFieldInfo.cs | 8 ++++++++ .../src/System/Reflection/RtFieldInfo.cs | 8 ++++++++ .../System/Reflection/RuntimeConstructorInfo.CoreCLR.cs | 3 ++- .../src/System/Reflection/RuntimeFieldInfo.cs | 7 ------- .../src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs | 1 - 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs index ef97899581195d..8f241f4d8b6b3e 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Globalization; +using System.Reflection.Metadata; using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache; namespace System.Reflection @@ -42,6 +43,13 @@ o is MdFieldInfo m && public override int MetadataToken => m_tkField; internal override RuntimeModule GetRuntimeModule() { return m_declaringType.GetRuntimeModule(); } + + public override bool Equals(object? obj) => + ReferenceEquals(this, obj) || + (MetadataUpdater.IsSupported && CacheEquals(obj)); + + public override int GetHashCode() => + HashCode.Combine(m_tkField.GetHashCode(), m_declaringType.GetUnderlyingNativeHandle().GetHashCode()); #endregion #region FieldInfo Overrides diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs index 5831eca455adc1..ac322bdf20c002 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Globalization; +using System.Reflection.Metadata; using System.Runtime.CompilerServices; using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache; @@ -183,6 +184,13 @@ internal override RuntimeModule GetRuntimeModule() return RuntimeTypeHandle.GetModule(RuntimeFieldHandle.GetApproxDeclaringType(this)); } + public override bool Equals(object? obj) => + ReferenceEquals(this, obj) || + (MetadataUpdater.IsSupported && CacheEquals(obj)); + + public override int GetHashCode() => + HashCode.Combine(m_fieldHandle.GetHashCode(), m_declaringType.GetUnderlyingNativeHandle().GetHashCode()); + #endregion #region FieldInfo Overrides diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs index c5297a3ab8b486..98a98161208f41 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs @@ -73,7 +73,8 @@ internal RuntimeConstructorInfo( RuntimeMethodHandleInternal IRuntimeMethodInfo.Value => new RuntimeMethodHandleInternal(m_handle); internal override bool CacheEquals(object? o) => - o is RuntimeConstructorInfo m && m.m_handle == m_handle; + o is RuntimeConstructorInfo m && m.m_handle == m_handle && + ReferenceEquals(m_declaringType, m.m_declaringType); internal Signature Signature { diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index 1d0a1c61a83322..5cbf1cb1463c0f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Reflection.Metadata; using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache; namespace System.Reflection @@ -48,12 +47,6 @@ internal RuntimeType GetDeclaringTypeInternal() public override Module Module => GetRuntimeModule(); public override bool IsCollectible => m_declaringType.IsCollectible; - public override bool Equals(object? obj) => - ReferenceEquals(this, obj) || - (MetadataUpdater.IsSupported && CacheEquals(obj)); - - public override int GetHashCode() => - HashCode.Combine(MetadataToken.GetHashCode(), m_declaringType.GetUnderlyingNativeHandle().GetHashCode()); #endregion #region Object Overrides diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs index 53388ccf2c7554..c55ee607da7738 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Security; using System.Text;