Skip to content

Commit 6b3ec8e

Browse files
Incorporate review feedback from #64646 (#65376)
* Incorporate review feedback from #64646 * Prevent trimming of unused CachingContext.Count method * use correct syntax for nested types
1 parent 10bf322 commit 6b3ec8e

File tree

5 files changed

+27
-14
lines changed

5 files changed

+27
-14
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<linker>
2+
<assembly fullname="System.Text.Json">
3+
<type fullname="System.Text.Json.JsonSerializerOptions/CachingContext">
4+
<!-- Internal API used by tests only. -->
5+
<method name="get_Count" />
6+
</type>
7+
</assembly>
8+
</linker>

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ConverterList.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ namespace System.Text.Json.Serialization
1111
/// </summary>
1212
internal sealed class ConverterList : IList<JsonConverter>
1313
{
14-
private readonly List<JsonConverter> _list = new List<JsonConverter>();
14+
private readonly List<JsonConverter> _list;
1515
private readonly JsonSerializerOptions _options;
1616

1717
public ConverterList(JsonSerializerOptions options)
1818
{
1919
_options = options;
20+
_list = new();
2021
}
2122

2223
public ConverterList(JsonSerializerOptions options, ConverterList source)

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Runtime.CompilerServices;
99
using System.Text.Json.Serialization;
1010
using System.Text.Json.Serialization.Metadata;
11+
using System.Threading;
1112

1213
namespace System.Text.Json
1314
{
@@ -20,8 +21,7 @@ public sealed partial class JsonSerializerOptions
2021
private CachingContext? _cachingContext;
2122

2223
// Simple LRU cache for the public (de)serialize entry points that avoid some lookups in _cachingContext.
23-
// Although this may be written by multiple threads, 'volatile' was not added since any local affinity is fine.
24-
private JsonTypeInfo? _lastTypeInfo;
24+
private volatile JsonTypeInfo? _lastTypeInfo;
2525

2626
internal JsonTypeInfo GetOrAddJsonTypeInfo(Type type)
2727
{
@@ -90,10 +90,11 @@ internal sealed class CachingContext
9090
public CachingContext(JsonSerializerOptions options)
9191
{
9292
Options = options;
93-
_ = Count;
9493
}
9594

9695
public JsonSerializerOptions Options { get; }
96+
// Property only accessed by reflection in testing -- do not remove.
97+
// If changing please ensure that src/ILLink.Descriptors.LibraryBuild.xml is up-to-date.
9798
public int Count => _converterCache.Count + _jsonTypeInfoCache.Count;
9899
public JsonConverter GetOrAddConverter(Type type) => _converterCache.GetOrAdd(type, Options.GetConverterFromType);
99100
public JsonTypeInfo GetOrAddJsonTypeInfo(Type type) => _jsonTypeInfoCache.GetOrAdd(type, Options.GetJsonTypeInfoFromContextOrCreate);
@@ -109,7 +110,7 @@ public void Clear()
109110

110111
/// <summary>
111112
/// Defines a cache of CachingContexts; instead of using a ConditionalWeakTable which can be slow to traverse
112-
/// this approach uses a regular dictionary pointing to weak references of <see cref="CachingContext"/>.
113+
/// this approach uses a concurrent dictionary pointing to weak references of <see cref="CachingContext"/>.
113114
/// Relevant caching contexts are looked up using the equality comparison defined by <see cref="EqualityComparer"/>.
114115
/// </summary>
115116
internal static class TrackedCachingContexts
@@ -188,6 +189,8 @@ private static bool TryEvictDanglingEntries()
188189
// across multiple initializations. The backoff count is determined by the eviction
189190
// rates of the most recent runs.
190191

192+
Debug.Assert(Monitor.IsEntered(s_cache));
193+
191194
if (s_evictionRunsToSkip > 0)
192195
{
193196
--s_evictionRunsToSkip;
@@ -252,7 +255,7 @@ static int EstimateEvictionRunsToSkip(int latestEvictionCount)
252255
/// If two instances are equivalent, they should generate identical metadata caches;
253256
/// the converse however does not necessarily hold.
254257
/// </summary>
255-
private class EqualityComparer : IEqualityComparer<JsonSerializerOptions>
258+
private sealed class EqualityComparer : IEqualityComparer<JsonSerializerOptions>
256259
{
257260
public bool Equals(JsonSerializerOptions? left, JsonSerializerOptions? right)
258261
{
@@ -276,9 +279,9 @@ public bool Equals(JsonSerializerOptions? left, JsonSerializerOptions? right)
276279
left._propertyNameCaseInsensitive == right._propertyNameCaseInsensitive &&
277280
left._writeIndented == right._writeIndented &&
278281
left._serializerContext == right._serializerContext &&
279-
CompareConverters(left.Converters, right.Converters);
282+
CompareConverters(left._converters, right._converters);
280283

281-
static bool CompareConverters(IList<JsonConverter> left, IList<JsonConverter> right)
284+
static bool CompareConverters(ConverterList left, ConverterList right)
282285
{
283286
int n;
284287
if ((n = left.Count) != right.Count)
@@ -321,9 +324,9 @@ public int GetHashCode(JsonSerializerOptions options)
321324
hc.Add(options._writeIndented);
322325
hc.Add(options._serializerContext);
323326

324-
foreach (JsonConverter converter in options.Converters)
327+
for (int i = 0; i < options._converters.Count; i++)
325328
{
326-
hc.Add(converter);
329+
hc.Add(options._converters[i]);
327330
}
328331

329332
return hc.ToHashCode();

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ void Add(JsonConverter converter) =>
9191
/// <remarks>
9292
/// Once serialization or deserialization occurs, the list cannot be modified.
9393
/// </remarks>
94-
public IList<JsonConverter> Converters { get; }
94+
public IList<JsonConverter> Converters => _converters;
9595

9696
internal JsonConverter GetConverterFromMember(Type? parentClassType, Type propertyType, MemberInfo? memberInfo)
9797
{
@@ -183,7 +183,7 @@ private JsonConverter GetConverterFromType(Type typeToConvert)
183183

184184
// Priority 2: Attempt to get custom converter added at runtime.
185185
// Currently there is not a way at runtime to override the [JsonConverter] when applied to a property.
186-
foreach (JsonConverter item in Converters)
186+
foreach (JsonConverter item in _converters)
187187
{
188188
if (item.CanConvert(typeToConvert))
189189
{

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public sealed partial class JsonSerializerOptions
4646
private JsonCommentHandling _readCommentHandling;
4747
private ReferenceHandler? _referenceHandler;
4848
private JavaScriptEncoder? _encoder;
49+
private ConverterList _converters;
4950
private JsonIgnoreCondition _defaultIgnoreCondition;
5051
private JsonNumberHandling _numberHandling;
5152
private JsonUnknownTypeHandling _unknownTypeHandling;
@@ -65,7 +66,7 @@ public sealed partial class JsonSerializerOptions
6566
/// </summary>
6667
public JsonSerializerOptions()
6768
{
68-
Converters = new ConverterList(this);
69+
_converters = new ConverterList(this);
6970
TrackOptionsInstance(this);
7071
}
7172

@@ -98,7 +99,7 @@ public JsonSerializerOptions(JsonSerializerOptions options!!)
9899
_propertyNameCaseInsensitive = options._propertyNameCaseInsensitive;
99100
_writeIndented = options._writeIndented;
100101

101-
Converters = new ConverterList(this, (ConverterList)options.Converters);
102+
_converters = new ConverterList(this, options._converters);
102103
EffectiveMaxDepth = options.EffectiveMaxDepth;
103104
ReferenceHandlingStrategy = options.ReferenceHandlingStrategy;
104105

0 commit comments

Comments
 (0)