Skip to content

Commit ada0379

Browse files
authored
Switch JsonReaderHelper.IndexOfQuoteOrAnyControlOrBackSlash to use IndexOfAnyValues (#82789)
* Switch JsonReaderHelper.IndexOfQuoteOrAnyControlOrBackSlash to use IndexOfAnyValues * Remove aggressive inlining
1 parent 6ef2d07 commit ada0379

File tree

5 files changed

+64
-255
lines changed

5 files changed

+64
-255
lines changed

src/libraries/System.Text.Json/src/System.Text.Json.csproj

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,11 +348,14 @@ The System.Text.Json library is built-in as part of the shared framework in .NET
348348
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">
349349
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\StringSyntaxAttribute.cs" />
350350
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\RequiresDynamicCodeAttribute.cs" />
351-
<Compile Include="System\Text\Json\Reader\JsonReaderHelper.sn.cs" />
352351
</ItemGroup>
353352

354-
<ItemGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">
355-
<Compile Include="System\Text\Json\Reader\JsonReaderHelper.sri.cs" />
353+
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
354+
<Compile Include="System\Text\Json\Reader\JsonReaderHelper.netstandard.cs" />
355+
</ItemGroup>
356+
357+
<ItemGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
358+
<Compile Include="System\Text\Json\Reader\JsonReaderHelper.net8.cs" />
356359
</ItemGroup>
357360

358361
<!-- Application tfms (.NETCoreApp, .NETFramework) need to use the same or higher version of .NETStandard's dependencies. -->

src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,6 @@ public static bool IsTokenTypePrimitive(JsonTokenType tokenType) =>
7777
// Otherwise, return false.
7878
public static bool IsHexDigit(byte nextByte) => HexConverter.IsHexChar(nextByte);
7979

80-
// https://tools.ietf.org/html/rfc8259
81-
// Does the span contain '"', '\', or any control characters (i.e. 0 to 31)
82-
// IndexOfAny(34, 92, < 32)
83-
// Borrowed and modified from SpanHelpers.Byte:
84-
// https://github.com/dotnet/corefx/blob/fc169cddedb6820aaabbdb8b7bece2a3df0fd1a5/src/Common/src/CoreLib/System/SpanHelpers.Byte.cs#L473-L604
85-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
86-
public static int IndexOfQuoteOrAnyControlOrBackSlash(this ReadOnlySpan<byte> span)
87-
{
88-
return IndexOfOrLessThan(
89-
ref MemoryMarshal.GetReference(span),
90-
JsonConstants.Quote,
91-
JsonConstants.BackSlash,
92-
lessThan: 32, // Space ' '
93-
span.Length);
94-
}
95-
9680
public static bool TryGetEscapedDateTime(ReadOnlySpan<byte> source, out DateTime value)
9781
{
9882
Debug.Assert(source.Length <= JsonConstants.MaximumEscapedDateTimeOffsetParseLength);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Buffers;
5+
using System.Runtime.CompilerServices;
6+
7+
namespace System.Text.Json
8+
{
9+
internal static partial class JsonReaderHelper
10+
{
11+
/// <summary>'"', '\', or any control characters (i.e. 0 to 31).</summary>
12+
/// <remarks>https://tools.ietf.org/html/rfc8259</remarks>
13+
private static readonly IndexOfAnyValues<byte> s_controlQuoteBackslash = IndexOfAnyValues.Create(
14+
// Any Control, < 32 (' ')
15+
"\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 +
16+
// Quote
17+
"\""u8 +
18+
// Backslash
19+
"\\"u8);
20+
21+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
22+
public static int IndexOfQuoteOrAnyControlOrBackSlash(this ReadOnlySpan<byte> span) =>
23+
span.IndexOfAny(s_controlQuoteBackslash);
24+
}
25+
}

src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.sn.cs renamed to src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.netstandard.cs

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,31 @@
44
using System.Diagnostics;
55
using System.Numerics;
66
using System.Runtime.CompilerServices;
7+
using System.Runtime.InteropServices;
78

89
namespace System.Text.Json
910
{
1011
internal static partial class JsonReaderHelper
1112
{
12-
private static unsafe int IndexOfOrLessThan(ref byte searchSpace, byte value0, byte value1, byte lessThan, int length)
13+
/// <summary>IndexOfAny('"', '\', less than 32)</summary>
14+
/// <remarks>https://tools.ietf.org/html/rfc8259</remarks>
15+
public static unsafe int IndexOfQuoteOrAnyControlOrBackSlash(this ReadOnlySpan<byte> span)
1316
{
17+
// Borrowed and modified from SpanHelpers.Byte:
18+
// https://github.com/dotnet/corefx/blob/fc169cddedb6820aaabbdb8b7bece2a3df0fd1a5/src/Common/src/CoreLib/System/SpanHelpers.Byte.cs#L473-L604
19+
20+
ref byte searchSpace = ref MemoryMarshal.GetReference(span);
21+
int length = span.Length;
1422
Debug.Assert(length >= 0);
1523

16-
uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
17-
uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions
18-
uint uLessThan = lessThan; // Use uint for comparisons to avoid unnecessary 8->32 extensions
24+
const byte Value0 = JsonConstants.Quote;
25+
const byte Value1 = JsonConstants.BackSlash;
26+
const byte LessThan = JsonConstants.Space;
27+
28+
const uint UValue0 = Value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
29+
const uint UValue1 = Value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions
30+
const uint ULessThan = LessThan; // Use uint for comparisons to avoid unnecessary 8->32 extensions
31+
1932
IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
2033
IntPtr nLength = (IntPtr)length;
2134

@@ -31,28 +44,28 @@ private static unsafe int IndexOfOrLessThan(ref byte searchSpace, byte value0, b
3144
nLength -= 8;
3245

3346
lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
34-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
47+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
3548
goto Found;
3649
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
37-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
50+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
3851
goto Found1;
3952
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
40-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
53+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
4154
goto Found2;
4255
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
43-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
56+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
4457
goto Found3;
4558
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 4);
46-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
59+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
4760
goto Found4;
4861
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 5);
49-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
62+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
5063
goto Found5;
5164
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 6);
52-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
65+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
5366
goto Found6;
5467
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 7);
55-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
68+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
5669
goto Found7;
5770

5871
index += 8;
@@ -63,16 +76,16 @@ private static unsafe int IndexOfOrLessThan(ref byte searchSpace, byte value0, b
6376
nLength -= 4;
6477

6578
lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
66-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
79+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
6780
goto Found;
6881
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
69-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
82+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
7083
goto Found1;
7184
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
72-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
85+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
7386
goto Found2;
7487
lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
75-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
88+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
7689
goto Found3;
7790

7891
index += 4;
@@ -83,7 +96,7 @@ private static unsafe int IndexOfOrLessThan(ref byte searchSpace, byte value0, b
8396
nLength -= 1;
8497

8598
lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
86-
if (uValue0 == lookUp || uValue1 == lookUp || uLessThan > lookUp)
99+
if (UValue0 == lookUp || UValue1 == lookUp || ULessThan > lookUp)
87100
goto Found;
88101

89102
index += 1;
@@ -94,9 +107,9 @@ private static unsafe int IndexOfOrLessThan(ref byte searchSpace, byte value0, b
94107
nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<byte>.Count - 1));
95108

96109
// Get comparison Vector
97-
Vector<byte> values0 = new Vector<byte>(value0);
98-
Vector<byte> values1 = new Vector<byte>(value1);
99-
Vector<byte> valuesLessThan = new Vector<byte>(lessThan);
110+
Vector<byte> values0 = new Vector<byte>(Value0);
111+
Vector<byte> values1 = new Vector<byte>(Value1);
112+
Vector<byte> valuesLessThan = new Vector<byte>(LessThan);
100113

101114
while ((byte*)nLength > (byte*)index)
102115
{

0 commit comments

Comments
 (0)