@@ -425,28 +425,28 @@ public static unsafe int SequenceCompareTo(ref char first, int firstLength, ref
425
425
// IndexOfNullCharacter processes memory in aligned chunks, and thus it won't crash even if it accesses memory beyond the null terminator.
426
426
// This behavior is an implementation detail of the runtime and callers outside System.Private.CoreLib must not depend on it.
427
427
[ MethodImpl ( MethodImplOptions . AggressiveOptimization ) ]
428
- public static unsafe int IndexOfNullCharacter ( ref char searchSpace )
428
+ public static unsafe int IndexOfNullCharacter ( char * searchSpace )
429
429
{
430
430
const char value = '\0 ' ;
431
431
const int length = int . MaxValue ;
432
432
433
433
nint offset = 0 ;
434
434
nint lengthToExamine = length ;
435
435
436
- if ( ( ( int ) Unsafe . AsPointer ( ref searchSpace ) & 1 ) != 0 )
436
+ if ( ( ( int ) searchSpace & 1 ) != 0 )
437
437
{
438
438
// Input isn't char aligned, we won't be able to align it to a Vector
439
439
}
440
440
else if ( Vector128 . IsHardwareAccelerated )
441
441
{
442
442
// Avx2 branch also operates on Sse2 sizes, so check is combined.
443
443
// Needs to be double length to allow us to align the data first.
444
- lengthToExamine = UnalignedCountVector128 ( ref searchSpace ) ;
444
+ lengthToExamine = UnalignedCountVector128 ( searchSpace ) ;
445
445
}
446
446
else if ( Vector . IsHardwareAccelerated )
447
447
{
448
448
// Needs to be double length to allow us to align the data first.
449
- lengthToExamine = UnalignedCountVector ( ref searchSpace ) ;
449
+ lengthToExamine = UnalignedCountVector ( searchSpace ) ;
450
450
}
451
451
452
452
SequentialScan :
@@ -456,15 +456,13 @@ public static unsafe int IndexOfNullCharacter(ref char searchSpace)
456
456
// remaining data that is shorter than a Vector length.
457
457
while ( lengthToExamine >= 4 )
458
458
{
459
- ref char current = ref Unsafe . Add ( ref searchSpace , offset ) ;
460
-
461
- if ( value == current )
459
+ if ( value == searchSpace [ offset ] )
462
460
goto Found ;
463
- if ( value == Unsafe . Add ( ref current , 1 ) )
461
+ if ( value == searchSpace [ offset + 1 ] )
464
462
goto Found1 ;
465
- if ( value == Unsafe . Add ( ref current , 2 ) )
463
+ if ( value == searchSpace [ offset + 2 ] )
466
464
goto Found2 ;
467
- if ( value == Unsafe . Add ( ref current , 3 ) )
465
+ if ( value == searchSpace [ offset + 3 ] )
468
466
goto Found3 ;
469
467
470
468
offset += 4 ;
@@ -473,7 +471,7 @@ public static unsafe int IndexOfNullCharacter(ref char searchSpace)
473
471
474
472
while ( lengthToExamine > 0 )
475
473
{
476
- if ( value == Unsafe . Add ( ref searchSpace , offset ) )
474
+ if ( value == searchSpace [ offset ] )
477
475
goto Found ;
478
476
479
477
offset ++ ;
@@ -487,25 +485,19 @@ public static unsafe int IndexOfNullCharacter(ref char searchSpace)
487
485
if ( offset < length )
488
486
{
489
487
Debug . Assert ( length - offset >= Vector128 < ushort > . Count ) ;
490
- ref ushort ushortSearchSpace = ref Unsafe . As < char , ushort > ( ref searchSpace ) ;
491
- if ( ( ( nint ) Unsafe . AsPointer ( ref Unsafe . Add ( ref searchSpace , ( nint ) offset ) ) & ( nint ) ( Vector256 < byte > . Count - 1 ) ) != 0 )
488
+ if ( ( ( nint ) ( searchSpace + ( nint ) offset ) & ( nint ) ( Vector256 < byte > . Count - 1 ) ) != 0 )
492
489
{
493
490
// Not currently aligned to Vector256 (is aligned to Vector128); this can cause a problem for searches
494
491
// with no upper bound e.g. String.wcslen. Start with a check on Vector128 to align to Vector256,
495
492
// before moving to processing Vector256.
496
493
497
- // If the input searchSpan has been fixed or pinned, this ensures we do not fault across memory pages
494
+ // This ensures we do not fault across memory pages
498
495
// while searching for an end of string. Specifically that this assumes that the length is either correct
499
496
// or that the data is pinned otherwise it may cause an AccessViolation from crossing a page boundary into an
500
497
// unowned page. If the search is unbounded (e.g. null terminator in wcslen) and the search value is not found,
501
498
// again this will likely cause an AccessViolation. However, correctly bounded searches will return -1 rather
502
499
// than ever causing an AV.
503
-
504
- // If the searchSpan has not been fixed or pinned the GC can relocate it during the execution of this
505
- // method, so the alignment only acts as best endeavour. The GC cost is likely to dominate over
506
- // the misalignment that may occur after; to we default to giving the GC a free hand to relocate and
507
- // its up to the caller whether they are operating over fixed data.
508
- Vector128 < ushort > search = Vector128 . LoadUnsafe ( ref ushortSearchSpace , ( nuint ) offset ) ;
500
+ Vector128 < ushort > search = * ( Vector128 < ushort > * ) ( searchSpace + ( nuint ) offset ) ;
509
501
510
502
// Same method as below
511
503
uint matches = Vector128 . Equals ( Vector128 < ushort > . Zero , search ) . AsByte ( ) . ExtractMostSignificantBits ( ) ;
@@ -528,7 +520,7 @@ public static unsafe int IndexOfNullCharacter(ref char searchSpace)
528
520
{
529
521
Debug . Assert ( lengthToExamine >= Vector256 < ushort > . Count ) ;
530
522
531
- Vector256 < ushort > search = Vector256 . LoadUnsafe ( ref ushortSearchSpace , ( nuint ) offset ) ;
523
+ Vector256 < ushort > search = * ( Vector256 < ushort > * ) ( searchSpace + ( nuint ) offset ) ;
532
524
uint matches = Vector256 . Equals ( Vector256 < ushort > . Zero , search ) . AsByte ( ) . ExtractMostSignificantBits ( ) ;
533
525
// Note that MoveMask has converted the equal vector elements into a set of bit flags,
534
526
// So the bit position in 'matches' corresponds to the element offset.
@@ -551,7 +543,7 @@ public static unsafe int IndexOfNullCharacter(ref char searchSpace)
551
543
{
552
544
Debug . Assert ( lengthToExamine >= Vector128 < ushort > . Count ) ;
553
545
554
- Vector128 < ushort > search = Vector128 . LoadUnsafe ( ref ushortSearchSpace , ( nuint ) offset ) ;
546
+ Vector128 < ushort > search = * ( Vector128 < ushort > * ) ( searchSpace + ( nuint ) offset ) ;
555
547
556
548
// Same method as above
557
549
uint matches = Vector128 . Equals ( Vector128 < ushort > . Zero , search ) . AsByte ( ) . ExtractMostSignificantBits ( ) ;
@@ -581,7 +573,6 @@ public static unsafe int IndexOfNullCharacter(ref char searchSpace)
581
573
if ( offset < length )
582
574
{
583
575
Debug . Assert ( length - offset >= Vector128 < ushort > . Count ) ;
584
- ref ushort ushortSearchSpace = ref Unsafe . As < char , ushort > ( ref searchSpace ) ;
585
576
586
577
lengthToExamine = GetCharVector128SpanLength ( offset , length ) ;
587
578
if ( lengthToExamine > 0 )
@@ -590,7 +581,7 @@ public static unsafe int IndexOfNullCharacter(ref char searchSpace)
590
581
{
591
582
Debug . Assert ( lengthToExamine >= Vector128 < ushort > . Count ) ;
592
583
593
- Vector128 < ushort > search = Vector128 . LoadUnsafe ( ref ushortSearchSpace , ( uint ) offset ) ;
584
+ Vector128 < ushort > search = * ( Vector128 < ushort > * ) ( searchSpace + ( nuint ) offset ) ;
594
585
595
586
// Same method as above
596
587
Vector128 < ushort > compareResult = Vector128 . Equals ( Vector128 < ushort > . Zero , search ) ;
@@ -630,7 +621,7 @@ public static unsafe int IndexOfNullCharacter(ref char searchSpace)
630
621
{
631
622
Debug . Assert ( lengthToExamine >= Vector < ushort > . Count ) ;
632
623
633
- var matches = Vector . Equals ( Vector < ushort > . Zero , LoadVector ( ref searchSpace , offset ) ) ;
624
+ var matches = Vector . Equals ( Vector < ushort > . Zero , * ( Vector < ushort > * ) ( searchSpace + ( nuint ) offset ) ) ;
634
625
if ( Vector < ushort > . Zero . Equals ( matches ) )
635
626
{
636
627
offset += Vector < ushort > . Count ;
@@ -708,28 +699,17 @@ private static nint GetCharVector256SpanLength(nint offset, nint length)
708
699
=> ( length - offset ) & ~ ( Vector256 < ushort > . Count - 1 ) ;
709
700
710
701
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
711
- private static unsafe nint UnalignedCountVector ( ref char searchSpace )
702
+ private static unsafe nint UnalignedCountVector ( char * searchSpace )
712
703
{
713
704
const int ElementsPerByte = sizeof ( ushort ) / sizeof ( byte ) ;
714
- // Figure out how many characters to read sequentially until we are vector aligned
715
- // This is equivalent to:
716
- // unaligned = ((int)pCh % sizeof(Vector<ushort>) / ElementsPerByte
717
- // length = (Vector<ushort>.Count - unaligned) % Vector<ushort>.Count
718
-
719
- // This alignment is only valid if the GC does not relocate; so we use ReadUnaligned to get the data.
720
- // If a GC does occur and alignment is lost, the GC cost will outweigh any gains from alignment so it
721
- // isn't too important to pin to maintain the alignment.
722
- return ( nint ) ( uint ) ( - ( int ) Unsafe . AsPointer ( ref searchSpace ) / ElementsPerByte ) & ( Vector < ushort > . Count - 1 ) ;
705
+ return ( nint ) ( uint ) ( - ( int ) searchSpace / ElementsPerByte ) & ( Vector < ushort > . Count - 1 ) ;
723
706
}
724
707
725
708
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
726
- private static unsafe nint UnalignedCountVector128 ( ref char searchSpace )
709
+ private static unsafe nint UnalignedCountVector128 ( char * searchSpace )
727
710
{
728
711
const int ElementsPerByte = sizeof ( ushort ) / sizeof ( byte ) ;
729
- // This alignment is only valid if the GC does not relocate; so we use ReadUnaligned to get the data.
730
- // If a GC does occur and alignment is lost, the GC cost will outweigh any gains from alignment so it
731
- // isn't too important to pin to maintain the alignment.
732
- return ( nint ) ( uint ) ( - ( int ) Unsafe . AsPointer ( ref searchSpace ) / ElementsPerByte ) & ( Vector128 < ushort > . Count - 1 ) ;
712
+ return ( nint ) ( uint ) ( - ( int ) searchSpace / ElementsPerByte ) & ( Vector128 < ushort > . Count - 1 ) ;
733
713
}
734
714
735
715
public static void Reverse ( ref char buf , nuint length )
0 commit comments