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

Commit 32daf30

Browse files
author
Viktor Hofer
committed
Merged PR 101766: Move to marvin hashing for OrdinalIgnoreCase CompareInfo & StringComparers
Move to marvin hashing for OrdinalIgnoreCase CompareInfo & StringComparers
1 parent 6753cf2 commit 32daf30

File tree

5 files changed

+45
-29
lines changed

5 files changed

+45
-29
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
@@ -87,6 +87,7 @@ class COMString {
8787

8888
#ifdef FEATURE_RANDOMIZED_STRING_HASHING
8989
static FCDECL3(INT32, Marvin32HashString, StringObject* thisRefUNSAFE, INT32 strLen, INT64 additionalEntropy);
90+
static FCDECL2(INT32, Marvin32HashPtr, WCHAR *pRawStr, INT32 strLen);
9091
static BOOL QCALLTYPE UseRandomizedHashing();
9192
#endif // FEATURE_RANDOMIZED_STRING_HASHING
9293

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

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

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

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

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

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

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

454-
return (int)hash;
445+
return String.InternalMarvin32HashPtr(charArr, str.Length);
455446
}
456447
}
457448
}

src/mscorlib/src/System/String.Comparison.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,10 @@ public static bool Equals(String a, String b, StringComparison comparisonType) {
985985
[MethodImplAttribute(MethodImplOptions.InternalCall)]
986986
internal static extern int InternalMarvin32HashString(string s, int strLen, long additionalEntropy);
987987

988+
[System.Security.SecurityCritical]
989+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
990+
internal unsafe static extern int InternalMarvin32HashPtr(char* s, int strLen);
991+
988992
[System.Security.SecuritySafeCritical]
989993
internal static bool UseRandomizedHashing() {
990994
return InternalUseRandomizedHashing();

src/vm/ecalllist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ FCFuncStart(gStringFuncs)
234234
#endif // FEATURE_COMINTEROP
235235
#ifdef FEATURE_RANDOMIZED_STRING_HASHING
236236
FCFuncElement("InternalMarvin32HashString", COMString::Marvin32HashString)
237+
FCFuncElement("InternalMarvin32HashPtr", COMString::Marvin32HashPtr)
237238
QCFuncElement("InternalUseRandomizedHashing", COMString::UseRandomizedHashing)
238239
#endif // FEATURE_RANDOMIZED_STRING_HASHING
239240
FCFuncEnd()

0 commit comments

Comments
 (0)