From a109206f1c3cf59961e8519115960f5e8d955f3c Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:30:12 +0000 Subject: [PATCH] Use early zero-extension --- .../src/System/ReadOnlySpan.cs | 34 +++++++++++++------ .../System.Private.CoreLib/src/System/Span.cs | 34 +++++++++++++------ 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs index 1402f8d2a3e4e8..066474df645b34 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs @@ -62,23 +62,26 @@ public ReadOnlySpan(T[]? array) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan(T[]? array, int start, int length) { + // Early zero-extension + nint offset = (nint)(uint)start; + if (array == null) { - if (start != 0 || length != 0) + if ((int)offset != 0 || length != 0) ThrowHelper.ThrowArgumentOutOfRangeException(); this = default; return; // returns default } #if TARGET_64BIT // See comment in Span.Slice for how this works. - if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length) + if ((ulong)offset + (ulong)(uint)length > (ulong)(uint)array.Length) ThrowHelper.ThrowArgumentOutOfRangeException(); #else - if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) + if ((uint)offset > (uint)array.Length || (uint)length > (uint)array.Length - (uint)offset) ThrowHelper.ThrowArgumentOutOfRangeException(); #endif - _reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */); + _reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), offset); _length = length; } @@ -143,9 +146,12 @@ public ref readonly T this[int index] [NonVersionable] get { - if ((uint)index >= (uint)_length) + // Early zero-extension + nint offset = (nint)(uint)index; + + if ((uint)offset >= (uint)_length) ThrowHelper.ThrowIndexOutOfRangeException(); - return ref Unsafe.Add(ref _reference, (nint)(uint)index /* force zero-extension */); + return ref Unsafe.Add(ref _reference, offset); } } @@ -356,10 +362,13 @@ public override string ToString() [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan Slice(int start) { - if ((uint)start > (uint)_length) + // Early zero-extension + nint offset = (nint)(uint)start; + + if ((uint)offset > (uint)_length) ThrowHelper.ThrowArgumentOutOfRangeException(); - return new ReadOnlySpan(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), _length - start); + return new ReadOnlySpan(ref Unsafe.Add(ref _reference, offset), _length - start); } /// @@ -373,16 +382,19 @@ public ReadOnlySpan Slice(int start) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan Slice(int start, int length) { + // Early zero-extension + nint offset = (nint)(uint)start; + #if TARGET_64BIT // See comment in Span.Slice for how this works. - if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length) + if ((ulong)offset + (ulong)(uint)length > (ulong)(uint)_length) ThrowHelper.ThrowArgumentOutOfRangeException(); #else - if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) + if ((uint)offset > (uint)_length || (uint)length > (uint)_length - (uint)offset) ThrowHelper.ThrowArgumentOutOfRangeException(); #endif - return new ReadOnlySpan(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), length); + return new ReadOnlySpan(ref Unsafe.Add(ref _reference, offset), length); } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Span.cs b/src/libraries/System.Private.CoreLib/src/System/Span.cs index 92b90b82910e42..3261b3be182267 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Span.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Span.cs @@ -65,9 +65,12 @@ public Span(T[]? array) [MethodImpl(MethodImplOptions.AggressiveInlining)] public Span(T[]? array, int start, int length) { + // Early zero-extension + nint offset = (nint)(uint)start; + if (array == null) { - if (start != 0 || length != 0) + if ((int)offset != 0 || length != 0) ThrowHelper.ThrowArgumentOutOfRangeException(); this = default; return; // returns default @@ -76,14 +79,14 @@ public Span(T[]? array, int start, int length) ThrowHelper.ThrowArrayTypeMismatchException(); #if TARGET_64BIT // See comment in Span.Slice for how this works. - if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length) + if ((ulong)offset + (ulong)(uint)length > (ulong)(uint)array.Length) ThrowHelper.ThrowArgumentOutOfRangeException(); #else - if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) + if ((uint)offset > (uint)array.Length || (uint)length > (uint)array.Length - (uint)offset) ThrowHelper.ThrowArgumentOutOfRangeException(); #endif - _reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */); + _reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), offset); _length = length; } @@ -148,9 +151,12 @@ public ref T this[int index] [NonVersionable] get { - if ((uint)index >= (uint)_length) + // Early zero-extension + nint offset = (nint)(uint)index; + + if ((uint)offset >= (uint)_length) ThrowHelper.ThrowIndexOutOfRangeException(); - return ref Unsafe.Add(ref _reference, (nint)(uint)index /* force zero-extension */); + return ref Unsafe.Add(ref _reference, offset); } } @@ -380,10 +386,13 @@ public override string ToString() [MethodImpl(MethodImplOptions.AggressiveInlining)] public Span Slice(int start) { - if ((uint)start > (uint)_length) + // Early zero-extension + nint offset = (nint)(uint)start; + + if ((uint)offset > (uint)_length) ThrowHelper.ThrowArgumentOutOfRangeException(); - return new Span(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), _length - start); + return new Span(ref Unsafe.Add(ref _reference, offset), _length - start); } /// @@ -397,6 +406,9 @@ public Span Slice(int start) [MethodImpl(MethodImplOptions.AggressiveInlining)] public Span Slice(int start, int length) { + // Early zero-extension + nint offset = (nint)(uint)start; + #if TARGET_64BIT // Since start and length are both 32-bit, their sum can be computed across a 64-bit domain // without loss of fidelity. The cast to uint before the cast to ulong ensures that the @@ -404,14 +416,14 @@ public Span Slice(int start, int length) // of this is that if either input is negative or if the input sum overflows past Int32.MaxValue, // that information is captured correctly in the comparison against the backing _length field. // We don't use this same mechanism in a 32-bit process due to the overhead of 64-bit arithmetic. - if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length) + if ((ulong)offset + (ulong)(uint)length > (ulong)(uint)_length) ThrowHelper.ThrowArgumentOutOfRangeException(); #else - if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) + if ((uint)offset > (uint)_length || (uint)length > (uint)_length - (uint)offset) ThrowHelper.ThrowArgumentOutOfRangeException(); #endif - return new Span(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), length); + return new Span(ref Unsafe.Add(ref _reference, offset), length); } ///