Skip to content

Commit

Permalink
Use overriden double/float GetHashCode for default struct hashcodes
Browse files Browse the repository at this point in the history
Fixes #16545
  • Loading branch information
jkotas committed Feb 24, 2018
1 parent a3e87cf commit 2ff34d8
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 44 deletions.
94 changes: 50 additions & 44 deletions src/vm/comutilnative.cpp
Expand Up @@ -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())
Expand All @@ -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
{
Expand All @@ -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;
}

Expand Down
6 changes: 6 additions & 0 deletions src/vm/mscorlib.h
Expand Up @@ -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)


Expand Down

0 comments on commit 2ff34d8

Please sign in to comment.