@@ -372,19 +372,23 @@ private unsafe static bool EqualsHelper(String strA, String strB)
372
372
char * a = ap ;
373
373
char * b = bp ;
374
374
375
- // unroll the loop
376
- #if AMD64
375
+ #if WIN64
376
+ // Single int read aligns pointers for the following long reads
377
+ // PERF: No length check needed as there is always an int32 worth of string allocated
378
+ // This read can also include the null terminator which both strings will have
379
+ if ( * ( int * ) a != * ( int * ) b ) return false;
380
+ length -= 2 ; a += 2 ; b += 2 ;
381
+
377
382
// for AMD64 bit platform we unroll by 12 and
378
383
// check 3 qword at a time. This is less code
379
384
// than the 32 bit case and is a shorter path length.
380
- // Reads are unaligned
381
385
382
386
while ( length >= 12 )
383
387
{
384
388
if ( * ( long * ) a != * ( long * ) b ) return false;
385
389
if ( * ( long * ) ( a + 4 ) != * ( long * ) ( b + 4 ) ) return false;
386
390
if ( * ( long * ) ( a + 8 ) != * ( long * ) ( b + 8 ) ) return false ;
387
- a + = 12 ; b += 12 ; length - = 12 ;
391
+ length - = 12 ; a += 12 ; b + = 12 ;
388
392
}
389
393
#else
390
394
while ( length > = 10 )
@@ -394,7 +398,7 @@ private unsafe static bool EqualsHelper(String strA, String strB)
394
398
if ( * ( int * ) ( a+ 4 ) != * ( int * ) ( b + 4 ) ) return false;
395
399
if ( * ( int * ) ( a+ 6 ) != * ( int * ) ( b + 6 ) ) return false;
396
400
if ( * ( int * ) ( a+ 8 ) != * ( int * ) ( b + 8 ) ) return false;
397
- a + = 10 ; b += 10 ; length - = 10 ;
401
+ length - = 10 ; a += 10 ; b + = 10 ;
398
402
}
399
403
#endif
400
404
@@ -405,13 +409,70 @@ private unsafe static bool EqualsHelper(String strA, String strB)
405
409
while ( length > 0 )
406
410
{
407
411
if ( * ( int * ) a != * ( int * ) b) break ;
408
- a + = 2 ; b += 2 ; length - = 2 ;
412
+ length - = 2 ; a += 2 ; b + = 2 ;
409
413
}
410
414
411
415
return ( length < = 0 ) ;
412
416
}
413
417
}
414
-
418
+
419
+ [ System . Security . SecuritySafeCritical ] // auto-generated
420
+ [ ReliabilityContract ( Consistency . WillNotCorruptState , Cer . MayFail ) ]
421
+ private unsafe static bool StartsWithOrdinalHelper( String str, String startsWith )
422
+ {
423
+ Contract . Requires ( str != null ) ;
424
+ Contract . Requires ( startsWith != null ) ;
425
+ Contract . Requires ( str . Length > = startsWith . Length ) ;
426
+
427
+ int length = startsWith. Length;
428
+
429
+ fixed ( char * ap = & str. m_firstChar) fixed ( char * bp = & startsWith. m_firstChar)
430
+ {
431
+ char * a = ap;
432
+ char * b = bp;
433
+
434
+ #if WIN64
435
+ // Single int read aligns pointers for the following long reads
436
+ // No length check needed as this method is called when length >= 2
437
+ Contract . Assert( length > = 2 ) ;
438
+ if ( * ( int * ) a != * ( int * ) b) goto ReturnFalse;
439
+ length -= 2 ; a += 2 ; b += 2 ;
440
+
441
+ while ( length > = 12 )
442
+ {
443
+ if ( * ( long * ) a != * ( long * ) b) goto ReturnFalse;
444
+ if ( * ( long * ) ( a + 4 ) != * ( long * ) ( b + 4 ) ) goto ReturnFalse;
445
+ if ( * ( long * ) ( a + 8 ) != * ( long * ) ( b + 8 ) ) goto ReturnFalse;
446
+ length -= 12 ; a += 12 ; b += 12 ;
447
+ }
448
+ #else
449
+ while ( length > = 10 )
450
+ {
451
+ if ( * ( int * ) a != * ( int * ) b) goto ReturnFalse;
452
+ if ( * ( int * ) ( a+ 2 ) != * ( int * ) ( b+ 2 ) ) goto ReturnFalse;
453
+ if ( * ( int * ) ( a+ 4 ) != * ( int * ) ( b+ 4 ) ) goto ReturnFalse;
454
+ if ( * ( int * ) ( a+ 6 ) != * ( int * ) ( b+ 6 ) ) goto ReturnFalse;
455
+ if ( * ( int * ) ( a+ 8 ) != * ( int * ) ( b+ 8 ) ) goto ReturnFalse;
456
+ length -= 10 ; a += 10 ; b += 10 ;
457
+ }
458
+ #endif
459
+
460
+ while ( length > = 2 )
461
+ {
462
+ if ( * ( int * ) a != * ( int * ) b) goto ReturnFalse;
463
+ length -= 2 ; a += 2 ; b += 2 ;
464
+ }
465
+
466
+ // PERF: This depends on the fact that the String objects are always zero terminated
467
+ // and that the terminating zero is not included in the length. For even string sizes
468
+ // this compare can include the zero terminator. Bitwise OR avoids a branch.
469
+ return length == 0 | * a == * b;
470
+
471
+ ReturnFalse :
472
+ return false;
473
+ }
474
+ }
475
+
415
476
[ System . Security . SecuritySafeCritical ] // auto-generated
416
477
private unsafe static int CompareOrdinalHelper ( String strA , String strB )
417
478
{
@@ -453,9 +514,9 @@ private unsafe static int CompareOrdinalHelper(String strA, String strB)
453
514
diffOffset = 8 ;
454
515
break ;
455
516
}
517
+ length -= 10 ;
456
518
a += 10 ;
457
519
b += 10 ;
458
- length -= 10 ;
459
520
}
460
521
461
522
if ( diffOffset ! = - 1 ) {
@@ -479,9 +540,9 @@ private unsafe static int CompareOrdinalHelper(String strA, String strB)
479
540
if ( * ( int * ) a != * ( int * ) b) {
480
541
break ;
481
542
}
543
+ length -= 2 ;
482
544
a += 2 ;
483
545
b += 2 ;
484
- length -= 2 ;
485
546
}
486
547
487
548
if ( length > 0 ) {
@@ -2559,7 +2620,7 @@ public Boolean StartsWith(String value, StringComparison comparisonType) {
2559
2620
}
2560
2621
return ( value. Length == 1 ) ?
2561
2622
true : // First char is the same and thats all there is to compare
2562
- ( nativeCompareOrdinalEx ( this , 0 , value, 0 , value . Length ) == 0 ) ;
2623
+ StartsWithOrdinalHelper ( this , value) ;
2563
2624
2564
2625
case StringComparison. OrdinalIgnoreCase:
2565
2626
if ( this . Length < value. Length) {
0 commit comments