From c9293aa4ea7529034950a89fe82b40e8bbf42822 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Tue, 17 Sep 2024 20:04:01 +0100 Subject: [PATCH 1/2] Mitigate JsonObject and JsonValue performance regressions. --- .../src/System/Text/Json/Nodes/JsonObject.cs | 8 ++++++-- .../src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs | 5 ++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs index 20cdc076aac64d..e310382c1f3f53 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs @@ -248,17 +248,21 @@ internal void SetItem(string propertyName, JsonNode? value) OrderedDictionary dict = Dictionary; - if (dict.TryGetValue(propertyName, out JsonNode? replacedValue)) + if (!dict.TryAdd(propertyName, value)) { + int index = dict.IndexOf(propertyName); + Debug.Assert(index >= 0); + JsonNode? replacedValue = dict.GetAt(index).Value; + if (ReferenceEquals(value, replacedValue)) { return; } DetachParent(replacedValue); + dict.SetAt(index, value); } - dict[propertyName] = value; value?.AssignParent(this); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs index fce1d5fbf04cf4..9850046584be4e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs @@ -13,7 +13,7 @@ namespace System.Text.Json.Nodes internal sealed class JsonValuePrimitive : JsonValue { private readonly JsonConverter _converter; - private readonly JsonValueKind _valueKind; + private JsonValueKind? _valueKind; public JsonValuePrimitive(TValue value, JsonConverter converter, JsonNodeOptions? options) : base(value, options) { @@ -21,10 +21,9 @@ public JsonValuePrimitive(TValue value, JsonConverter converter, JsonNod Debug.Assert(converter is { IsInternalConverter: true, ConverterStrategy: ConverterStrategy.Value }); _converter = converter; - _valueKind = DetermineValueKind(value); } - private protected override JsonValueKind GetValueKindCore() => _valueKind; + private protected override JsonValueKind GetValueKindCore() => _valueKind ??= DetermineValueKind(Value); internal override JsonNode DeepCloneCore() => new JsonValuePrimitive(Value, _converter, Options); internal override bool DeepEqualsCore(JsonNode otherNode) From 35584a1dd777d38aa1f1d8c505c45f1c5d30a584 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Tue, 17 Sep 2024 20:41:46 +0100 Subject: [PATCH 2/2] Revert delayed JsonValueKind derivation. --- .../src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs index 9850046584be4e..fce1d5fbf04cf4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfTPrimitive.cs @@ -13,7 +13,7 @@ namespace System.Text.Json.Nodes internal sealed class JsonValuePrimitive : JsonValue { private readonly JsonConverter _converter; - private JsonValueKind? _valueKind; + private readonly JsonValueKind _valueKind; public JsonValuePrimitive(TValue value, JsonConverter converter, JsonNodeOptions? options) : base(value, options) { @@ -21,9 +21,10 @@ public JsonValuePrimitive(TValue value, JsonConverter converter, JsonNod Debug.Assert(converter is { IsInternalConverter: true, ConverterStrategy: ConverterStrategy.Value }); _converter = converter; + _valueKind = DetermineValueKind(value); } - private protected override JsonValueKind GetValueKindCore() => _valueKind ??= DetermineValueKind(Value); + private protected override JsonValueKind GetValueKindCore() => _valueKind; internal override JsonNode DeepCloneCore() => new JsonValuePrimitive(Value, _converter, Options); internal override bool DeepEqualsCore(JsonNode otherNode)