@@ -451,7 +451,8 @@ public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out
451451 while ( s . Length != 0 )
452452 {
453453 var index = _searcher . IndexOfAnyExcept ( s ) ;
454- if ( index >= 0 )
454+
455+ if ( ( uint ) index < ( uint ) s . Length )
455456 {
456457 count += index ;
457458
@@ -461,13 +462,21 @@ public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out
461462 index ++ ;
462463 count ++ ;
463464
464- Debug . Assert ( ( uint ) index <= ( uint ) s . Length ) ;
465-
466- s = MemoryMarshal . CreateReadOnlySpan (
467- ref Unsafe . Add ( ref MemoryMarshal . GetReference ( s ) , ( nint ) ( uint ) index ) ,
468- s . Length - index ) ;
465+ // At this point, "index" is guaranteed to be within [0..s.Length].
466+ // While the Slice method performs its own bounds check and would throw if out of range,
467+ // our explicit check helps the JIT recognize that the call to Slice is safe.
468+ // This allows the JIT to eliminate the internal bounds check
469+ // and avoid generating unnecessary exception-handling code inside Slice.
470+ //
471+ // In other words, the check would happen anyway, but by placing it here explicitly,
472+ // we eliminate the need for exception code inside Slice itself.
473+ //
474+ // Even though logically (uint)index < (uint)s.Length implies (uint)index <= (uint)s.Length,
475+ // the JIT cannot currently prove this identity and therefore cannot optimize away
476+ // the redundant check in Slice.
469477
470- // s = s.Slice(index);
478+ if ( ( uint ) index <= ( uint ) s . Length )
479+ s = s . Slice ( index ) ;
471480 }
472481 else
473482 {
@@ -535,7 +544,7 @@ public override bool TryParse(ref ParseContext context, out Unit value)
535544 while ( s . Length != 0 )
536545 {
537546 var index = _searcher . IndexOfAnyExcept ( s ) ;
538- if ( index >= 0 )
547+ if ( ( uint ) index < ( uint ) s . Length )
539548 {
540549 count += index ;
541550
@@ -545,13 +554,21 @@ public override bool TryParse(ref ParseContext context, out Unit value)
545554 index ++ ;
546555 count ++ ;
547556
548- Debug . Assert ( ( uint ) index <= ( uint ) s . Length ) ;
549-
550- s = MemoryMarshal . CreateReadOnlySpan (
551- ref Unsafe . Add ( ref MemoryMarshal . GetReference ( s ) , ( nint ) ( uint ) index ) ,
552- s . Length - index ) ;
557+ // At this point, "index" is guaranteed to be within [0..s.Length].
558+ // While the Slice method performs its own bounds check and would throw if out of range,
559+ // our explicit check helps the JIT recognize that the call to Slice is safe.
560+ // This allows the JIT to eliminate the internal bounds check
561+ // and avoid generating unnecessary exception-handling code inside Slice.
562+ //
563+ // In other words, the check would happen anyway, but by placing it here explicitly,
564+ // we eliminate the need for exception code inside Slice itself.
565+ //
566+ // Even though logically (uint)index < (uint)s.Length implies (uint)index <= (uint)s.Length,
567+ // the JIT cannot currently prove this identity and therefore cannot optimize away
568+ // the redundant check in Slice.
553569
554- // s = s.Slice(index);
570+ if ( ( uint ) index <= ( uint ) s . Length )
571+ s = s . Slice ( index ) ;
555572 }
556573 else
557574 {
0 commit comments