struct BucketTable
{
- DPTR(PTR_EEHashEntry_t) m_pBuckets; // Pointer to first entry for each bucket
- DWORD m_dwNumBuckets;
+ DPTR(PTR_EEHashEntry_t) m_pBuckets; // Pointer to first entry for each bucket
+ DWORD m_dwNumBuckets;
+#ifdef TARGET_64BIT
+ UINT64 m_dwNumBucketsMul; // "Fast Mod" multiplier for "X % m_dwNumBuckets"
+#endif
} m_BucketTable[2];
typedef DPTR(BucketTable) PTR_BucketTable;
EEHashTable()
{
LIMITED_METHOD_CONTRACT;
- this->m_BucketTable[0].m_pBuckets = NULL;
- this->m_BucketTable[0].m_dwNumBuckets = 0;
- this->m_BucketTable[1].m_pBuckets = NULL;
- this->m_BucketTable[1].m_dwNumBuckets = 0;
+ this->m_BucketTable[0].m_pBuckets = NULL;
+ this->m_BucketTable[0].m_dwNumBuckets = 0;
+ this->m_BucketTable[1].m_pBuckets = NULL;
+ this->m_BucketTable[1].m_dwNumBuckets = 0;
+#ifdef TARGET_64BIT
+ this->m_BucketTable[0].m_dwNumBucketsMul = 0;
+ this->m_BucketTable[1].m_dwNumBucketsMul = 0;
+#endif
+
#ifndef DACCESS_COMPILE
this->m_pVolatileBucketTable = NULL;
#endif
}
m_pVolatileBucketTable->m_dwNumBuckets = 0;
+#ifdef TARGET_64BIT
+ m_pVolatileBucketTable->m_dwNumBucketsMul = 0;
+#endif
m_dwNumEntries = 0;
}
// The first slot links to the next list.
m_pVolatileBucketTable->m_pBuckets++;
-
m_pVolatileBucketTable->m_dwNumBuckets = dwNumBuckets;
+#ifdef TARGET_64BIT
+ m_pVolatileBucketTable->m_dwNumBucketsMul = GetFastModMultiplier(dwNumBuckets);
+#endif
m_Heap = pHeap;
_ASSERTE(pBucketTable->m_dwNumBuckets != 0);
- DWORD dwBucket = dwHash % pBucketTable->m_dwNumBuckets;
+ DWORD dwBucket;
+#ifdef TARGET_64BIT
+ _ASSERTE(pBucketTable->m_dwNumBucketsMul != 0);
+ dwBucket = FastMod(dwHash, pBucketTable->m_dwNumBuckets, pBucketTable->m_dwNumBucketsMul);
+#else
+ dwBucket = dwHash % pBucketTable->m_dwNumBuckets;
+#endif
EEHashEntry_t * pSearch;
for (pSearch = pBucketTable->m_pBuckets[dwBucket]; pSearch; pSearch = pSearch->pNext)
pNewBucketTable->m_pBuckets = pNewBuckets;
pNewBucketTable->m_dwNumBuckets = dwNewNumBuckets;
+#ifdef TARGET_64BIT
+ pNewBucketTable->m_dwNumBucketsMul = GetFastModMultiplier(dwNewNumBuckets);
+#endif
// Add old table to the to free list. Note that the SyncClean thing will only
// delete the buckets at a safe point
HRESULT GetFileVersion(LPCWSTR wszFilePath, ULARGE_INTEGER* pFileVersion);
#endif // !TARGET_UNIX
+#ifdef TARGET_64BIT
+// We use modified Daniel Lemire's fastmod algorithm (https://github.com/dotnet/runtime/pull/406),
+// which allows to avoid the long multiplication if the divisor is less than 2**31.
+// This is a copy of HashHelpers.cs, see that impl (or linked PR) for more details
+inline UINT64 GetFastModMultiplier(UINT32 divisor)
+{
+ return UINT64_MAX / divisor + 1;
+}
+
+inline UINT32 FastMod(UINT32 value, UINT32 divisor, UINT64 multiplier)
+{
+ return (UINT32)(((((multiplier * value) >> 32) + 1) * divisor) >> 32);
+}
+#endif
+
#endif /* _H_UTIL */