Use overriden double/float GetHashCode for default struct hashcodes (#16550)
authorJan Kotas <jkotas@microsoft.com>
Mon, 26 Feb 2018 16:18:30 +0000 (08:18 -0800)
committerGitHub <noreply@github.com>
Mon, 26 Feb 2018 16:18:30 +0000 (08:18 -0800)
Fixes #16545

src/vm/comutilnative.cpp
src/vm/mscorlib.h

index c456399..3b30d4c 100644 (file)
@@ -2058,7 +2058,8 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef)
     } CONTRACTL_END;
 
     INT32 hashCode = 0;
-    INT32 *pObj = (INT32*)pObjRef;
+
+    GCPROTECT_BEGININTERIOR(pObjRef);
 
     BOOL canUseFastGetHashCodeHelper = FALSE;
     if (mt->HasCheckedCanCompareBitsOrUseFastGetHashCode())
@@ -2074,7 +2075,7 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef)
     // be able to handle getting the hashcode for an embedded structure whose hashcode is computed by the fast path.
     if (canUseFastGetHashCodeHelper)
     {
-        return FastGetValueTypeHashCodeHelper(mt, pObjRef);
+        hashCode = FastGetValueTypeHashCodeHelper(mt, pObjRef);
     }
     else
     {
@@ -2087,60 +2088,65 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef)
         //
         // <TODO> check this approximation - we may be losing exact type information </TODO>
         ApproxFieldDescIterator fdIterator(mt, ApproxFieldDescIterator::INSTANCE_FIELDS);
-        INT32 count = (INT32)fdIterator.Count();
 
-        if (count != 0)
+        FieldDesc *field;
+        while ((field = fdIterator.Next()) != NULL)
         {
-            for (INT32 i = 0; i < count; i++)
+            _ASSERTE(!field->IsRVA());
+            if (field->IsObjRef())
             {
-                FieldDesc *field = fdIterator.Next();
-                _ASSERTE(!field->IsRVA());
-                void *pFieldValue = (BYTE *)pObj + field->GetOffsetUnsafe();
-                if (field->IsObjRef())
+                // if we get an object reference we get the hash code out of that
+                if (*(Object**)((BYTE *)pObjRef + field->GetOffsetUnsafe()) != NULL)
                 {
-                    // if we get an object reference we get the hash code out of that
-                    if (*(Object**)pFieldValue != NULL)
-                    {
-
-                        OBJECTREF fieldObjRef = ObjectToOBJECTREF(*(Object **) pFieldValue);
-                        GCPROTECT_BEGIN(fieldObjRef);
-
-                        MethodDescCallSite getHashCode(METHOD__OBJECT__GET_HASH_CODE, &fieldObjRef);
-
-                        // Make the call.
-                        ARG_SLOT arg[1] = {ObjToArgSlot(fieldObjRef)};
-                        hashCode = getHashCode.Call_RetI4(arg);
-
-                        GCPROTECT_END();
-                    }
-                    else
-                    {
-                        // null object reference, try next
-                        continue;
-                    }
+                    PREPARE_SIMPLE_VIRTUAL_CALLSITE(METHOD__OBJECT__GET_HASH_CODE, (*(Object**)((BYTE *)pObjRef + field->GetOffsetUnsafe())));
+                    DECLARE_ARGHOLDER_ARRAY(args, 1);
+                    args[ARGNUM_0] = PTR_TO_ARGHOLDER(*(Object**)((BYTE *)pObjRef + field->GetOffsetUnsafe()));
+                    CALL_MANAGED_METHOD(hashCode, INT32, args);
                 }
                 else
                 {
+                    // null object reference, try next
+                    continue;
+                }
+            }
+            else
+            {
+                CorElementType fieldType = field->GetFieldType();
+                if (fieldType == ELEMENT_TYPE_R8)
+                {
+                    PREPARE_NONVIRTUAL_CALLSITE(METHOD__DOUBLE__GET_HASH_CODE);
+                    DECLARE_ARGHOLDER_ARRAY(args, 1);
+                    args[ARGNUM_0] = PTR_TO_ARGHOLDER(((BYTE *)pObjRef + field->GetOffsetUnsafe()));
+                    CALL_MANAGED_METHOD(hashCode, INT32, args);
+                }
+                else if (fieldType == ELEMENT_TYPE_R4)
+                {
+                    PREPARE_NONVIRTUAL_CALLSITE(METHOD__SINGLE__GET_HASH_CODE);
+                    DECLARE_ARGHOLDER_ARRAY(args, 1);
+                    args[ARGNUM_0] = PTR_TO_ARGHOLDER(((BYTE *)pObjRef + field->GetOffsetUnsafe()));
+                    CALL_MANAGED_METHOD(hashCode, INT32, args);
+                }
+                else if (fieldType != ELEMENT_TYPE_VALUETYPE)
+                {
                     UINT fieldSize = field->LoadSize();
-                    INT32 *pValue = (INT32*)pFieldValue;
-                    CorElementType fieldType = field->GetFieldType();
-                    if (fieldType != ELEMENT_TYPE_VALUETYPE)
-                    {
-                        for (INT32 j = 0; j < (INT32)(fieldSize / sizeof(INT32)); j++)
-                            hashCode ^= *pValue++;
-                    }
-                    else
-                    {
-                        // got another value type. Get the type
-                        TypeHandle fieldTH = field->LookupFieldTypeHandle(); // the type was loaded already
-                        _ASSERTE(!fieldTH.IsNull());
-                        hashCode = RegularGetValueTypeHashCode(fieldTH.GetMethodTable(), pValue);
-                    }
+                    INT32 *pValue = (INT32*)((BYTE *)pObjRef + field->GetOffsetUnsafe());
+                    for (INT32 j = 0; j < (INT32)(fieldSize / sizeof(INT32)); j++)
+                        hashCode ^= *pValue++;
+                }
+                else
+                {
+                    // got another value type. Get the type
+                    TypeHandle fieldTH = field->GetFieldTypeHandleThrowing();
+                    _ASSERTE(!fieldTH.IsNull());
+                    hashCode = RegularGetValueTypeHashCode(fieldTH.GetMethodTable(), (BYTE *)pObjRef + field->GetOffsetUnsafe());
                 }
-                break;
             }
+            break;
         }
     }
+
+    GCPROTECT_END();
+
     return hashCode;
 }
 
index d58e6aa..528f2d9 100644 (file)
@@ -661,6 +661,12 @@ DEFINE_METHOD(OBJECT,               EQUALS,                 Equals,
 DEFINE_METHOD(OBJECT,               FIELD_SETTER,           FieldSetter,                IM_Str_Str_Obj_RetVoid)
 DEFINE_METHOD(OBJECT,               FIELD_GETTER,           FieldGetter,                IM_Str_Str_RefObj_RetVoid)
 
+// DEFINE_CLASS(DOUBLE,                System,                 Double)
+DEFINE_METHOD(DOUBLE,               GET_HASH_CODE,          GetHashCode, IM_RetInt)
+
+// DEFINE_CLASS(SINGLE,                System,                 Single)
+DEFINE_METHOD(SINGLE,               GET_HASH_CODE,          GetHashCode, IM_RetInt)
+
 DEFINE_CLASS(__CANON,              System,                 __Canon)