Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit b7eaa28

Browse files
author
Viktor Hofer
committed
Merged PR 101703: Move to marvin hashing for OrdinalIgnoreCase CompareInfo & StringComparers
Move to marvin hashing for OrdinalIgnoreCase CompareInfo & StringComparers
1 parent a41736b commit b7eaa28

File tree

5 files changed

+45
-30
lines changed

5 files changed

+45
-30
lines changed

src/classlibnative/bcltype/stringnative.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,25 @@ FCIMPL3(INT32, COMString::Marvin32HashString, StringObject* thisRefUNSAFE, INT32
187187
}
188188
FCIMPLEND
189189

190+
FCIMPL2(INT32, COMString::Marvin32HashPtr, WCHAR *pRawStr, INT32 strLen) {
191+
FCALL_CONTRACT;
192+
193+
int iReturnHash = 0;
194+
195+
if (pRawStr == NULL) {
196+
FCThrow(kNullReferenceException);
197+
}
198+
199+
BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrow(kStackOverflowException));
200+
iReturnHash = GetCurrentNlsHashProvider()->HashString(pRawStr, strLen, TRUE, 0);
201+
END_SO_INTOLERANT_CODE;
202+
203+
FC_GC_POLL_RET();
204+
205+
return iReturnHash;
206+
}
207+
FCIMPLEND
208+
190209
BOOL QCALLTYPE COMString::UseRandomizedHashing() {
191210
QCALL_CONTRACT;
192211

src/classlibnative/bcltype/stringnative.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class COMString {
9191

9292
#ifdef FEATURE_RANDOMIZED_STRING_HASHING
9393
static FCDECL3(INT32, Marvin32HashString, StringObject* thisRefUNSAFE, INT32 strLen, INT64 additionalEntropy);
94+
static FCDECL2(INT32, Marvin32HashPtr, WCHAR *pRawStr, INT32 strLen);
9495
static BOOL QCALLTYPE UseRandomizedHashing();
9596
#endif // FEATURE_RANDOMIZED_STRING_HASHING
9697

src/mscorlib/corefx/System/Globalization/TextInfo.cs

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -407,53 +407,43 @@ internal unsafe int GetCaseInsensitiveHashCode(String str)
407407
throw new ArgumentNullException("str");
408408
}
409409

410+
// Do not allocate on the stack if string is empty
411+
if (str.Length == 0)
412+
{
413+
return str.GetHashCode();
414+
}
415+
410416
// This code assumes that ASCII casing is safe for whatever context is passed in.
411417
// this is true today, because we only ever call these methods on Invariant. It would be ideal to refactor
412418
// these methods so they were correct by construction and we could only ever use Invariant.
413419

414-
uint hash = 5381;
415-
uint c;
420+
// If the string contains Unicode characters or is longer than 250 characters
421+
// we allocate on the heap --> slow path.
422+
if (!str.IsAscii() || str.Length > 250)
423+
{
424+
return ToUpper(str).GetHashCode();
425+
}
426+
427+
// For the common case of ascii-only short strings (less than 250 characters) we can allocate on the stack
428+
// and upper case the characters.
429+
char* charArr = stackalloc char[str.Length];
430+
char c;
416431

417-
// Note: We assume that str contains only ASCII characters until
418-
// we hit a non-ASCII character to optimize the common case.
419432
for (int i = 0; i < str.Length; i++)
420433
{
421434
c = str[i];
422-
if (c >= 0x80)
423-
{
424-
return GetCaseInsensitiveHashCodeSlow(str);
425-
}
426435

427436
// If we have a lowercase character, ANDing off 0x20
428437
// will make it an uppercase character.
429438
if ((c - 'a') <= ('z' - 'a'))
430439
{
431-
c = (uint)((int)c & ~0x20);
440+
c = (char)(c & ~0x20);
432441
}
433442

434-
hash = ((hash << 5) + hash) ^ c;
435-
}
436-
437-
return (int)hash;
438-
439-
}
440-
441-
private unsafe int GetCaseInsensitiveHashCodeSlow(String str)
442-
{
443-
Contract.Assert(str != null);
444-
445-
string upper = ToUpper(str);
446-
447-
uint hash = 5381;
448-
uint c;
449-
450-
for (int i = 0; i < upper.Length; i++)
451-
{
452-
c = upper[i];
453-
hash = ((hash << 5) + hash) ^ c;
443+
charArr[i] = c;
454444
}
455445

456-
return (int)hash;
446+
return String.InternalMarvin32HashPtr(charArr, str.Length);
457447
}
458448
}
459449
}

src/mscorlib/src/System/String.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,10 @@ public static bool IsNullOrWhiteSpace(String value) {
827827
[MethodImplAttribute(MethodImplOptions.InternalCall)]
828828
internal static extern int InternalMarvin32HashString(string s, int strLen, long additionalEntropy);
829829

830+
[System.Security.SecurityCritical]
831+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
832+
internal unsafe static extern int InternalMarvin32HashPtr(char* s, int strLen);
833+
830834
[System.Security.SecuritySafeCritical]
831835
internal static bool UseRandomizedHashing() {
832836
return InternalUseRandomizedHashing();

src/vm/ecalllist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ FCFuncStart(gStringFuncs)
238238
#endif // FEATURE_COMINTEROP
239239
#ifdef FEATURE_RANDOMIZED_STRING_HASHING
240240
FCFuncElement("InternalMarvin32HashString", COMString::Marvin32HashString)
241+
FCFuncElement("InternalMarvin32HashPtr", COMString::Marvin32HashPtr)
241242
QCFuncElement("InternalUseRandomizedHashing", COMString::UseRandomizedHashing)
242243
#endif // FEATURE_RANDOMIZED_STRING_HASHING
243244
FCFuncEnd()

0 commit comments

Comments
 (0)