diff options
author | Jim Ma <mazong1123@gmail.com> | 2017-08-24 10:32:15 +1200 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2017-08-23 15:32:15 -0700 |
commit | 495ece4abd2204e1fc79f34cf3ea7fe5ecf90ad3 (patch) | |
tree | c61e4ca722f697cfdd7be3611cdb144cc513b7f9 /src/vm/methodtable.h | |
parent | 59da8574383d547a20dcae478b67ff458f6d71e6 (diff) | |
download | coreclr-495ece4abd2204e1fc79f34cf3ea7fe5ecf90ad3.tar.gz coreclr-495ece4abd2204e1fc79f34cf3ea7fe5ecf90ad3.tar.bz2 coreclr-495ece4abd2204e1fc79f34cf3ea7fe5ecf90ad3.zip |
Fixed Equals/GetHashCode bug for struct. (#13164)
Other than `ContainsPointers` and `IsNotTightlyPacked`, added two new conditions for checking whether a valuetype can go to fast path or not. Following are the details of these 2 conditions:
- Check whether a valuetype contains a Single/Double field. If it does, we cannot go to fast path. Floating point numbers have special `Equals` and `GetHashCode` implementation. We cannot simply compare floating point numbers via bits (e.g. +0.0 should equal to -0.0, but their underlying bits are different).
- Check whether an user-defined valuetype overrides `Equals` or `GetHashCode`. If it does, we cannot go to fast path. Because `Equals` or `GetHashCode` result may be different to bit comparison.
To find Single/Double fields and overridden `Equals`/`GetHashCode`, we start a DFS to go through the whole hierachy of the source valuetype, and cache the result to `MethodTable`.
Fix #11452
Diffstat (limited to 'src/vm/methodtable.h')
-rw-r--r-- | src/vm/methodtable.h | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h index 77ec9f51ea..85229b691f 100644 --- a/src/vm/methodtable.h +++ b/src/vm/methodtable.h @@ -405,6 +405,9 @@ struct MethodTableWriteableData enum_flag_SkipWinRTOverride = 0x00000100, // No WinRT override is needed + enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x00000200, // Is any field type or sub field type overrode Equals or GetHashCode + enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x00000400, // Whether we have checked the overridden Equals or GetHashCode + #ifdef FEATURE_PREJIT // These flags are used only at ngen time. We store them here since // we are running out of available flags in MethodTable. They may eventually @@ -1250,6 +1253,41 @@ public: WRAPPER_NO_CONTRACT; FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite_NoLogging()->m_dwFlags), MethodTableWriteableData::enum_flag_SkipWinRTOverride); } + + inline BOOL CanCompareBitsOrUseFastGetHashCode() + { + LIMITED_METHOD_CONTRACT; + return (GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode); + } + + // If canCompare is true, this method ensure an atomic operation for setting + // enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode and enum_flag_CanCompareBitsOrUseFastGetHashCode flags. + inline void SetCanCompareBitsOrUseFastGetHashCode(BOOL canCompare) + { + WRAPPER_NO_CONTRACT + if (canCompare) + { + // Set checked and canCompare flags in one interlocked operation. + FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite_NoLogging()->m_dwFlags), + MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode | MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode); + } + else + { + SetHasCheckedCanCompareBitsOrUseFastGetHashCode(); + } + } + + inline BOOL HasCheckedCanCompareBitsOrUseFastGetHashCode() + { + LIMITED_METHOD_CONTRACT; + return (GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode); + } + + inline void SetHasCheckedCanCompareBitsOrUseFastGetHashCode() + { + WRAPPER_NO_CONTRACT; + FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite_NoLogging()->m_dwFlags), MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode); + } inline void SetIsDependenciesLoaded() { |