From 1466e404dfac7ad6af7e6877d26885ce42414120 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 29 May 2022 21:12:49 +0800 Subject: Convert Valuetype.FastEqualsCheck and GetHashCodeOfPtr to managed (#69723) * Convert GetHashCodeOfPtr to managed * Convert FastEqualsCheck to managed * Add FCall to get object size * Reduce local variable creation * Change FCall to pass MethodTable* * Sort ecallist and move to MethodTableNative --- .../CompilerServices/RuntimeHelpers.CoreCLR.cs | 3 ++ .../System.Private.CoreLib/src/System/ValueType.cs | 55 +++++++++++++++------- src/coreclr/vm/comutilnative.cpp | 42 +---------------- src/coreclr/vm/comutilnative.h | 7 ++- src/coreclr/vm/ecalllist.h | 7 ++- 5 files changed, 54 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index cc594304715..cb8ca49e068 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -516,6 +516,9 @@ namespace System.Runtime.CompilerServices return (int)((BaseSize - (uint)(3 * sizeof(IntPtr))) / (uint)(2 * sizeof(int))); } } + + [MethodImpl(MethodImplOptions.InternalCall)] + public extern uint GetNumInstanceFieldBytes(); } // Helper structs used for tail calls via helper. diff --git a/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs b/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs index e15ad7512c8..31c98a5bf25 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs @@ -10,9 +10,11 @@ ** ===========================================================*/ +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; +using System.Threading; namespace System { @@ -22,34 +24,34 @@ namespace System { [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "Trimmed fields don't make a difference for equality")] - public override bool Equals([NotNullWhen(true)] object? obj) + public unsafe override bool Equals([NotNullWhen(true)] object? obj) { if (null == obj) { return false; } - Type thisType = this.GetType(); - Type thatType = obj.GetType(); - if (thatType != thisType) + if (GetType() != obj.GetType()) { return false; } - object thisObj = (object)this; - object? thisResult, thatResult; - // if there are no GC references in this object we can avoid reflection // and do a fast memcmp if (CanCompareBits(this)) - return FastEqualsCheck(thisObj, obj); + { + return SpanHelpers.SequenceEqual( + ref RuntimeHelpers.GetRawData(this), + ref RuntimeHelpers.GetRawData(obj), + RuntimeHelpers.GetMethodTable(this)->GetNumInstanceFieldBytes()); + } - FieldInfo[] thisFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + FieldInfo[] thisFields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < thisFields.Length; i++) { - thisResult = thisFields[i].GetValue(thisObj); - thatResult = thisFields[i].GetValue(obj); + object? thisResult = thisFields[i].GetValue(this); + object? thatResult = thisFields[i].GetValue(obj); if (thisResult == null) { @@ -69,9 +71,6 @@ namespace System [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool CanCompareBits(object obj); - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool FastEqualsCheck(object a, object b); - /*=================================GetHashCode================================== **Action: Our algorithm for returning the hashcode is a little bit complex. We look ** for the first non-static field and get its hashcode. If the type has no @@ -85,8 +84,32 @@ namespace System [MethodImpl(MethodImplOptions.InternalCall)] public extern override int GetHashCode(); - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern int GetHashCodeOfPtr(IntPtr ptr); + private static int s_seed; + + internal static int GetHashCodeOfPtr(IntPtr ptr) + { + int hashCode = (int)ptr; + + if (hashCode == 0) + { + return 0; + } + + int seed = s_seed; + + // Initialize s_seed lazily + if (seed == 0) + { + // We use the first non-0 pointer as the seed, all hashcodes will be based off that. + // This is to make sure that we only reveal relative memory addresses and never absolute ones. + seed = hashCode; + Interlocked.CompareExchange(ref s_seed, seed, 0); + seed = s_seed; + } + + Debug.Assert(s_seed != 0); + return hashCode - seed; + } public override string? ToString() { diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp index 7f92d23b8cc..5dfaec08323 100644 --- a/src/coreclr/vm/comutilnative.cpp +++ b/src/coreclr/vm/comutilnative.cpp @@ -1847,21 +1847,6 @@ FCIMPL1(FC_BOOL_RET, ValueTypeHelper::CanCompareBits, Object* obj) } FCIMPLEND -FCIMPL2(FC_BOOL_RET, ValueTypeHelper::FastEqualsCheck, Object* obj1, Object* obj2) -{ - FCALL_CONTRACT; - - _ASSERTE(obj1 != NULL); - _ASSERTE(obj2 != NULL); - _ASSERTE(!obj1->GetMethodTable()->ContainsPointers()); - _ASSERTE(obj1->GetSize() == obj2->GetSize()); - - TypeHandle pTh = obj1->GetTypeHandle(); - - FC_RETURN_BOOL(memcmp(obj1->GetData(),obj2->GetData(),pTh.GetSize()) == 0); -} -FCIMPLEND - static INT32 FastGetValueTypeHashCodeHelper(MethodTable *mt, void *pObjRef) { CONTRACTL @@ -2044,33 +2029,10 @@ FCIMPL1(INT32, ValueTypeHelper::GetHashCode, Object* objUNSAFE) } FCIMPLEND -static LONG s_dwSeed; - -FCIMPL1(INT32, ValueTypeHelper::GetHashCodeOfPtr, LPVOID ptr) +FCIMPL1(UINT32, MethodTableNative::GetNumInstanceFieldBytes, MethodTable* mt) { FCALL_CONTRACT; - - INT32 hashCode = (INT32)((INT64)(ptr)); - - if (hashCode == 0) - { - return 0; - } - - DWORD dwSeed = s_dwSeed; - - // Initialize s_dwSeed lazily - if (dwSeed == 0) - { - // We use the first non-0 pointer as the seed, all hashcodes will be based off that. - // This is to make sure that we only reveal relative memory addresses and never absolute ones. - dwSeed = hashCode; - InterlockedCompareExchange(&s_dwSeed, dwSeed, 0); - dwSeed = s_dwSeed; - } - _ASSERTE(dwSeed != 0); - - return hashCode - dwSeed; + return mt->GetNumInstanceFieldBytes(); } FCIMPLEND diff --git a/src/coreclr/vm/comutilnative.h b/src/coreclr/vm/comutilnative.h index 42ec3b0663b..cbcc4457ad6 100644 --- a/src/coreclr/vm/comutilnative.h +++ b/src/coreclr/vm/comutilnative.h @@ -218,9 +218,12 @@ extern "C" void QCALLTYPE Interlocked_MemoryBarrierProcessWide(); class ValueTypeHelper { public: static FCDECL1(FC_BOOL_RET, CanCompareBits, Object* obj); - static FCDECL2(FC_BOOL_RET, FastEqualsCheck, Object* obj1, Object* obj2); static FCDECL1(INT32, GetHashCode, Object* objRef); - static FCDECL1(INT32, GetHashCodeOfPtr, LPVOID ptr); +}; + +class MethodTableNative { +public: + static FCDECL1(UINT32, GetNumInstanceFieldBytes, MethodTable* mt); }; class StreamNative { diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index c85799fd7f1..a14d5855d59 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -83,9 +83,7 @@ FCFuncEnd() FCFuncStart(gValueTypeFuncs) FCFuncElement("CanCompareBits", ValueTypeHelper::CanCompareBits) - FCFuncElement("FastEqualsCheck", ValueTypeHelper::FastEqualsCheck) FCFuncElement("GetHashCode", ValueTypeHelper::GetHashCode) - FCFuncElement("GetHashCodeOfPtr", ValueTypeHelper::GetHashCodeOfPtr) FCFuncEnd() FCFuncStart(gDiagnosticsDebugger) @@ -605,6 +603,10 @@ FCFuncStart(gRuntimeHelpers) FCFuncElement("UnregisterForGCReporting", GCReporting::Unregister) FCFuncEnd() +FCFuncStart(gMethodTableFuncs) + FCFuncElement("GetNumInstanceFieldBytes", MethodTableNative::GetNumInstanceFieldBytes) +FCFuncEnd() + FCFuncStart(gMngdFixedArrayMarshalerFuncs) FCFuncElement("CreateMarshaler", MngdFixedArrayMarshaler::CreateMarshaler) FCFuncElement("ConvertSpaceToNative", MngdFixedArrayMarshaler::ConvertSpaceToNative) @@ -783,6 +785,7 @@ FCClassElement("Marshal", "System.Runtime.InteropServices", gInteropMarshalFuncs FCClassElement("Math", "System", gMathFuncs) FCClassElement("MathF", "System", gMathFFuncs) FCClassElement("MetadataImport", "System.Reflection", gMetaDataImport) +FCClassElement("MethodTable", "System.Runtime.CompilerServices", gMethodTableFuncs) FCClassElement("MngdFixedArrayMarshaler", "System.StubHelpers", gMngdFixedArrayMarshalerFuncs) FCClassElement("MngdNativeArrayMarshaler", "System.StubHelpers", gMngdNativeArrayMarshalerFuncs) FCClassElement("MngdRefCustomMarshaler", "System.StubHelpers", gMngdRefCustomMarshalerFuncs) -- cgit v1.2.3