Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Devirtualized default value comparison #37674

Merged
merged 4 commits into from
Jun 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
Expand Down Expand Up @@ -76,8 +75,6 @@ internal override sealed JsonParameterInfo CreateJsonParameterInfo()
/// </summary>
internal bool IsInternalConverter { get; set; }

internal readonly EqualityComparer<T> _defaultComparer = EqualityComparer<T>.Default;

// This non-generic API is sealed as it just forwards to the generic version.
internal sealed override bool TryWriteAsObject(Utf8JsonWriter writer, object? value, JsonSerializerOptions options, ref WriteStack state)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;

namespace System.Text.Json
Expand All @@ -16,8 +16,6 @@ namespace System.Text.Json
/// or a type's converter, if the current instance is a <see cref="JsonClassInfo.PropertyInfoForClassInfo"/>.
internal sealed class JsonPropertyInfo<T> : JsonPropertyInfo
{
private static readonly T s_defaultValue = default!;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless of the rest of the change, there's definitely no need for this to exist.

Copy link
Member

@steveharter steveharter Jun 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@layomia was this intended to actually contain a non-default value at some point in the future (when that feature is added)? e.g. System.String may want a default value of "" instead of null.

However, if\when we allow specifying a default value, we'd want an instance variable on this class (and\or on JsonClassInfo), not a static.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this intended to actually contain a non-default value at some point in the future (when that feature is added)?

Yup. No need to add it until we have that support - #36236.

we'd want an instance variable on this class (and\or on JsonClassInfo), not a static.

👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, but if this should be done for strings which is a ref type, then the comparer should be used in both branches, or they must be merged.


public Func<object, T>? Get { get; private set; }
public Action<object, T>? Set { get; private set; }

Expand Down Expand Up @@ -97,44 +95,45 @@ public override JsonConverter ConverterBase

public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer)
{
bool success;
T value = Get!(obj);

// Since devirtualization only works in non-shared generics,
// the default comparer is uded only for value types for now.
// For reference types there is a quick check for null.
if (IgnoreDefaultValuesOnWrite && (
default(T) == null ? value == null : EqualityComparer<T>.Default.Equals(default, value)))
{
return true;
}

if (value == null)
{
Debug.Assert(s_defaultValue == null && Converter.CanBeNull);
Debug.Assert(Converter.CanBeNull);

success = true;
if (!IgnoreDefaultValuesOnWrite)
if (Converter.HandleNull)
{
if (!Converter.HandleNull)
// No object, collection, or re-entrancy converter handles null.
Debug.Assert(Converter.ClassType == ClassType.Value);

if (state.Current.PropertyState < StackFramePropertyState.Name)
{
writer.WriteNullSection(EscapedNameSection);
state.Current.PropertyState = StackFramePropertyState.Name;
writer.WritePropertyNameSection(EscapedNameSection);
}
else

int originalDepth = writer.CurrentDepth;
Converter.Write(writer, value, Options);
if (originalDepth != writer.CurrentDepth)
{
// No object, collection, or re-entrancy converter handles null.
Debug.Assert(Converter.ClassType == ClassType.Value);

if (state.Current.PropertyState < StackFramePropertyState.Name)
{
state.Current.PropertyState = StackFramePropertyState.Name;
writer.WritePropertyNameSection(EscapedNameSection);
}

int originalDepth = writer.CurrentDepth;
Converter.Write(writer, value, Options);
if (originalDepth != writer.CurrentDepth)
{
ThrowHelper.ThrowJsonException_SerializationConverterWrite(Converter);
}
ThrowHelper.ThrowJsonException_SerializationConverterWrite(Converter);
}
}
}
else if (IgnoreDefaultValuesOnWrite && Converter._defaultComparer.Equals(s_defaultValue, value))
{
Debug.Assert(s_defaultValue != null && !Converter.CanBeNull);
success = true;
else
{
writer.WriteNullSection(EscapedNameSection);
}

return true;
}
else
{
Expand All @@ -144,10 +143,8 @@ public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf
writer.WritePropertyNameSection(EscapedNameSection);
}

success = Converter.TryWrite(writer, value, Options, ref state);
return Converter.TryWrite(writer, value, Options, ref state);
}

return success;
}

public override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer)
Expand Down Expand Up @@ -179,7 +176,7 @@ public override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref U
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Converter.TypeToConvert);
}

Debug.Assert(s_defaultValue == null);
Debug.Assert(default(T) == null);

if (!IgnoreDefaultValuesOnRead)
{
Expand Down