From 8209f50a8d6b660f904d13ea0206d93a9bd86d34 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Fri, 31 Jan 2025 21:54:14 +0100 Subject: [PATCH 1/2] Fix mono regressions in Number.Formatting.cs --- .../src/System/Number.Formatting.cs | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs index e22a12d24f6440..20486a83c9cbcb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -272,28 +272,28 @@ internal static partial class Number // Optimizations using "TwoDigits" inspired by: // https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c/ - private static ReadOnlySpan TwoDigitsCharsAsBytes => - MemoryMarshal.AsBytes("00010203040506070809" + - "10111213141516171819" + - "20212223242526272829" + - "30313233343536373839" + - "40414243444546474849" + - "50515253545556575859" + - "60616263646566676869" + - "70717273747576777879" + - "80818283848586878889" + - "90919293949596979899"); + private const string TwoDigitsChars = + "00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899"; private static ReadOnlySpan TwoDigitsBytes => - "00010203040506070809"u8 + - "10111213141516171819"u8 + - "20212223242526272829"u8 + - "30313233343536373839"u8 + - "40414243444546474849"u8 + - "50515253545556575859"u8 + - "60616263646566676869"u8 + - "70717273747576777879"u8 + - "80818283848586878889"u8 + - "90919293949596979899"u8; + "00010203040506070809"u8 + + "10111213141516171819"u8 + + "20212223242526272829"u8 + + "30313233343536373839"u8 + + "40414243444546474849"u8 + + "50515253545556575859"u8 + + "60616263646566676869"u8 + + "70717273747576777879"u8 + + "80818283848586878889"u8 + + "90919293949596979899"u8; public static unsafe string FormatDecimal(decimal value, ReadOnlySpan format, NumberFormatInfo info) { @@ -1564,16 +1564,19 @@ private static unsafe void UInt32ToNumber(uint value, ref NumberBuffer number) number.CheckConsistency(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref byte TwoDigitsRef() => ref typeof(TChar) == typeof(char) + ? ref Unsafe.As(ref TwoDigitsChars.GetRawStringData()) + : ref MemoryMarshal.GetReference(TwoDigitsBytes); + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static unsafe void WriteTwoDigits(uint value, TChar* ptr) where TChar : unmanaged, IUtfChar { Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); Debug.Assert(value <= 99); - Unsafe.CopyBlockUnaligned( - ref *(byte*)ptr, - ref Unsafe.Add(ref MemoryMarshal.GetReference(typeof(TChar) == typeof(char) ? TwoDigitsCharsAsBytes : TwoDigitsBytes), (uint)sizeof(TChar) * 2 * value), - (uint)sizeof(TChar) * 2); + ref byte valueRef = ref Unsafe.Add(ref TwoDigitsRef(), (nuint)sizeof(TChar) * 2 * value); + Unsafe.CopyBlockUnaligned(ref *(byte*)ptr, ref valueRef, (uint)sizeof(TChar) * 2); } /// @@ -1588,17 +1591,10 @@ internal static unsafe void WriteFourDigits(uint value, TChar* ptr) where (value, uint remainder) = Math.DivRem(value, 100); - ref byte charsArray = ref MemoryMarshal.GetReference(typeof(TChar) == typeof(char) ? TwoDigitsCharsAsBytes : TwoDigitsBytes); - - Unsafe.CopyBlockUnaligned( - ref *(byte*)ptr, - ref Unsafe.Add(ref charsArray, (uint)sizeof(TChar) * 2 * value), - (uint)sizeof(TChar) * 2); - - Unsafe.CopyBlockUnaligned( - ref *(byte*)(ptr + 2), - ref Unsafe.Add(ref charsArray, (uint)sizeof(TChar) * 2 * remainder), - (uint)sizeof(TChar) * 2); + ref byte valueRef1 = ref Unsafe.Add(ref TwoDigitsRef(), (nuint)sizeof(TChar) * 2 * value); + ref byte valueRef2 = ref Unsafe.Add(ref TwoDigitsRef(), (nuint)sizeof(TChar) * 2 * remainder); + Unsafe.CopyBlockUnaligned(ref *(byte*)(ptr + 0), ref valueRef1, (uint)sizeof(TChar) * 2); + Unsafe.CopyBlockUnaligned(ref *(byte*)(ptr + 2), ref valueRef2, (uint)sizeof(TChar) * 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From f9441f7a819de61f2d2cf663e2eaeae202ee84bf Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 1 Feb 2025 00:39:51 +0100 Subject: [PATCH 2/2] revert changes --- .../src/System/Number.Formatting.cs | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs index 20486a83c9cbcb..1fce5c50443666 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -272,28 +272,28 @@ internal static partial class Number // Optimizations using "TwoDigits" inspired by: // https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c/ - private const string TwoDigitsChars = - "00010203040506070809" + - "10111213141516171819" + - "20212223242526272829" + - "30313233343536373839" + - "40414243444546474849" + - "50515253545556575859" + - "60616263646566676869" + - "70717273747576777879" + - "80818283848586878889" + - "90919293949596979899"; - private static ReadOnlySpan TwoDigitsBytes => - "00010203040506070809"u8 + - "10111213141516171819"u8 + - "20212223242526272829"u8 + - "30313233343536373839"u8 + - "40414243444546474849"u8 + - "50515253545556575859"u8 + - "60616263646566676869"u8 + - "70717273747576777879"u8 + - "80818283848586878889"u8 + - "90919293949596979899"u8; + private static readonly byte[] TwoDigitsCharsAsBytes = + MemoryMarshal.AsBytes("00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899").ToArray(); + private static readonly byte[] TwoDigitsBytes = + ("00010203040506070809"u8 + + "10111213141516171819"u8 + + "20212223242526272829"u8 + + "30313233343536373839"u8 + + "40414243444546474849"u8 + + "50515253545556575859"u8 + + "60616263646566676869"u8 + + "70717273747576777879"u8 + + "80818283848586878889"u8 + + "90919293949596979899"u8).ToArray(); public static unsafe string FormatDecimal(decimal value, ReadOnlySpan format, NumberFormatInfo info) { @@ -1564,19 +1564,16 @@ private static unsafe void UInt32ToNumber(uint value, ref NumberBuffer number) number.CheckConsistency(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ref byte TwoDigitsRef() => ref typeof(TChar) == typeof(char) - ? ref Unsafe.As(ref TwoDigitsChars.GetRawStringData()) - : ref MemoryMarshal.GetReference(TwoDigitsBytes); - [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static unsafe void WriteTwoDigits(uint value, TChar* ptr) where TChar : unmanaged, IUtfChar { Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); Debug.Assert(value <= 99); - ref byte valueRef = ref Unsafe.Add(ref TwoDigitsRef(), (nuint)sizeof(TChar) * 2 * value); - Unsafe.CopyBlockUnaligned(ref *(byte*)ptr, ref valueRef, (uint)sizeof(TChar) * 2); + Unsafe.CopyBlockUnaligned( + ref *(byte*)ptr, + ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(typeof(TChar) == typeof(char) ? TwoDigitsCharsAsBytes : TwoDigitsBytes), (uint)sizeof(TChar) * 2 * value), + (uint)sizeof(TChar) * 2); } /// @@ -1591,10 +1588,16 @@ internal static unsafe void WriteFourDigits(uint value, TChar* ptr) where (value, uint remainder) = Math.DivRem(value, 100); - ref byte valueRef1 = ref Unsafe.Add(ref TwoDigitsRef(), (nuint)sizeof(TChar) * 2 * value); - ref byte valueRef2 = ref Unsafe.Add(ref TwoDigitsRef(), (nuint)sizeof(TChar) * 2 * remainder); - Unsafe.CopyBlockUnaligned(ref *(byte*)(ptr + 0), ref valueRef1, (uint)sizeof(TChar) * 2); - Unsafe.CopyBlockUnaligned(ref *(byte*)(ptr + 2), ref valueRef2, (uint)sizeof(TChar) * 2); + ref byte charsArray = ref MemoryMarshal.GetArrayDataReference(typeof(TChar) == typeof(char) ? TwoDigitsCharsAsBytes : TwoDigitsBytes); + + Unsafe.CopyBlockUnaligned( + ref *(byte*)ptr, + ref Unsafe.Add(ref charsArray, (uint)sizeof(TChar) * 2 * value), + (uint)sizeof(TChar) * 2); + Unsafe.CopyBlockUnaligned( + ref *(byte*)(ptr + 2), + ref Unsafe.Add(ref charsArray, (uint)sizeof(TChar) * 2 * remainder), + (uint)sizeof(TChar) * 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)]