summaryrefslogtreecommitdiff
path: root/src/vm/methodtable.h
diff options
context:
space:
mode:
authorJim Ma <mazong1123@gmail.com>2017-08-24 10:32:15 +1200
committerJan Kotas <jkotas@microsoft.com>2017-08-23 15:32:15 -0700
commit495ece4abd2204e1fc79f34cf3ea7fe5ecf90ad3 (patch)
treec61e4ca722f697cfdd7be3611cdb144cc513b7f9 /src/vm/methodtable.h
parent59da8574383d547a20dcae478b67ff458f6d71e6 (diff)
downloadcoreclr-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.h38
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()
{