diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.net8.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.net8.cs
index 08f72de280193c..8bfa2da0c0986e 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.net8.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.net8.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Buffers;
+using System.Numerics;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
namespace System.Text.Json
{
@@ -12,14 +16,38 @@ internal static partial class JsonReaderHelper
/// https://tools.ietf.org/html/rfc8259
private static readonly SearchValues s_controlQuoteBackslash = SearchValues.Create(
// Any Control, < 32 (' ')
- "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F"u8 +
- // Quote
- "\""u8 +
- // Backslash
- "\\"u8);
+ "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009"u8 +
+ "\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013"u8 +
+ "\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D"u8 +
+ "\u001E\u001F\"\\"u8);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOfQuoteOrAnyControlOrBackSlash(this ReadOnlySpan span) =>
- span.IndexOfAny(s_controlQuoteBackslash);
+ public static int IndexOfQuoteOrAnyControlOrBackSlash(this ReadOnlySpan span)
+ {
+ // Fast path for " in the first 16 bytes
+ if (Vector128.IsHardwareAccelerated && span.Length >= 16)
+ {
+ ref byte ptr = ref MemoryMarshal.GetReference(span);
+ Vector128 matches = Vector128.Equals(Vector128.LoadUnsafe(ref ptr), Vector128.Create((byte)'"'));
+ if (AdvSimd.IsSupported)
+ {
+ // TODO: use Vector128.IndexOf for both AdvSimd and Sse2 once
+ ulong mask = AdvSimd.ShiftRightLogicalNarrowingLower(matches.AsUInt16(), 4).AsUInt64().ToScalar();
+ if (mask != 0)
+ {
+ return BitOperations.TrailingZeroCount(mask) >> 2;
+ }
+ }
+ else
+ {
+ uint mask = matches.ExtractMostSignificantBits();
+ if (mask != 0)
+ {
+ return BitOperations.TrailingZeroCount(mask);
+ }
+ }
+ }
+ return span.IndexOfAny(s_controlQuoteBackslash);
+ }
}
}