Removed JIT (uint) cast workaround to elide bound-checks in CoreLib (#67448)
authorGünther Foidl <gue@korporal.at>
Tue, 12 Jul 2022 17:54:20 +0000 (19:54 +0200)
committerGitHub <noreply@github.com>
Tue, 12 Jul 2022 17:54:20 +0000 (10:54 -0700)
* Removed (uint) cast workaround in CoreLib, annotated missing places with TODOs

* Fixed the bug I introduced in TimeSpanParse.TimeSpanTokenizer

* Use uint-cast on both sided for clarity

Cf. https://github.com/dotnet/runtime/pull/67448#discussion_r841082992

* Use uint-division in BitHelper as the JIT can produce more efficient code

Cf. https://github.com/dotnet/runtime/pull/67448#discussion_r841239729

* Don't have struct local in ValueStringBuilder due to hitting JIT optimization limits

Cf. https://github.com/dotnet/runtime/pull/67448#discussion_r841129465

* BitHelper with uint division and without Math.DivRem for even better codegen

AggressiveInlining isn't needed anymore, also the JIT recognizes the _span field, so no local Span is needed here.

* BitHelper needs local Span due to regression in jit-diff otherwise

* Added Debug.Asserts to BitHelper's method that take bitPosition

* BitHelper: comment for workaround to tracking issue

15 files changed:
src/libraries/Common/src/System/Collections/Generic/BitHelper.cs
src/libraries/System.Private.CoreLib/src/System/Boolean.cs
src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.cs
src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Boolean.cs
src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs
src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs
src/libraries/System.Private.CoreLib/src/System/Char.cs
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ValueListBuilder.cs
src/libraries/System.Private.CoreLib/src/System/Decimal.cs
src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs
src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs
src/libraries/System.Private.CoreLib/src/System/Guid.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/DefaultInterpolatedStringHandler.cs
src/libraries/System.Private.CoreLib/src/System/Text/Rune.cs
src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs

index 01f0c1c..05f353b 100644 (file)
@@ -1,6 +1,8 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System.Diagnostics;
+
 namespace System.Collections.Generic
 {
     internal ref struct BitHelper
@@ -19,19 +21,29 @@ namespace System.Collections.Generic
 
         internal void MarkBit(int bitPosition)
         {
-            int bitArrayIndex = bitPosition / IntSize;
-            if ((uint)bitArrayIndex < (uint)_span.Length)
+            Debug.Assert(bitPosition >= 0);
+
+            uint bitArrayIndex = (uint)bitPosition / IntSize;
+
+            // Workaround for https://github.com/dotnet/runtime/issues/72004
+            Span<int> span = _span;
+            if (bitArrayIndex < (uint)span.Length)
             {
-                _span[bitArrayIndex] |= (1 << (bitPosition % IntSize));
+                span[(int)bitArrayIndex] |= (1 << (int)((uint)bitPosition % IntSize));
             }
         }
 
         internal bool IsMarked(int bitPosition)
         {
-            int bitArrayIndex = bitPosition / IntSize;
+            Debug.Assert(bitPosition >= 0);
+
+            uint bitArrayIndex = (uint)bitPosition / IntSize;
+
+            // Workaround for https://github.com/dotnet/runtime/issues/72004
+            Span<int> span = _span;
             return
-                (uint)bitArrayIndex < (uint)_span.Length &&
-                (_span[bitArrayIndex] & (1 << (bitPosition % IntSize))) != 0;
+                bitArrayIndex < (uint)span.Length &&
+                (span[(int)bitArrayIndex] & (1 << ((int)((uint)bitPosition % IntSize)))) != 0;
         }
 
         /// <summary>How many ints must be allocated to represent n bits. Returns (n+31)/32, but avoids overflow.</summary>
index 722b1b6..885e1db 100644 (file)
@@ -99,7 +99,7 @@ namespace System
         {
             if (m_value)
             {
-                if ((uint)destination.Length > 3) // uint cast, per https://github.com/dotnet/runtime/issues/10596
+                if (destination.Length > 3)
                 {
                     ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
                     MemoryMarshal.Write<ulong>(MemoryMarshal.AsBytes(destination), ref true_val);
@@ -109,7 +109,7 @@ namespace System
             }
             else
             {
-                if ((uint)destination.Length > 4)
+                if (destination.Length > 4)
                 {
                     ulong fals_val = BitConverter.IsLittleEndian ? 0x73006C00610046ul : 0x460061006C0073ul; // "Fals"
                     MemoryMarshal.Write<ulong>(MemoryMarshal.AsBytes(destination), ref fals_val);
index 1ad5884..784b08c 100644 (file)
@@ -164,8 +164,7 @@ namespace System.Buffers
             int count = 0;
             char symbol = Symbol;
 
-            if (symbol != default &&
-                (uint)destination.Length == FormatStringLength) // to eliminate bounds checks
+            if (symbol != default && destination.Length == FormatStringLength)
             {
                 destination[0] = symbol;
                 count = 1;
index b23cc3a..220a493 100644 (file)
@@ -65,7 +65,7 @@ namespace System.Buffers.Text
                 {
                     // This check can't be performed earlier because we need to throw if an invalid symbol is
                     // provided, even if the buffer is too small.
-                    if ((uint)4 >= (uint)destination.Length)
+                    if (destination.Length <= 4)
                     {
                         goto BufferTooSmall;
                     }
@@ -75,7 +75,7 @@ namespace System.Buffers.Text
                 }
                 else if (symbol == 'l')
                 {
-                    if ((uint)4 >= (uint)destination.Length)
+                    if (destination.Length <= 4)
                     {
                         goto BufferTooSmall;
                     }
index 0f20a2a..6d4dc61 100644 (file)
@@ -13,9 +13,7 @@ namespace System.Buffers.Text
         //
         private static bool TryFormatDateTimeL(DateTime value, Span<byte> destination, out int bytesWritten)
         {
-            // Writing the check in this fashion elides all bounds checks on 'buffer'
-            // for the remainder of the method.
-            if ((uint)28 >= (uint)destination.Length)
+            if (destination.Length <= 28)
             {
                 bytesWritten = 0;
                 return false;
index 9c9738d..d80b27c 100644 (file)
@@ -13,9 +13,7 @@ namespace System.Buffers.Text
         //
         private static bool TryFormatDateTimeR(DateTime value, Span<byte> destination, out int bytesWritten)
         {
-            // Writing the check in this fashion elides all bounds checks on 'buffer'
-            // for the remainder of the method.
-            if ((uint)28 >= (uint)destination.Length)
+            if (destination.Length <= 28)
             {
                 bytesWritten = 0;
                 return false;
index 3741919..e6d39ce 100644 (file)
@@ -591,7 +591,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -606,7 +606,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -626,7 +626,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -647,7 +647,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -667,8 +667,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -710,7 +709,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -743,7 +742,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -788,7 +787,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -813,7 +812,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -845,7 +844,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -865,7 +864,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -885,7 +884,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -911,7 +910,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -935,7 +934,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -957,7 +956,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -979,7 +978,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
@@ -996,7 +995,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
             }
-            if (((uint)index) >= ((uint)s.Length))
+            if ((uint)index >= (uint)s.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
             }
index 71ccb1b..51dcd6a 100644 (file)
@@ -44,9 +44,12 @@ namespace System.Collections.Generic
         public void Append(T item)
         {
             int pos = _pos;
-            if ((uint)pos < (uint)_span.Length)
+
+            // Workaround for https://github.com/dotnet/runtime/issues/72004
+            Span<T> span = _span;
+            if ((uint)pos < (uint)span.Length)
             {
-                _span[pos] = item;
+                span[pos] = item;
                 _pos = pos + 1;
             }
             else
index 49d2c3e..5436bae 100644 (file)
@@ -602,7 +602,7 @@ namespace System
         /// <exception cref="ArgumentException">The destination span was not long enough to store the binary representation.</exception>
         public static int GetBits(decimal d, Span<int> destination)
         {
-            if ((uint)destination.Length <= 3)
+            if (destination.Length <= 3)
             {
                 ThrowHelper.ThrowArgumentException_DestinationTooShort();
             }
@@ -623,7 +623,7 @@ namespace System
         /// <returns>true if the decimal's binary representation was written to the destination; false if the destination wasn't long enough.</returns>
         public static bool TryGetBits(decimal d, Span<int> destination, out int valuesWritten)
         {
-            if ((uint)destination.Length <= 3)
+            if (destination.Length <= 3)
             {
                 valuesWritten = 0;
                 return false;
index 15bfe71..3b0876c 100644 (file)
@@ -4663,7 +4663,7 @@ new DS[] { DS.ERROR,  DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             // Tue, 03 Jan 2017 08:08:05 GMT
 
             // The format is exactly 29 characters.
-            if ((uint)source.Length != 29)
+            if (source.Length != 29)
             {
                 result.SetBadDateTimeFailure();
                 return false;
@@ -4860,7 +4860,7 @@ new DS[] { DS.ERROR,  DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             // 2017-06-12T05:30:45.7680000-7:00   (special-case of one-digit offset hour)
             // 2017-06-12T05:30:45.7680000-07:00
 
-            if ((uint)source.Length < 27 ||
+            if (source.Length < 27 ||
                 source[4] != '-' ||
                 source[7] != '-' ||
                 source[10] != 'T' ||
@@ -4981,7 +4981,7 @@ new DS[] { DS.ERROR,  DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 return false;
             }
 
-            if ((uint)source.Length > 27)
+            if (source.Length > 27)
             {
                 char offsetChar = source[27];
                 switch (offsetChar)
@@ -4999,7 +4999,7 @@ new DS[] { DS.ERROR,  DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     case '-':
                         int offsetHours, colonIndex;
 
-                        if ((uint)source.Length == 33)
+                        if (source.Length == 33)
                         {
                             uint oh1 = (uint)(source[28] - '0'), oh2 = (uint)(source[29] - '0');
 
@@ -5012,7 +5012,7 @@ new DS[] { DS.ERROR,  DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             offsetHours = (int)(oh1 * 10 + oh2);
                             colonIndex = 30;
                         }
-                        else if ((uint)source.Length == 32) // special-case allowed for compat: only one offset hour digit
+                        else if (source.Length == 32) // special-case allowed for compat: only one offset hour digit
                         {
                             offsetHours = source[28] - '0';
 
index 362d803..729302e 100644 (file)
@@ -169,15 +169,17 @@ namespace System.Globalization
             {
                 // Get the position of the next character to be processed.  If there is no
                 // next character, we're at the end.
-                int pos = _pos;
+                int startPos = _pos;
+                int pos = startPos;
+                ReadOnlySpan<char> value = _value;
                 Debug.Assert(pos > -1);
-                if (pos >= _value.Length)
+                if ((uint)pos >= (uint)value.Length)
                 {
                     return new TimeSpanToken(TTT.End);
                 }
 
                 // Now retrieve that character. If it's a digit, we're processing a number.
-                int num = _value[pos] - '0';
+                int num = value[pos] - '0';
                 if ((uint)num <= 9)
                 {
                     int zeroes = 0;
@@ -188,8 +190,9 @@ namespace System.Globalization
                         while (true)
                         {
                             int digit;
-                            if (++_pos >= _value.Length || (uint)(digit = _value[_pos] - '0') > 9)
+                            if ((uint)++pos >= (uint)value.Length || (uint)(digit = value[pos] - '0') > 9)
                             {
+                                _pos = pos;
                                 return new TimeSpanToken(TTT.Num, 0, zeroes, default);
                             }
 
@@ -202,12 +205,14 @@ namespace System.Globalization
                             num = digit;
                             break;
                         }
+
+                        _pos = pos;
                     }
 
                     // Continue to read as long as we're reading digits.
-                    while (++_pos < _value.Length)
+                    while ((uint)++pos < (uint)value.Length)
                     {
-                        int digit = _value[_pos] - '0';
+                        int digit = value[pos] - '0';
                         if ((uint)digit > 9)
                         {
                             break;
@@ -216,27 +221,26 @@ namespace System.Globalization
                         num = num * 10 + digit;
                         if ((num & 0xF0000000) != 0) // Max limit we can support 268435455 which is FFFFFFF
                         {
+                            _pos = pos;
                             return new TimeSpanToken(TTT.NumOverflow);
                         }
                     }
 
+                    _pos = pos;
                     return new TimeSpanToken(TTT.Num, num, zeroes, default);
                 }
 
                 // Otherwise, we're processing a separator, and we've already processed the first
                 // character of it.  Continue processing characters as long as they're not digits.
                 int length = 1;
-                while (true)
+                while ((uint)++pos < (uint)value.Length && !char.IsAsciiDigit(value[pos]))
                 {
-                    if (++_pos >= _value.Length || char.IsAsciiDigit(_value[_pos]))
-                    {
-                        break;
-                    }
                     length++;
                 }
+                _pos = pos;
 
                 // Return the separator.
-                return new TimeSpanToken(TTT.Sep, 0, 0, _value.Slice(pos, length));
+                return new TimeSpanToken(TTT.Sep, 0, 0, _value.Slice(startPos, length));
             }
 
             internal bool EOL => _pos >= (_value.Length - 1);
@@ -249,7 +253,7 @@ namespace System.Globalization
             internal char NextChar()
             {
                 int pos = ++_pos;
-                return (uint)pos < (uint)_value.Length?
+                return (uint)pos < (uint)_value.Length ?
                     _value[pos] :
                     (char)0;
             }
index f7c74fb..ea1e5df 100644 (file)
@@ -48,7 +48,7 @@ namespace System
         // Creates a new guid from a read-only span.
         public Guid(ReadOnlySpan<byte> b)
         {
-            if ((uint)b.Length != 16)
+            if (b.Length != 16)
             {
                 throw new ArgumentException(SR.Format(SR.Arg_GuidArrayCtor, "16"), nameof(b));
             }
@@ -378,7 +378,7 @@ namespace System
         {
             // e.g. "{d85b1407-351d-4694-9392-03acc5870eb1}"
 
-            if ((uint)guidString.Length != 38 || guidString[0] != '{' || guidString[37] != '}')
+            if (guidString.Length != 38 || guidString[0] != '{' || guidString[37] != '}')
             {
                 result.SetFailure(overflow: false, nameof(SR.Format_GuidInvLen));
                 return false;
@@ -391,7 +391,7 @@ namespace System
         {
             // e.g. "d85b1407-351d-4694-9392-03acc5870eb1"
 
-            if ((uint)guidString.Length != 36 || guidString[8] != '-' || guidString[13] != '-' || guidString[18] != '-' || guidString[23] != '-')
+            if (guidString.Length != 36 || guidString[8] != '-' || guidString[13] != '-' || guidString[18] != '-' || guidString[23] != '-')
             {
                 result.SetFailure(overflow: false, guidString.Length != 36 ? nameof(SR.Format_GuidInvLen) : nameof(SR.Format_GuidDashes));
                 return false;
@@ -477,7 +477,7 @@ namespace System
         {
             // e.g. "d85b1407351d4694939203acc5870eb1"
 
-            if ((uint)guidString.Length != 32)
+            if (guidString.Length != 32)
             {
                 result.SetFailure(overflow: false, nameof(SR.Format_GuidInvLen));
                 return false;
@@ -520,7 +520,7 @@ namespace System
         {
             // e.g. "(d85b1407-351d-4694-9392-03acc5870eb1)"
 
-            if ((uint)guidString.Length != 38 || guidString[0] != '(' || guidString[37] != ')')
+            if (guidString.Length != 38 || guidString[0] != '(' || guidString[37] != ')')
             {
                 result.SetFailure(overflow: false, nameof(SR.Format_GuidInvLen));
                 return false;
@@ -547,7 +547,7 @@ namespace System
             guidString = EatAllWhitespace(guidString);
 
             // Check for leading '{'
-            if ((uint)guidString.Length == 0 || guidString[0] != '{')
+            if (guidString.Length == 0 || guidString[0] != '{')
             {
                 result.SetFailure(overflow: false, nameof(SR.Format_GuidBrace));
                 return false;
@@ -735,14 +735,14 @@ namespace System
 
         private static bool TryParseHex(ReadOnlySpan<char> guidString, out uint result, ref bool overflow)
         {
-            if ((uint)guidString.Length > 0)
+            if (guidString.Length > 0)
             {
                 if (guidString[0] == '+')
                 {
                     guidString = guidString.Slice(1);
                 }
 
-                if ((uint)guidString.Length > 1 && guidString[0] == '0' && (guidString[1] | 0x20) == 'x')
+                if (guidString.Length > 1 && guidString[0] == '0' && (guidString[1] | 0x20) == 'x')
                 {
                     guidString = guidString.Slice(2);
                 }
index 8e441b6..3b46f19 100644 (file)
@@ -154,8 +154,8 @@ namespace System.Runtime.CompilerServices
 
             if (value.Length == 1)
             {
-                Span<char> chars = _chars;
                 int pos = _pos;
+                Span<char> chars = _chars;
                 if ((uint)pos < (uint)chars.Length)
                 {
                     chars[pos] = value[0];
@@ -170,12 +170,11 @@ namespace System.Runtime.CompilerServices
 
             if (value.Length == 2)
             {
-                Span<char> chars = _chars;
                 int pos = _pos;
-                if ((uint)pos < chars.Length - 1)
+                if ((uint)pos < _chars.Length - 1)
                 {
                     Unsafe.WriteUnaligned(
-                        ref Unsafe.As<char, byte>(ref Unsafe.Add(ref MemoryMarshal.GetReference(chars), pos)),
+                        ref Unsafe.As<char, byte>(ref Unsafe.Add(ref MemoryMarshal.GetReference(_chars), pos)),
                         Unsafe.ReadUnaligned<int>(ref Unsafe.As<char, byte>(ref value.GetRawStringData())));
                     _pos = pos + 2;
                 }
index 1cd73a5..182863b 100644 (file)
@@ -842,7 +842,7 @@ namespace System.Text
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
             }
 
-            if ((uint)index >= (uint)input!.Length)
+            if ((uint)index >= (uint)input.Length)
             {
                 ThrowHelper.ThrowArgumentOutOfRange_IndexMustBeLessException();
             }
@@ -1019,7 +1019,7 @@ namespace System.Text
                     charsWritten = 1;
                     return true;
                 }
-                else if (1 < (uint)destination.Length)
+                else if (destination.Length > 1)
                 {
                     UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar((uint)value._value, out destination[0], out destination[1]);
                     charsWritten = 2;
@@ -1066,7 +1066,7 @@ namespace System.Text
                     return true;
                 }
 
-                if (1 < (uint)destination.Length)
+                if (destination.Length > 1)
                 {
                     if (value.Value <= 0x7FFu)
                     {
@@ -1077,7 +1077,7 @@ namespace System.Text
                         return true;
                     }
 
-                    if (2 < (uint)destination.Length)
+                    if (destination.Length > 2)
                     {
                         if (value.Value <= 0xFFFFu)
                         {
@@ -1089,7 +1089,7 @@ namespace System.Text
                             return true;
                         }
 
-                        if (3 < (uint)destination.Length)
+                        if (destination.Length > 3)
                         {
                             // Scalar 000uuuuu zzzzyyyy yyxxxxxx -> bytes [ 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx ]
                             destination[0] = (byte)((value._value + (0b11110 << 21)) >> 18);
index 398bc70..956660f 100644 (file)
@@ -1052,10 +1052,10 @@ namespace System.Text
             int nextCharIndex = m_ChunkLength;
             char[] chars = m_ChunkChars;
 
-            if ((uint)chars.Length > (uint)nextCharIndex)
+            if ((uint)nextCharIndex < (uint)chars.Length)
             {
                 chars[nextCharIndex] = value;
-                m_ChunkLength++;
+                m_ChunkLength = nextCharIndex + 1;
             }
             else
             {