From bc27b7922ab5593ed7c0a81d99ebc632eb6ec731 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Tue, 10 Aug 2021 11:36:45 -0500 Subject: [PATCH 1/7] Improve serializer performance --- .../FSharp/FSharpTypeConverterFactory.cs | 2 +- .../Object/ObjectDefaultConverter.cs | 18 +++-- .../Converters/Value/NullableConverter.cs | 1 + .../Json/Serialization/JsonConverterOfT.cs | 68 ++++++++++++++++--- .../Serialization/JsonSerializer.Helpers.cs | 8 ++- .../JsonSerializer.Read.Document.cs | 19 +++--- .../JsonSerializer.Read.Element.cs | 19 +++--- .../JsonSerializer.Read.Helpers.cs | 21 +++++- .../Serialization/JsonSerializer.Read.Node.cs | 20 +++--- .../Serialization/JsonSerializer.Read.Span.cs | 19 +++--- .../JsonSerializer.Read.Stream.cs | 24 +++---- .../JsonSerializer.Read.String.cs | 45 ++++++++---- .../JsonSerializer.Read.Utf8JsonReader.cs | 21 +++--- .../JsonSerializer.Write.ByteArray.cs | 25 +++++-- .../JsonSerializer.Write.Document.cs | 44 ++++++++---- .../JsonSerializer.Write.Element.cs | 46 ++++++++----- .../JsonSerializer.Write.Helpers.cs | 47 +++++++++---- .../JsonSerializer.Write.Node.cs | 45 +++++++----- .../JsonSerializer.Write.Stream.cs | 4 +- .../JsonSerializer.Write.String.cs | 43 ++++++++---- .../JsonSerializer.Write.Utf8JsonWriter.cs | 38 +++++------ .../JsonSerializerOptions.Converters.cs | 4 +- .../Serialization/JsonSerializerOptions.cs | 8 ++- .../Serialization/Metadata/JsonTypeInfo.cs | 3 + .../Serialization/Metadata/JsonTypeInfoOfT.cs | 15 +++- 25 files changed, 395 insertions(+), 212 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/FSharp/FSharpTypeConverterFactory.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/FSharp/FSharpTypeConverterFactory.cs index c0cb9b88fd5743..548ef706ac547a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/FSharp/FSharpTypeConverterFactory.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/FSharp/FSharpTypeConverterFactory.cs @@ -8,7 +8,7 @@ namespace System.Text.Json.Serialization.Converters { - internal class FSharpTypeConverterFactory : JsonConverterFactory + internal sealed class FSharpTypeConverterFactory : JsonConverterFactory { // Temporary solution to account for not implemented support for type-level attributes // TODO remove once addressed https://github.com/mono/linker/issues/1742#issuecomment-875036480 diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs index a1f70edfe4ff68..60708ae8eee52f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs @@ -16,6 +16,9 @@ internal class ObjectDefaultConverter : JsonObjectConverter where T : notn { internal override bool CanHaveIdMetadata => true; +#if NET6_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveOptimization)] +#endif internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNullWhen(false)] out T value) { JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo; @@ -246,6 +249,9 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, return true; } +#if NET6_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveOptimization)] +#endif internal sealed override bool OnTryWrite( Utf8JsonWriter writer, T value, @@ -272,7 +278,7 @@ internal sealed override bool OnTryWrite( onSerializing.OnSerializing(); } - List> properties = state.Current.JsonTypeInfo.PropertyCache!.List; + List> properties = jsonTypeInfo.PropertyCache!.List; for (int i = 0; i < properties.Count; i++) { JsonPropertyInfo jsonPropertyInfo = properties[i].Value!; @@ -291,7 +297,7 @@ internal sealed override bool OnTryWrite( } // Write extension data after the normal properties. - JsonPropertyInfo? dataExtensionProperty = state.Current.JsonTypeInfo.DataExtensionProperty; + JsonPropertyInfo? dataExtensionProperty = jsonTypeInfo.DataExtensionProperty; if (dataExtensionProperty?.ShouldSerialize == true) { // Remember the current property for JsonPath support if an exception is thrown. @@ -327,7 +333,7 @@ internal sealed override bool OnTryWrite( state.Current.ProcessedStartToken = true; } - List>? propertyList = state.Current.JsonTypeInfo.PropertyCache!.List!; + List>? propertyList = jsonTypeInfo.PropertyCache!.List!; while (state.Current.EnumeratorIndex < propertyList.Count) { JsonPropertyInfo? jsonPropertyInfo = propertyList![state.Current.EnumeratorIndex].Value; @@ -362,7 +368,7 @@ internal sealed override bool OnTryWrite( // Write extension data after the normal properties. if (state.Current.EnumeratorIndex == propertyList.Count) { - JsonPropertyInfo? dataExtensionProperty = state.Current.JsonTypeInfo.DataExtensionProperty; + JsonPropertyInfo? dataExtensionProperty = jsonTypeInfo.DataExtensionProperty; if (dataExtensionProperty?.ShouldSerialize == true) { // Remember the current property for JsonPath support if an exception is thrown. @@ -407,7 +413,7 @@ internal sealed override bool OnTryWrite( // AggressiveInlining since this method is only called from two locations and is on a hot path. [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ReadPropertyValue( + protected static void ReadPropertyValue( object obj, ref ReadStack state, ref Utf8JsonReader reader, @@ -438,7 +444,7 @@ protected void ReadPropertyValue( state.Current.EndProperty(); } - protected bool ReadAheadPropertyValue(ref ReadStack state, ref Utf8JsonReader reader, JsonPropertyInfo jsonPropertyInfo) + protected static bool ReadAheadPropertyValue(ref ReadStack state, ref Utf8JsonReader reader, JsonPropertyInfo jsonPropertyInfo) { // Returning false below will cause the read-ahead functionality to finish the read. state.Current.PropertyState = StackFramePropertyState.ReadValue; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverter.cs index 227a8c32a9f42f..d799f5e6b3faf7 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverter.cs @@ -72,5 +72,6 @@ internal override void WriteNumberWithCustomHandling(Utf8JsonWriter writer, T? v } internal override bool IsNull(in T? value) => !value.HasValue; + internal override bool IsNullableOfT() => true; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs index 89d6c380ae9c5e..b1040e7521f43c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Serialization @@ -29,6 +30,12 @@ protected internal JsonConverter() HandleNullOnRead = true; HandleNullOnWrite = true; } + else + { + _autoWriteNulls = CanBeNull; + } + + _isNullableOfT = IsNullableOfT(); // For the HandleNull == false case, either: // 1) The default values are assigned in this type's virtual HandleNull property @@ -39,6 +46,17 @@ protected internal JsonConverter() CanUseDirectReadOrWrite = !CanBePolymorphic && IsInternalConverter && ConverterStrategy == ConverterStrategy.Value; } + // + // Optimized check for 'CanBeNull && !HandleNullOnWrite' + // + private bool _autoWriteNulls; + + + // + // Optimized check to check if converter is for Nullable + // + private bool _isNullableOfT; + /// /// Determines whether the type can be converted. /// @@ -143,6 +161,9 @@ internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, J /// Note that the value of determines if the converter handles null JSON tokens. public abstract T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options); +#if NET6_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveOptimization)] +#endif internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, out T? value) { if (ConverterStrategy == ConverterStrategy.Value) @@ -310,10 +331,20 @@ internal override sealed bool TryReadAsObject(ref Utf8JsonReader reader, JsonSer } /// - /// Overridden by the nullable converter to prevent boxing of values by the JIT. + /// Performance optimization. Overridden by the nullable converter to prevent boxing of values by the JIT. + /// Although the JIT added support to detect this IL pattern (box+isinst+br), it still manifests in TryWrite(). + /// + internal virtual bool IsNull(in T value) => value is null; + + /// + /// Performance optimization to determine if IsNull() above should be called. /// - internal virtual bool IsNull(in T value) => value == null; + /// + internal virtual bool IsNullableOfT() => false; +#if NET6_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveOptimization)] +#endif internal bool TryWrite(Utf8JsonWriter writer, in T value, JsonSerializerOptions options, ref WriteStack state) { if (writer.CurrentDepth >= options.EffectiveMaxDepth) @@ -321,22 +352,38 @@ internal bool TryWrite(Utf8JsonWriter writer, in T value, JsonSerializerOptions ThrowHelper.ThrowJsonException_SerializerCycleDetected(options.EffectiveMaxDepth); } - if (default(T) is null && !HandleNullOnWrite && IsNull(value)) + // We do not pass null values to converters unless HandleNullOnWrite is true. Null values for properties were + // already handled in GetMemberAndWriteJson() so we don't need to check for IgnoreNullValues here. + if (_autoWriteNulls) { - // We do not pass null values to converters unless HandleNullOnWrite is true. Null values for properties were - // already handled in GetMemberAndWriteJson() so we don't need to check for IgnoreNullValues here. - writer.WriteNullValue(); - return true; + // Optimized check to see if 'IsNull()' or 'is null' should be used. + if (_isNullableOfT) + { + if (IsNull(value)) + { + writer.WriteNullValue(); + return true; + } + } + else if (value is null) + { + writer.WriteNullValue(); + return true; + } } bool ignoreCyclesPopReference = false; if ( #if NET5_0_OR_GREATER - !typeof(T).IsValueType && // treated as a constant by recent versions of the JIT. + // Short-circuit the check against "is not null"; treated as a constant by recent versions of the JIT. + !typeof(T).IsValueType && #else !IsValueType && #endif + // Since we may have checked for a null value above we may have a redundant check here, + // but this seems to be better than trying to cache that value when considering all permutations: + // int?, int?(null value), int, object, object(null value) value is not null) { @@ -433,11 +480,12 @@ internal bool TryWrite(Utf8JsonWriter writer, in T value, JsonSerializerOptions if ( #if NET5_0_OR_GREATER - !typeof(T).IsValueType && // treated as a constant by recent versions of the JIT. + // Short-circuit the check against ignoreCyclesPopReference; treated as a constant by recent versions of the JIT. + !typeof(T).IsValueType && #endif ignoreCyclesPopReference) { - // should only be entered if we're serializing instances + // Should only be entered if we're serializing instances // of type object using the internal object converter. Debug.Assert(value?.GetType() == typeof(object) && IsInternalConverter); state.ReferenceResolver.PopReferenceForCycleDetection(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs index 0cc45a0e90c485..d0ce95e169546a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs @@ -13,10 +13,14 @@ public static partial class JsonSerializer internal const string SerializationUnreferencedCodeMessage = "JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved."; [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static JsonTypeInfo GetTypeInfo(Type runtimeType, JsonSerializerOptions? options) + private static JsonTypeInfo GetTypeInfo(JsonSerializerOptions? options, Type runtimeType) { options ??= JsonSerializerOptions.s_defaultOptions; - options.RootBuiltInConvertersAndTypeInfoCreator(); + if (!options.IsInitializedForReflectionSerializer) + { + options.InitializeForReflectionSerializer(); + } + return options.GetOrAddClassForRootType(runtimeType); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Document.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Document.cs index 45f78a979310e2..dd2b3d3852eb0e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Document.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Document.cs @@ -33,7 +33,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(document)); } - return ReadUsingOptions(document, typeof(TValue), options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + return ReadDocument(document, jsonTypeInfo); } /// @@ -66,7 +67,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(returnType)); } - return ReadUsingOptions(document, returnType, options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); + return ReadDocument(document, jsonTypeInfo); } /// @@ -101,7 +103,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return ReadUsingMetadata(document, jsonTypeInfo); + return ReadDocument(document, jsonTypeInfo); } /// @@ -157,17 +159,14 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(context)); } - return ReadUsingMetadata(document, GetTypeInfo(context, returnType)); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, returnType); + return ReadDocument(document, jsonTypeInfo); } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static TValue? ReadUsingOptions(JsonDocument document, Type returnType, JsonSerializerOptions? options) => - ReadUsingMetadata(document, GetTypeInfo(returnType, options)); - - private static TValue? ReadUsingMetadata(JsonDocument document, JsonTypeInfo jsonTypeInfo) + private static TValue? ReadDocument(JsonDocument document, JsonTypeInfo jsonTypeInfo) { ReadOnlySpan utf8Json = document.GetRootRawValue().Span; - return ReadUsingMetadata(utf8Json, jsonTypeInfo); + return ReadSpan(utf8Json, jsonTypeInfo); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs index 9419f646975b72..51f8f9fadc7569 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs @@ -23,8 +23,11 @@ public static partial class JsonSerializer /// for or its serializable members. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static TValue? Deserialize(this JsonElement element, JsonSerializerOptions? options = null) => - ReadUsingOptions(element, typeof(TValue), options); + public static TValue? Deserialize(this JsonElement element, JsonSerializerOptions? options = null) + { + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + return ReadUsingMetadata(element, jsonTypeInfo); + } /// /// Converts the representing a single JSON value into a . @@ -51,7 +54,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(returnType)); } - return ReadUsingOptions(element, returnType, options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); + return ReadUsingMetadata(element, jsonTypeInfo); } /// @@ -124,17 +128,14 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(context)); } - return ReadUsingMetadata(element, GetTypeInfo(context, returnType)); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, returnType); + return ReadUsingMetadata(element, jsonTypeInfo); } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static TValue? ReadUsingOptions(JsonElement element, Type returnType, JsonSerializerOptions? options) => - ReadUsingMetadata(element, GetTypeInfo(returnType, options)); - private static TValue? ReadUsingMetadata(JsonElement element, JsonTypeInfo jsonTypeInfo) { ReadOnlySpan utf8Json = element.GetRawValue().Span; - return ReadUsingMetadata(utf8Json, jsonTypeInfo); + return ReadSpan(utf8Json, jsonTypeInfo); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs index 66d9cb4899c19a..ebaa15ed54be27 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs @@ -20,10 +20,10 @@ public static partial class JsonSerializer // The non-generic API was called or we have a polymorphic case where TValue is not equal to the T in JsonConverter. object? value = jsonConverter.ReadCoreAsObject(ref reader, options, ref state); Debug.Assert(value == null || value is TValue); - return (TValue)value!; + return (TValue?)value; } - private static TValue? ReadUsingMetadata(ReadOnlySpan utf8Json, JsonTypeInfo jsonTypeInfo, int? actualByteCount = null) + private static TValue? ReadSpan(ReadOnlySpan utf8Json, JsonTypeInfo jsonTypeInfo, int? actualByteCount = null) { JsonSerializerOptions options = jsonTypeInfo.Options; @@ -33,7 +33,22 @@ public static partial class JsonSerializer ReadStack state = default; state.Initialize(jsonTypeInfo); - TValue? value = ReadCore(jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase, ref reader, options, ref state); + TValue? value; + JsonConverter jsonConverter = jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase; + + // For performance, the code below is a lifted ReadCore() above. + if (jsonConverter is JsonConverter converter) + { + // Call the strongly-typed ReadCore that will not box structs. + value = converter.ReadCore(ref reader, options, ref state); + } + else + { + // The non-generic API was called or we have a polymorphic case where TValue is not equal to the T in JsonConverter. + object? objValue = jsonConverter.ReadCoreAsObject(ref reader, options, ref state); + Debug.Assert(objValue == null || objValue is TValue); + value = (TValue?)objValue; + } // The reader should have thrown if we have remaining bytes. Debug.Assert(reader.BytesConsumed == (actualByteCount ?? utf8Json.Length)); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Node.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Node.cs index 32de1de46da955..49a3c7b6c19c04 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Node.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Node.cs @@ -27,7 +27,8 @@ public static partial class JsonSerializer [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] public static TValue? Deserialize(this JsonNode? node, JsonSerializerOptions? options = null) { - return ReadUsingOptions(node, typeof(TValue), options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + return ReadNode(node, jsonTypeInfo); } /// @@ -52,7 +53,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(returnType)); } - return ReadUsingOptions(node, returnType, options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); + return ReadNode(node, jsonTypeInfo); } /// @@ -78,7 +80,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return ReadUsingMetadata(node, jsonTypeInfo); + return ReadNode(node, jsonTypeInfo); } /// @@ -125,17 +127,13 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(context)); } - return ReadUsingMetadata(node, GetTypeInfo(context, returnType)); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, returnType); + return ReadNode(node, jsonTypeInfo); } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static TValue? ReadUsingOptions(JsonNode? node, Type returnType, JsonSerializerOptions? options) => - ReadUsingMetadata(node, GetTypeInfo(returnType, options)); - - private static TValue? ReadUsingMetadata(JsonNode? node, JsonTypeInfo jsonTypeInfo) + private static TValue? ReadNode(JsonNode? node, JsonTypeInfo jsonTypeInfo) { JsonSerializerOptions options = jsonTypeInfo.Options; - Debug.Assert(options != null); // For performance, share the same buffer across serialization and deserialization. using var output = new PooledByteBufferWriter(options.DefaultBufferSize); @@ -151,7 +149,7 @@ public static partial class JsonSerializer } } - return ReadUsingMetadata(output.WrittenMemory.Span, jsonTypeInfo); + return ReadSpan(output.WrittenMemory.Span, jsonTypeInfo); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs index 6983253171d612..f8e2e8312c245e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs @@ -26,7 +26,10 @@ public static partial class JsonSerializer /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] public static TValue? Deserialize(ReadOnlySpan utf8Json, JsonSerializerOptions? options = null) - => ReadUsingOptions(utf8Json, typeof(TValue), options); + { + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + return ReadSpan(utf8Json, jsonTypeInfo); + } /// /// Parses the UTF-8 encoded text representing a single JSON value into a . @@ -55,7 +58,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(returnType)); } - return ReadUsingOptions(utf8Json, returnType, options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); + return ReadSpan(utf8Json, jsonTypeInfo); } /// @@ -80,7 +84,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return ReadUsingMetadata(utf8Json, jsonTypeInfo); + return ReadSpan(utf8Json, jsonTypeInfo); } /// @@ -118,14 +122,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(context)); } - return ReadUsingMetadata(utf8Json, GetTypeInfo(context, returnType)); - } - - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static TValue? ReadUsingOptions(ReadOnlySpan utf8Json, Type returnType, JsonSerializerOptions? options) - { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(returnType, options); - return ReadUsingMetadata(utf8Json, jsonTypeInfo); + return ReadSpan(utf8Json, GetTypeInfo(context, returnType)); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs index 95c26c4a6c3327..e299d83a6bedd8 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs @@ -50,7 +50,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(utf8Json)); } - return ReadAllUsingOptionsAsync(utf8Json, typeof(TValue), options, cancellationToken); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + return ReadAllAsync(utf8Json, jsonTypeInfo, cancellationToken); } /// @@ -125,7 +126,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(returnType)); } - return ReadAllUsingOptionsAsync(utf8Json, returnType, options, cancellationToken); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); + return ReadAllAsync(utf8Json, jsonTypeInfo, cancellationToken); } /// @@ -365,7 +367,10 @@ public static partial class JsonSerializer } options ??= JsonSerializerOptions.s_defaultOptions; - options.RootBuiltInConvertersAndTypeInfoCreator(); + if (!options.IsInitializedForReflectionSerializer) + { + options.InitializeForReflectionSerializer(); + } return CreateAsyncEnumerableDeserializer(utf8Json, options, cancellationToken); @@ -616,24 +621,13 @@ internal static TValue ContinueDeserialize( return value; } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static ValueTask ReadAllUsingOptionsAsync( - Stream utf8Json, - Type returnType, - JsonSerializerOptions? options, - CancellationToken cancellationToken) - { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(returnType, options); - return ReadAllAsync(utf8Json, jsonTypeInfo, cancellationToken); - } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] private static TValue? ReadAllUsingOptions( Stream utf8Json, Type returnType, JsonSerializerOptions? options) { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(returnType, options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); return ReadAll(utf8Json, jsonTypeInfo); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs index b3f07a58e8475b..0e68fb689d63d3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs @@ -48,7 +48,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(json)); } - return ReadUsingOptions(json.AsSpan(), typeof(TValue), options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + return ReadSpan(json.AsSpan(), jsonTypeInfo); } /// @@ -79,7 +80,8 @@ public static partial class JsonSerializer { // default/null span is treated as empty - return ReadUsingOptions(json, typeof(TValue), options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + return ReadSpan(json, jsonTypeInfo); } /// @@ -122,7 +124,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(returnType)); } - return ReadUsingOptions(json.AsSpan(), returnType, options)!; + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); + return ReadSpan(json.AsSpan(), jsonTypeInfo)!; } /// @@ -162,7 +165,13 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(returnType)); } - return ReadUsingOptions(json, returnType, options)!; + if (returnType == null) + { + throw new ArgumentNullException(nameof(returnType)); + } + + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); + return ReadSpan(json, jsonTypeInfo)!; } /// @@ -209,7 +218,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return ReadUsingMetadata(json.AsSpan(), jsonTypeInfo); + return ReadSpan(json.AsSpan(), jsonTypeInfo); } /// @@ -251,7 +260,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return ReadUsingMetadata(json, jsonTypeInfo); + return ReadSpan(json, jsonTypeInfo); } /// @@ -296,7 +305,18 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(json)); } - return Deserialize(json.AsSpan(), returnType, context); + if (returnType == null) + { + throw new ArgumentNullException(nameof(returnType)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, returnType); + return ReadSpan(json.AsSpan(), jsonTypeInfo); } /// @@ -346,14 +366,11 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(context)); } - return ReadUsingMetadata(json, GetTypeInfo(context, returnType)); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, returnType); + return ReadSpan(json, jsonTypeInfo); } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static TValue? ReadUsingOptions(ReadOnlySpan json, Type returnType, JsonSerializerOptions? options) - => ReadUsingMetadata(json, GetTypeInfo(returnType, options)); - - private static TValue? ReadUsingMetadata(ReadOnlySpan json, JsonTypeInfo jsonTypeInfo) + private static TValue? ReadSpan(ReadOnlySpan json, JsonTypeInfo jsonTypeInfo) { byte[]? tempArray = null; @@ -369,7 +386,7 @@ public static partial class JsonSerializer { int actualByteCount = JsonReaderHelper.GetUtf8FromText(json, utf8); utf8 = utf8.Slice(0, actualByteCount); - return ReadUsingMetadata(utf8, jsonTypeInfo, actualByteCount); + return ReadSpan(utf8, jsonTypeInfo, actualByteCount); } finally { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs index d0d35d480f56e2..1ca166c7850de1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs @@ -55,7 +55,10 @@ public static partial class JsonSerializer /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] public static TValue? Deserialize(ref Utf8JsonReader reader, JsonSerializerOptions? options = null) - => ReadUsingOptions(ref reader, typeof(TValue), options); + { + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + return Read(ref reader, jsonTypeInfo); + } /// /// Reads one JSON value (including objects or arrays) from the provided reader into a . @@ -110,7 +113,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(returnType)); } - return ReadUsingOptions(ref reader, returnType, options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); + return Read(ref reader, jsonTypeInfo); } /// @@ -162,7 +166,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return ReadUsingMetadata(ref reader, jsonTypeInfo); + return Read(ref reader, jsonTypeInfo); } /// @@ -226,17 +230,10 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(context)); } - return ReadUsingMetadata(ref reader, GetTypeInfo(context, returnType)); - } - - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static TValue? ReadUsingOptions(ref Utf8JsonReader reader, Type returnType, JsonSerializerOptions? options) - { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(returnType, options); - return ReadUsingMetadata(ref reader, jsonTypeInfo); + return Read(ref reader, GetTypeInfo(context, returnType)); } - private static TValue? ReadUsingMetadata(ref Utf8JsonReader reader, JsonTypeInfo jsonTypeInfo) + private static TValue? Read(ref Utf8JsonReader reader, JsonTypeInfo jsonTypeInfo) { ReadStack state = default; state.Initialize(jsonTypeInfo); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs index 932689c97146eb..f6799bd2d75a4d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs @@ -76,7 +76,7 @@ public static byte[] SerializeToUtf8Bytes(TValue value, JsonTypeInfo @@ -108,24 +108,37 @@ public static byte[] SerializeToUtf8Bytes(object? value, Type inputType, JsonSer } Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - return WriteCoreBytes(value!, GetTypeInfo(context, runtimeType)); + return WriteBytesUsingGeneratedSerializer(value!, GetTypeInfo(context, runtimeType)); } [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] private static byte[] WriteCoreBytes(in TValue value, Type runtimeType, JsonSerializerOptions? options) { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(runtimeType, options); - return WriteCoreBytes(value, jsonTypeInfo); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteBytesUsingSerializer(value, jsonTypeInfo); } - private static byte[] WriteCoreBytes(in TValue value, JsonTypeInfo jsonTypeInfo) + private static byte[] WriteBytesUsingGeneratedSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) { JsonSerializerOptions options = jsonTypeInfo.Options; using var output = new PooledByteBufferWriter(options.DefaultBufferSize); using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { - WriteUsingMetadata(writer, value, jsonTypeInfo); + WriteUsingGeneratedSerializer(writer, value, jsonTypeInfo); + } + + return output.WrittenMemory.ToArray(); + } + + private static byte[] WriteBytesUsingSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) + { + JsonSerializerOptions options = jsonTypeInfo.Options; + + using var output = new PooledByteBufferWriter(options.DefaultBufferSize); + using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) + { + WriteUsingSerializer(writer, value, jsonTypeInfo); } return output.WrittenMemory.ToArray(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Document.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Document.cs index d96d63e05b9e9d..562b1cdbc78a6e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Document.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Document.cs @@ -21,8 +21,12 @@ public static partial class JsonSerializer /// for or its serializable members. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static JsonDocument SerializeToDocument(TValue value, JsonSerializerOptions? options = null) => - WriteDocument(value, GetRuntimeType(value), options); + public static JsonDocument SerializeToDocument(TValue value, JsonSerializerOptions? options = null) + { + Type runtimeType = GetRuntimeType(value); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteDocumentUsingSerializer(value, jsonTypeInfo); + } /// /// Converts the provided value into a . @@ -42,11 +46,12 @@ public static JsonDocument SerializeToDocument(TValue value, JsonSeriali /// for or its serializable members. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static JsonDocument SerializeToDocument(object? value, Type inputType, JsonSerializerOptions? options = null) => - WriteDocument( - value, - GetRuntimeTypeAndValidateInputType(value, inputType), - options); + public static JsonDocument SerializeToDocument(object? value, Type inputType, JsonSerializerOptions? options = null) + { + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteDocumentUsingSerializer(value, jsonTypeInfo); + } /// /// Converts the provided value into a . @@ -68,7 +73,7 @@ public static JsonDocument SerializeToDocument(TValue value, JsonTypeInf throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return WriteDocument(value, jsonTypeInfo); + return WriteDocumentUsingGeneratedSerializer(value, jsonTypeInfo); } /// @@ -97,17 +102,26 @@ public static JsonDocument SerializeToDocument(object? value, Type inputType, Js } Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - return WriteDocument(value, GetTypeInfo(context, runtimeType)); + return WriteDocumentUsingGeneratedSerializer(value, GetTypeInfo(context, runtimeType)); } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static JsonDocument WriteDocument(in TValue value, Type runtimeType, JsonSerializerOptions? options) + private static JsonDocument WriteDocumentUsingGeneratedSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) { - JsonTypeInfo typeInfo = GetTypeInfo(runtimeType, options); - return WriteDocument(value, typeInfo); + JsonSerializerOptions options = jsonTypeInfo.Options; + Debug.Assert(options != null); + + // For performance, share the same buffer across serialization and deserialization. + // The PooledByteBufferWriter is cleared and returned when JsonDocument.Dispose() is called. + PooledByteBufferWriter output = new(options.DefaultBufferSize); + using (Utf8JsonWriter writer = new(output, options.GetWriterOptions())) + { + WriteUsingGeneratedSerializer(writer, value, jsonTypeInfo); + } + + return JsonDocument.ParseRented(output, options.GetDocumentOptions()); } - private static JsonDocument WriteDocument(in TValue value, JsonTypeInfo jsonTypeInfo) + private static JsonDocument WriteDocumentUsingSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) { JsonSerializerOptions options = jsonTypeInfo.Options; Debug.Assert(options != null); @@ -117,7 +131,7 @@ private static JsonDocument WriteDocument(in TValue value, JsonTypeInfo PooledByteBufferWriter output = new(options.DefaultBufferSize); using (Utf8JsonWriter writer = new(output, options.GetWriterOptions())) { - WriteUsingMetadata(writer, value, jsonTypeInfo); + WriteUsingSerializer(writer, value, jsonTypeInfo); } return JsonDocument.ParseRented(output, options.GetDocumentOptions()); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Element.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Element.cs index 06900470e7b9eb..4c4d6e70a6c7ad 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Element.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Element.cs @@ -21,8 +21,12 @@ public static partial class JsonSerializer /// for or its serializable members. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static JsonElement SerializeToElement(TValue value, JsonSerializerOptions? options = null) => - WriteElement(value, GetRuntimeType(value), options); + public static JsonElement SerializeToElement(TValue value, JsonSerializerOptions? options = null) + { + Type runtimeType = GetRuntimeType(value); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteElementUsingSerializer(value, jsonTypeInfo); + } /// /// Converts the provided value into a . @@ -42,11 +46,12 @@ public static JsonElement SerializeToElement(TValue value, JsonSerialize /// for or its serializable members. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static JsonElement SerializeToElement(object? value, Type inputType, JsonSerializerOptions? options = null) => - WriteElement( - value, - GetRuntimeTypeAndValidateInputType(value, inputType), - options); + public static JsonElement SerializeToElement(object? value, Type inputType, JsonSerializerOptions? options = null) + { + Type type = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, type); + return WriteElementUsingSerializer(value, jsonTypeInfo); + } /// /// Converts the provided value into a . @@ -68,7 +73,7 @@ public static JsonElement SerializeToElement(TValue value, JsonTypeInfo< throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return WriteElement(value, jsonTypeInfo); + return WriteElementUsingGeneratedSerializer(value, jsonTypeInfo); } /// @@ -96,18 +101,27 @@ public static JsonElement SerializeToElement(object? value, Type inputType, Json throw new ArgumentNullException(nameof(context)); } - Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - return WriteElement(value, GetTypeInfo(context, runtimeType)); + Type type = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo typeInfo = GetTypeInfo(context, type); + return WriteElementUsingGeneratedSerializer(value, typeInfo); } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static JsonElement WriteElement(in TValue value, Type runtimeType, JsonSerializerOptions? options) + private static JsonElement WriteElementUsingGeneratedSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) { - JsonTypeInfo typeInfo = GetTypeInfo(runtimeType, options); - return WriteElement(value, typeInfo); + JsonSerializerOptions options = jsonTypeInfo.Options; + Debug.Assert(options != null); + + // For performance, share the same buffer across serialization and deserialization. + using var output = new PooledByteBufferWriter(options.DefaultBufferSize); + using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) + { + WriteUsingGeneratedSerializer(writer, value, jsonTypeInfo); + } + + return JsonElement.ParseValue(output.WrittenMemory.Span, options.GetDocumentOptions()); } - private static JsonElement WriteElement(in TValue value, JsonTypeInfo jsonTypeInfo) + private static JsonElement WriteElementUsingSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) { JsonSerializerOptions options = jsonTypeInfo.Options; Debug.Assert(options != null); @@ -116,7 +130,7 @@ private static JsonElement WriteElement(in TValue value, JsonTypeInfo js using var output = new PooledByteBufferWriter(options.DefaultBufferSize); using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { - WriteUsingMetadata(writer, value, jsonTypeInfo); + WriteUsingSerializer(writer, value, jsonTypeInfo); } return JsonElement.ParseValue(output.WrittenMemory.Span, options.GetDocumentOptions()); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs index cd6cd1b163b33b..5aa1ada5a39c00 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; @@ -36,37 +35,57 @@ private static bool WriteCore( return success; } - private static void WriteUsingMetadata(Utf8JsonWriter writer, in TValue value, JsonTypeInfo jsonTypeInfo) + private static void WriteUsingGeneratedSerializer(Utf8JsonWriter writer, in TValue value, JsonTypeInfo jsonTypeInfo) { - if (jsonTypeInfo is JsonTypeInfo typedInfo && - typedInfo.Serialize != null && + if (jsonTypeInfo.HasSerialize && + jsonTypeInfo is JsonTypeInfo typedInfo && typedInfo.Options._context?.CanUseSerializationLogic == true) { + Debug.Assert(typedInfo.Serialize != null); typedInfo.Serialize(writer, value); writer.Flush(); } else { - WriteStack state = default; - state.Initialize(jsonTypeInfo, supportContinuation: false); + WriteUsingSerializer(writer, value, jsonTypeInfo); + } + } + + private static void WriteUsingSerializer(Utf8JsonWriter writer, in TValue value, JsonTypeInfo jsonTypeInfo) + { + Debug.Assert(jsonTypeInfo is not JsonTypeInfo, "Incorrect method called."); - JsonConverter converter = jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase; - Debug.Assert(converter != null); + WriteStack state = default; + state.Initialize(jsonTypeInfo, supportContinuation: false); - Debug.Assert(jsonTypeInfo.Options != null); + JsonConverter converter = jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase; + Debug.Assert(converter != null); + Debug.Assert(jsonTypeInfo.Options != null); - WriteCore(converter, writer, value, jsonTypeInfo.Options, ref state); + // For performance, the code below is a lifted WriteCore() above. + if (converter is JsonConverter typedConverter) + { + // Call the strongly-typed WriteCore that will not box structs. + typedConverter.WriteCore(writer, value, jsonTypeInfo.Options, ref state); } + else + { + // The non-generic API was called or we have a polymorphic case where TValue is not equal to the T in JsonConverter. + converter.WriteCoreAsObject(writer, value, jsonTypeInfo.Options, ref state); + } + + writer.Flush(); } private static Type GetRuntimeType(in TValue value) { - if (typeof(TValue) == typeof(object) && value != null) + Type type = typeof(TValue); + if (type == JsonTypeInfo.ObjectType && value is not null) { - return value.GetType(); + type = value.GetType(); } - return typeof(TValue); + return type; } private static Type GetRuntimeTypeAndValidateInputType(object? value, Type inputType) @@ -84,7 +103,7 @@ private static Type GetRuntimeTypeAndValidateInputType(object? value, Type input ThrowHelper.ThrowArgumentException_DeserializeWrongType(inputType, value); } - if (inputType == typeof(object)) + if (inputType == JsonTypeInfo.ObjectType) { return runtimeType; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs index 4b37821a58e0c4..4266d29dc7fe52 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs @@ -22,8 +22,12 @@ public static partial class JsonSerializer /// for or its serializable members. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static JsonNode? SerializeToNode(TValue value, JsonSerializerOptions? options = null) => - WriteNode(value, GetRuntimeType(value), options); + public static JsonNode? SerializeToNode(TValue value, JsonSerializerOptions? options = null) + { + Type runtimeType = GetRuntimeType(value); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteNodeUsingSerializer(value, jsonTypeInfo); + } /// /// Converts the provided value into a . @@ -43,11 +47,12 @@ public static partial class JsonSerializer /// for or its serializable members. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static JsonNode? SerializeToNode(object? value, Type inputType, JsonSerializerOptions? options = null) => - WriteNode( - value, - GetRuntimeTypeAndValidateInputType(value, inputType), - options); + public static JsonNode? SerializeToNode(object? value, Type inputType, JsonSerializerOptions? options = null) + { + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo typeInfo = GetTypeInfo(options, runtimeType); + return WriteNodeUsingSerializer(value, typeInfo); + } /// /// Converts the provided value into a . @@ -69,7 +74,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return WriteNode(value, jsonTypeInfo); + return WriteNodeUsingGeneratedSerializer(value, jsonTypeInfo); } /// @@ -97,18 +102,26 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(context)); } - Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - return WriteNode(value, GetTypeInfo(context, runtimeType)); + Type type = GetRuntimeTypeAndValidateInputType(value, inputType); + return WriteNodeUsingGeneratedSerializer(value, GetTypeInfo(context, type)); } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static JsonNode? WriteNode(in TValue value, Type runtimeType, JsonSerializerOptions? options) + private static JsonNode? WriteNodeUsingGeneratedSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) { - JsonTypeInfo typeInfo = GetTypeInfo(runtimeType, options); - return WriteNode(value, typeInfo); + JsonSerializerOptions options = jsonTypeInfo.Options; + Debug.Assert(options != null); + + // For performance, share the same buffer across serialization and deserialization. + using var output = new PooledByteBufferWriter(options.DefaultBufferSize); + using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) + { + WriteUsingGeneratedSerializer(writer, value, jsonTypeInfo); + } + + return JsonNode.Parse(output.WrittenMemory.Span, options.GetNodeOptions()); } - private static JsonNode? WriteNode(in TValue value, JsonTypeInfo jsonTypeInfo) + private static JsonNode? WriteNodeUsingSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) { JsonSerializerOptions options = jsonTypeInfo.Options; Debug.Assert(options != null); @@ -117,7 +130,7 @@ public static partial class JsonSerializer using var output = new PooledByteBufferWriter(options.DefaultBufferSize); using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { - WriteUsingMetadata(writer, value, jsonTypeInfo); + WriteUsingSerializer(writer, value, jsonTypeInfo); } return JsonNode.Parse(output.WrittenMemory.Span, options.GetNodeOptions()); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs index 802b9300fc7c11..90bdabd127be56 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs @@ -318,7 +318,7 @@ private static Task WriteAsync( JsonSerializerOptions? options, CancellationToken cancellationToken) { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(runtimeType, options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); return WriteAsyncCore(utf8Json, value!, jsonTypeInfo, cancellationToken); } @@ -329,7 +329,7 @@ private static void Write( Type runtimeType, JsonSerializerOptions? options) { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(runtimeType, options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); WriteCore(utf8Json, value!, jsonTypeInfo); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs index a7c504823af586..2f94a2ebe5cc4c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs @@ -26,7 +26,9 @@ public static partial class JsonSerializer [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] public static string Serialize(TValue value, JsonSerializerOptions? options = null) { - return Write(value, GetRuntimeType(value), options); + Type runtimeType = GetRuntimeType(value); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteStringUsingSerializer(value, jsonTypeInfo); } /// @@ -56,10 +58,9 @@ public static string Serialize( Type inputType, JsonSerializerOptions? options = null) { - return Write( - value, - GetRuntimeTypeAndValidateInputType(value, inputType), - options); + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteStringUsingSerializer(value, jsonTypeInfo); } /// @@ -81,7 +82,7 @@ public static string Serialize( /// public static string Serialize(TValue value, JsonTypeInfo jsonTypeInfo) { - return WriteUsingMetadata(value, jsonTypeInfo); + return WriteStringUsingGeneratedSerializer(value, jsonTypeInfo); } /// @@ -113,18 +114,32 @@ public static string Serialize(object? value, Type inputType, JsonSerializerCont throw new ArgumentNullException(nameof(context)); } - Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - return WriteUsingMetadata(value, GetTypeInfo(context, runtimeType)); + Type type = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, type); + return WriteStringUsingGeneratedSerializer(value, jsonTypeInfo); } - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static string Write(in TValue value, Type runtimeType, JsonSerializerOptions? options) + private static string WriteStringUsingGeneratedSerializer(in TValue value, JsonTypeInfo? jsonTypeInfo) { - JsonTypeInfo typeInfo = GetTypeInfo(runtimeType, options); - return WriteUsingMetadata(value, typeInfo); + if (jsonTypeInfo == null) + { + throw new ArgumentNullException(nameof(jsonTypeInfo)); + } + + JsonSerializerOptions options = jsonTypeInfo.Options; + + using (var output = new PooledByteBufferWriter(options.DefaultBufferSize)) + { + using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) + { + WriteUsingGeneratedSerializer(writer, value, jsonTypeInfo); + } + + return JsonReaderHelper.TranscodeHelper(output.WrittenMemory.Span); + } } - private static string WriteUsingMetadata(in TValue value, JsonTypeInfo? jsonTypeInfo) + private static string WriteStringUsingSerializer(in TValue value, JsonTypeInfo? jsonTypeInfo) { if (jsonTypeInfo == null) { @@ -137,7 +152,7 @@ private static string WriteUsingMetadata(in TValue value, JsonTypeInfo? { using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { - WriteUsingMetadata(writer, value, jsonTypeInfo); + WriteUsingSerializer(writer, value, jsonTypeInfo); } return JsonReaderHelper.TranscodeHelper(output.WrittenMemory.Span); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs index 7641ae44047f93..58771f38316d0b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs @@ -28,7 +28,14 @@ public static void Serialize( TValue value, JsonSerializerOptions? options = null) { - Serialize(writer, value, GetRuntimeType(value), options); + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + Type runtimeType = GetRuntimeType(value); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + WriteUsingSerializer(writer, value, jsonTypeInfo); } /// @@ -55,11 +62,14 @@ public static void Serialize( Type inputType, JsonSerializerOptions? options = null) { - Serialize( - writer, - value, - GetRuntimeTypeAndValidateInputType(value, inputType), - options); + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + WriteUsingSerializer(writer, value, jsonTypeInfo); } /// @@ -87,7 +97,7 @@ public static void Serialize(Utf8JsonWriter writer, TValue value, JsonTy throw new ArgumentNullException(nameof(jsonTypeInfo)); } - WriteUsingMetadata(writer, value, jsonTypeInfo); + WriteUsingGeneratedSerializer(writer, value, jsonTypeInfo); } /// @@ -124,19 +134,7 @@ public static void Serialize(Utf8JsonWriter writer, object? value, Type inputTyp } Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - WriteUsingMetadata(writer, value, GetTypeInfo(context, runtimeType)); - } - - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static void Serialize(Utf8JsonWriter writer, in TValue value, Type runtimeType, JsonSerializerOptions? options) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - JsonTypeInfo typeInfo = GetTypeInfo(runtimeType, options); - WriteUsingMetadata(writer, value, typeInfo); + WriteUsingGeneratedSerializer(writer, value, GetTypeInfo(context, runtimeType)); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs index e394d9a91e78d6..5d8a38fcc3f166 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs @@ -30,8 +30,8 @@ public sealed partial class JsonSerializerOptions [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] private void RootBuiltInConverters() { - s_defaultSimpleConverters ??= GetDefaultSimpleConverters(); - s_defaultFactoryConverters ??= new JsonConverter[] + s_defaultSimpleConverters = GetDefaultSimpleConverters(); + s_defaultFactoryConverters = new JsonConverter[] { // Check for disallowed types. new DisallowedTypeConverterFactory(), diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 49e3813b2a16e4..8e5be33ad7ac46 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -247,6 +247,8 @@ public JsonNamingPolicy? DictionaryKeyPolicy } } + internal bool IsInitializedForReflectionSerializer { get; set; } + /// /// Determines whether null values are ignored during serialization and deserialization. /// The default value is false. @@ -576,10 +578,12 @@ internal MemberAccessor MemberAccessorStrategy } [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] - internal void RootBuiltInConvertersAndTypeInfoCreator() + internal void InitializeForReflectionSerializer() { + // For threading cases, the state that is set here can be overwritten. RootBuiltInConverters(); - _typeInfoCreationFunc ??= CreateJsonTypeInfo; + _typeInfoCreationFunc = CreateJsonTypeInfo; + IsInitializedForReflectionSerializer = true; [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] static JsonTypeInfo CreateJsonTypeInfo(Type type, JsonSerializerOptions options) => new JsonTypeInfo(type, options); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs index 758e90835a1b5b..28fb27669139e6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs @@ -33,6 +33,9 @@ public partial class JsonTypeInfo // If enumerable or dictionary, the JsonTypeInfo for the element type. private JsonTypeInfo? _elementTypeInfo; + // Avoids having to perform an expensive cast to JsonTypeInfo to check if there is a Serialize method. + internal bool HasSerialize { get; set; } + /// /// Return the JsonTypeInfo for the element type, or null if the type is not an enumerable or dictionary. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs index 13bdbc8259e6c1..337fd7cf1a3ca9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs @@ -13,6 +13,8 @@ namespace System.Text.Json.Serialization.Metadata [EditorBrowsable(EditorBrowsableState.Never)] public abstract class JsonTypeInfo : JsonTypeInfo { + private Action? _serialize; + internal JsonTypeInfo(Type type, JsonSerializerOptions options, ConverterStrategy converterStrategy) : base(type, options, converterStrategy) { } @@ -26,6 +28,17 @@ internal JsonTypeInfo() /// A method that serializes an instance of using /// values specified at design time. /// - public Action? Serialize { get; private protected set; } + public Action? Serialize + { + get + { + return _serialize; + } + private protected set + { + _serialize = value; + HasSerialize = value != null; + } + } } } From 5467cd9a4d59b94d025a0938aef67acb698a684d Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 13 Aug 2021 13:16:05 -0500 Subject: [PATCH 2/7] Change main null check in TryWrite(); other misc --- .../Converters/Value/NullableConverter.cs | 3 -- .../Json/Serialization/JsonConverterOfT.cs | 50 +++---------------- .../JsonSerializer.Read.String.cs | 18 +++---- .../JsonSerializer.Write.ByteArray.cs | 20 +++----- .../JsonSerializer.Write.Helpers.cs | 7 ++- 5 files changed, 29 insertions(+), 69 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverter.cs index d799f5e6b3faf7..ba69c3efbf9ffd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverter.cs @@ -70,8 +70,5 @@ internal override void WriteNumberWithCustomHandling(Utf8JsonWriter writer, T? v _converter.WriteNumberWithCustomHandling(writer, value.Value, handling); } } - - internal override bool IsNull(in T? value) => !value.HasValue; - internal override bool IsNullableOfT() => true; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs index b1040e7521f43c..714332bef36b00 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs @@ -30,12 +30,6 @@ protected internal JsonConverter() HandleNullOnRead = true; HandleNullOnWrite = true; } - else - { - _autoWriteNulls = CanBeNull; - } - - _isNullableOfT = IsNullableOfT(); // For the HandleNull == false case, either: // 1) The default values are assigned in this type's virtual HandleNull property @@ -46,17 +40,6 @@ protected internal JsonConverter() CanUseDirectReadOrWrite = !CanBePolymorphic && IsInternalConverter && ConverterStrategy == ConverterStrategy.Value; } - // - // Optimized check for 'CanBeNull && !HandleNullOnWrite' - // - private bool _autoWriteNulls; - - - // - // Optimized check to check if converter is for Nullable - // - private bool _isNullableOfT; - /// /// Determines whether the type can be converted. /// @@ -331,16 +314,9 @@ internal override sealed bool TryReadAsObject(ref Utf8JsonReader reader, JsonSer } /// - /// Performance optimization. Overridden by the nullable converter to prevent boxing of values by the JIT. - /// Although the JIT added support to detect this IL pattern (box+isinst+br), it still manifests in TryWrite(). - /// - internal virtual bool IsNull(in T value) => value is null; - - /// - /// Performance optimization to determine if IsNull() above should be called. + /// Performance optimization. The 'in' modifier in TryWrite(in T Value) will cause boxing, so this helper method avoids that. /// - /// - internal virtual bool IsNullableOfT() => false; + internal bool IsNull(T value) => value is null; #if NET6_0_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveOptimization)] @@ -352,24 +328,12 @@ internal bool TryWrite(Utf8JsonWriter writer, in T value, JsonSerializerOptions ThrowHelper.ThrowJsonException_SerializerCycleDetected(options.EffectiveMaxDepth); } - // We do not pass null values to converters unless HandleNullOnWrite is true. Null values for properties were - // already handled in GetMemberAndWriteJson() so we don't need to check for IgnoreNullValues here. - if (_autoWriteNulls) + if (default(T) is null && !HandleNullOnWrite && IsNull(value)) { - // Optimized check to see if 'IsNull()' or 'is null' should be used. - if (_isNullableOfT) - { - if (IsNull(value)) - { - writer.WriteNullValue(); - return true; - } - } - else if (value is null) - { - writer.WriteNullValue(); - return true; - } + // We do not pass null values to converters unless HandleNullOnWrite is true. Null values for properties were + // already handled in GetMemberAndWriteJson() so we don't need to check for IgnoreNullValues here. + writer.WriteNullValue(); + return true; } bool ignoreCyclesPopReference = false; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs index 0e68fb689d63d3..8694f7ac328fa1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs @@ -49,7 +49,7 @@ public static partial class JsonSerializer } JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); - return ReadSpan(json.AsSpan(), jsonTypeInfo); + return ReadFromSpan(json.AsSpan(), jsonTypeInfo); } /// @@ -81,7 +81,7 @@ public static partial class JsonSerializer // default/null span is treated as empty JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); - return ReadSpan(json, jsonTypeInfo); + return ReadFromSpan(json, jsonTypeInfo); } /// @@ -125,7 +125,7 @@ public static partial class JsonSerializer } JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); - return ReadSpan(json.AsSpan(), jsonTypeInfo)!; + return ReadFromSpan(json.AsSpan(), jsonTypeInfo)!; } /// @@ -171,7 +171,7 @@ public static partial class JsonSerializer } JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); - return ReadSpan(json, jsonTypeInfo)!; + return ReadFromSpan(json, jsonTypeInfo)!; } /// @@ -218,7 +218,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return ReadSpan(json.AsSpan(), jsonTypeInfo); + return ReadFromSpan(json.AsSpan(), jsonTypeInfo); } /// @@ -260,7 +260,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return ReadSpan(json, jsonTypeInfo); + return ReadFromSpan(json, jsonTypeInfo); } /// @@ -316,7 +316,7 @@ public static partial class JsonSerializer } JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, returnType); - return ReadSpan(json.AsSpan(), jsonTypeInfo); + return ReadFromSpan(json.AsSpan(), jsonTypeInfo); } /// @@ -367,10 +367,10 @@ public static partial class JsonSerializer } JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, returnType); - return ReadSpan(json, jsonTypeInfo); + return ReadFromSpan(json, jsonTypeInfo); } - private static TValue? ReadSpan(ReadOnlySpan json, JsonTypeInfo jsonTypeInfo) + private static TValue? ReadFromSpan(ReadOnlySpan json, JsonTypeInfo jsonTypeInfo) { byte[]? tempArray = null; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs index f6799bd2d75a4d..6a8333ac0f3d6f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs @@ -24,7 +24,8 @@ public static byte[] SerializeToUtf8Bytes( TValue value, JsonSerializerOptions? options = null) { - return WriteCoreBytes(value, GetRuntimeType(value), options); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + return WriteBytesUsingSerializer(value, jsonTypeInfo); } /// @@ -50,10 +51,9 @@ public static byte[] SerializeToUtf8Bytes( Type inputType, JsonSerializerOptions? options = null) { - return WriteCoreBytes( - value!, - GetRuntimeTypeAndValidateInputType(value, inputType), - options); + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteBytesUsingSerializer(value, jsonTypeInfo); } /// @@ -108,14 +108,8 @@ public static byte[] SerializeToUtf8Bytes(object? value, Type inputType, JsonSer } Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - return WriteBytesUsingGeneratedSerializer(value!, GetTypeInfo(context, runtimeType)); - } - - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static byte[] WriteCoreBytes(in TValue value, Type runtimeType, JsonSerializerOptions? options) - { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); - return WriteBytesUsingSerializer(value, jsonTypeInfo); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, runtimeType); + return WriteBytesUsingGeneratedSerializer(value!, jsonTypeInfo); } private static byte[] WriteBytesUsingGeneratedSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs index 5aa1ada5a39c00..901d4d6cab9d63 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs @@ -37,6 +37,8 @@ private static bool WriteCore( private static void WriteUsingGeneratedSerializer(Utf8JsonWriter writer, in TValue value, JsonTypeInfo jsonTypeInfo) { + Debug.Assert(writer != null); + if (jsonTypeInfo.HasSerialize && jsonTypeInfo is JsonTypeInfo typedInfo && typedInfo.Options._context?.CanUseSerializationLogic == true) @@ -53,7 +55,10 @@ jsonTypeInfo is JsonTypeInfo typedInfo && private static void WriteUsingSerializer(Utf8JsonWriter writer, in TValue value, JsonTypeInfo jsonTypeInfo) { - Debug.Assert(jsonTypeInfo is not JsonTypeInfo, "Incorrect method called."); + Debug.Assert(writer != null); + + Debug.Assert(!jsonTypeInfo.HasSerialize || + jsonTypeInfo is not JsonTypeInfo, "Incorrect method called."); WriteStack state = default; state.Initialize(jsonTypeInfo, supportContinuation: false); From ee345f69c48ca78be9a7f7cd327ff12d3fbca118 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 13 Aug 2021 14:38:44 -0500 Subject: [PATCH 3/7] Fix up entry method coding patterns --- .../JsonSerializer.Write.ByteArray.cs | 3 +- .../JsonSerializer.Write.Element.cs | 4 +- .../JsonSerializer.Write.Node.cs | 4 +- .../JsonSerializer.Write.Stream.cs | 68 +++++-------------- 4 files changed, 23 insertions(+), 56 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs index 6a8333ac0f3d6f..5e7bd64a797e3c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs @@ -24,7 +24,8 @@ public static byte[] SerializeToUtf8Bytes( TValue value, JsonSerializerOptions? options = null) { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); + Type runtimeType = GetRuntimeType(value); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); return WriteBytesUsingSerializer(value, jsonTypeInfo); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Element.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Element.cs index 4c4d6e70a6c7ad..be7f27e3820ff9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Element.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Element.cs @@ -48,8 +48,8 @@ public static JsonElement SerializeToElement(TValue value, JsonSerialize [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] public static JsonElement SerializeToElement(object? value, Type inputType, JsonSerializerOptions? options = null) { - Type type = GetRuntimeTypeAndValidateInputType(value, inputType); - JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, type); + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); return WriteElementUsingSerializer(value, jsonTypeInfo); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs index 4266d29dc7fe52..29a603dcf49535 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs @@ -102,8 +102,8 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(context)); } - Type type = GetRuntimeTypeAndValidateInputType(value, inputType); - return WriteNodeUsingGeneratedSerializer(value, GetTypeInfo(context, type)); + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + return WriteNodeUsingGeneratedSerializer(value, GetTypeInfo(context, runtimeType)); } private static JsonNode? WriteNodeUsingGeneratedSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs index 90bdabd127be56..3f4ca142986364 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs @@ -48,15 +48,11 @@ public static Task SerializeAsync( throw new ArgumentNullException(nameof(utf8Json)); } - return WriteAsync( - utf8Json, - value, - GetRuntimeType(value), - options, - cancellationToken); + Type runtimeType = GetRuntimeType(value); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteStreamAsync(utf8Json, value!, jsonTypeInfo, cancellationToken); } - /// /// Converts the provided value to UTF-8 encoded JSON text and write it to the . /// @@ -81,11 +77,9 @@ public static void Serialize( throw new ArgumentNullException(nameof(utf8Json)); } - Write( - utf8Json, - value, - GetRuntimeType(value), - options); + Type runtimeType = GetRuntimeType(value); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + WriteStream(utf8Json, value!, jsonTypeInfo); } /// @@ -120,12 +114,9 @@ public static Task SerializeAsync( throw new ArgumentNullException(nameof(utf8Json)); } - return WriteAsync( - utf8Json, - value!, - GetRuntimeTypeAndValidateInputType(value, inputType), - options, - cancellationToken); + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + return WriteStreamAsync(utf8Json, value!, jsonTypeInfo, cancellationToken); } /// @@ -157,11 +148,9 @@ public static void Serialize( throw new ArgumentNullException(nameof(utf8Json)); } - Write( - utf8Json, - value!, - GetRuntimeTypeAndValidateInputType(value, inputType), - options); + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); + WriteStream(utf8Json, value!, jsonTypeInfo); } /// @@ -226,7 +215,7 @@ public static void Serialize( throw new ArgumentNullException(nameof(jsonTypeInfo)); } - WriteCore(utf8Json, value, jsonTypeInfo); + WriteStream(utf8Json, value, jsonTypeInfo); } /// @@ -266,7 +255,7 @@ public static Task SerializeAsync( } Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - return WriteAsyncCore( + return WriteStreamAsync( utf8Json, value!, GetTypeInfo(context, runtimeType), @@ -307,33 +296,10 @@ public static void Serialize( } Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - WriteCore(utf8Json, value!, GetTypeInfo(context, runtimeType)); - } - - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static Task WriteAsync( - Stream utf8Json, - in TValue value, - Type runtimeType, - JsonSerializerOptions? options, - CancellationToken cancellationToken) - { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); - return WriteAsyncCore(utf8Json, value!, jsonTypeInfo, cancellationToken); - } - - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - private static void Write( - Stream utf8Json, - in TValue value, - Type runtimeType, - JsonSerializerOptions? options) - { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, runtimeType); - WriteCore(utf8Json, value!, jsonTypeInfo); + WriteStream(utf8Json, value!, GetTypeInfo(context, runtimeType)); } - private static async Task WriteAsyncCore( + private static async Task WriteStreamAsync( Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, @@ -394,7 +360,7 @@ private static async Task WriteAsyncCore( } } - private static void WriteCore( + private static void WriteStream( Stream utf8Json, in TValue value, JsonTypeInfo jsonTypeInfo) From e1d10a7520c9b5d67d331272898c3ad9128f5ead Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 13 Aug 2021 15:42:23 -0500 Subject: [PATCH 4/7] 2: Change main null check in TryWrite(); other misc --- .../Text/Json/Serialization/JsonSerializer.Write.Stream.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs index 3f4ca142986364..bd04e358b11aa1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs @@ -184,7 +184,7 @@ public static Task SerializeAsync( throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return WriteAsyncCore(utf8Json, value, jsonTypeInfo, cancellationToken); + return WriteStreamAsync(utf8Json, value, jsonTypeInfo, cancellationToken); } /// From 39bab2217b75fd21663993e51c9286003012b190 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 13 Aug 2021 17:52:22 -0500 Subject: [PATCH 5/7] fix assert --- .../Text/Json/Serialization/JsonSerializer.Write.Helpers.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs index 901d4d6cab9d63..d7f80b2a7bba78 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs @@ -58,7 +58,10 @@ private static void WriteUsingSerializer(Utf8JsonWriter writer, in TValu Debug.Assert(writer != null); Debug.Assert(!jsonTypeInfo.HasSerialize || - jsonTypeInfo is not JsonTypeInfo, "Incorrect method called."); + jsonTypeInfo is not JsonTypeInfo || + jsonTypeInfo.Options._context == null || + !jsonTypeInfo.Options._context.CanUseSerializationLogic, + "Incorrect method called. WriteUsingGeneratedSerializer() should have been called instead."); WriteStack state = default; state.Initialize(jsonTypeInfo, supportContinuation: false); From 77bb810244d254a773a2a3d556e8d803fea79855 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Sun, 15 Aug 2021 11:22:02 -0500 Subject: [PATCH 6/7] Make IsNull() private static. Other misc non-functional --- .../Text/Json/Serialization/JsonConverterOfT.cs | 6 ++++-- .../Json/Serialization/JsonSerializer.Helpers.cs | 4 +++- .../Serialization/JsonSerializer.Read.Helpers.cs | 2 +- .../Serialization/JsonSerializer.Write.Helpers.cs | 4 ++-- .../Json/Serialization/JsonSerializer.Write.Node.cs | 3 ++- .../Text/Json/Serialization/JsonSerializerOptions.cs | 12 ++++++++++-- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs index 714332bef36b00..6c6f4a56f1ca11 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs @@ -314,9 +314,11 @@ internal override sealed bool TryReadAsObject(ref Utf8JsonReader reader, JsonSer } /// - /// Performance optimization. The 'in' modifier in TryWrite(in T Value) will cause boxing, so this helper method avoids that. + /// Performance optimization. + /// The 'in' modifier in 'TryWrite(in T Value)' causes boxing for Nullable{T}, so this helper avoids that. + /// TODO: Remove this work-around once #50915 is addressed. /// - internal bool IsNull(T value) => value is null; + private static bool IsNull(T value) => value is null; #if NET6_0_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveOptimization)] diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs index d0ce95e169546a..02ad7870814207 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs @@ -15,6 +15,8 @@ public static partial class JsonSerializer [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] private static JsonTypeInfo GetTypeInfo(JsonSerializerOptions? options, Type runtimeType) { + Debug.Assert(runtimeType != null); + options ??= JsonSerializerOptions.s_defaultOptions; if (!options.IsInitializedForReflectionSerializer) { @@ -30,7 +32,7 @@ private static JsonTypeInfo GetTypeInfo(JsonSerializerContext context, Type type Debug.Assert(type != null); JsonTypeInfo? info = context.GetTypeInfo(type); - if (info == null) + if (info is null) { ThrowHelper.ThrowInvalidOperationException_NoMetadataForType(type); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs index ebaa15ed54be27..608e33242e924a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs @@ -23,7 +23,7 @@ public static partial class JsonSerializer return (TValue?)value; } - private static TValue? ReadSpan(ReadOnlySpan utf8Json, JsonTypeInfo jsonTypeInfo, int? actualByteCount = null) + private static TValue? ReadFromSpan(ReadOnlySpan utf8Json, JsonTypeInfo jsonTypeInfo, int? actualByteCount = null) { JsonSerializerOptions options = jsonTypeInfo.Options; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs index d7f80b2a7bba78..4f100523bf486c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs @@ -98,12 +98,12 @@ private static Type GetRuntimeType(in TValue value) private static Type GetRuntimeTypeAndValidateInputType(object? value, Type inputType) { - if (inputType == null) + if (inputType is null) { throw new ArgumentNullException(nameof(inputType)); } - if (value != null) + if (value is not null) { Type runtimeType = value.GetType(); if (!inputType.IsAssignableFrom(runtimeType)) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs index 29a603dcf49535..8fad9e11757a21 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Node.cs @@ -103,7 +103,8 @@ public static partial class JsonSerializer } Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - return WriteNodeUsingGeneratedSerializer(value, GetTypeInfo(context, runtimeType)); + JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, runtimeType); + return WriteNodeUsingGeneratedSerializer(value, jsonTypeInfo); } private static JsonNode? WriteNodeUsingGeneratedSerializer(in TValue value, JsonTypeInfo jsonTypeInfo) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 8e5be33ad7ac46..2d23e7c5c9200b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -247,8 +247,6 @@ public JsonNamingPolicy? DictionaryKeyPolicy } } - internal bool IsInitializedForReflectionSerializer { get; set; } - /// /// Determines whether null values are ignored during serialization and deserialization. /// The default value is false. @@ -577,6 +575,15 @@ internal MemberAccessor MemberAccessorStrategy } } + /// + /// Whether needs to be called. + /// + internal bool IsInitializedForReflectionSerializer { get; set; } + + /// + /// Initializes the converters for the reflection-based serializer. + /// must be checked before calling. + /// [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] internal void InitializeForReflectionSerializer() { @@ -624,6 +631,7 @@ internal JsonTypeInfo GetClassFromContextOrCreate(Type type) /// Return the TypeInfo for root API calls. /// This has a LRU cache that is intended only for public API calls that specify the root type. /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal JsonTypeInfo GetOrAddClassForRootType(Type type) { JsonTypeInfo? jsonTypeInfo = _lastClass; From d2852adb495f88fca638cdbaaa91bbb019cf85d2 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Sun, 15 Aug 2021 12:33:57 -0500 Subject: [PATCH 7/7] ReadSpan() -> ReadFromSpan() naming --- .../Json/Serialization/JsonSerializer.Read.Document.cs | 2 +- .../Json/Serialization/JsonSerializer.Read.Element.cs | 2 +- .../Text/Json/Serialization/JsonSerializer.Read.Node.cs | 2 +- .../Text/Json/Serialization/JsonSerializer.Read.Span.cs | 8 ++++---- .../Text/Json/Serialization/JsonSerializer.Read.String.cs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Document.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Document.cs index dd2b3d3852eb0e..b9dd114987c2e9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Document.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Document.cs @@ -166,7 +166,7 @@ public static partial class JsonSerializer private static TValue? ReadDocument(JsonDocument document, JsonTypeInfo jsonTypeInfo) { ReadOnlySpan utf8Json = document.GetRootRawValue().Span; - return ReadSpan(utf8Json, jsonTypeInfo); + return ReadFromSpan(utf8Json, jsonTypeInfo); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs index 51f8f9fadc7569..14a2306c7cba65 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs @@ -135,7 +135,7 @@ public static partial class JsonSerializer private static TValue? ReadUsingMetadata(JsonElement element, JsonTypeInfo jsonTypeInfo) { ReadOnlySpan utf8Json = element.GetRawValue().Span; - return ReadSpan(utf8Json, jsonTypeInfo); + return ReadFromSpan(utf8Json, jsonTypeInfo); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Node.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Node.cs index 49a3c7b6c19c04..2c496d3d0a5c98 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Node.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Node.cs @@ -149,7 +149,7 @@ public static partial class JsonSerializer } } - return ReadSpan(output.WrittenMemory.Span, jsonTypeInfo); + return ReadFromSpan(output.WrittenMemory.Span, jsonTypeInfo); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs index f8e2e8312c245e..3327b2a227d124 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs @@ -28,7 +28,7 @@ public static partial class JsonSerializer public static TValue? Deserialize(ReadOnlySpan utf8Json, JsonSerializerOptions? options = null) { JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, typeof(TValue)); - return ReadSpan(utf8Json, jsonTypeInfo); + return ReadFromSpan(utf8Json, jsonTypeInfo); } /// @@ -59,7 +59,7 @@ public static partial class JsonSerializer } JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); - return ReadSpan(utf8Json, jsonTypeInfo); + return ReadFromSpan(utf8Json, jsonTypeInfo); } /// @@ -84,7 +84,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return ReadSpan(utf8Json, jsonTypeInfo); + return ReadFromSpan(utf8Json, jsonTypeInfo); } /// @@ -122,7 +122,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(context)); } - return ReadSpan(utf8Json, GetTypeInfo(context, returnType)); + return ReadFromSpan(utf8Json, GetTypeInfo(context, returnType)); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs index 8694f7ac328fa1..7d780010e10814 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs @@ -386,7 +386,7 @@ public static partial class JsonSerializer { int actualByteCount = JsonReaderHelper.GetUtf8FromText(json, utf8); utf8 = utf8.Slice(0, actualByteCount); - return ReadSpan(utf8, jsonTypeInfo, actualByteCount); + return ReadFromSpan(utf8, jsonTypeInfo, actualByteCount); } finally {