|
4 | 4 | using System;
|
5 | 5 | using System.Buffers.Binary;
|
6 | 6 | using System.Collections;
|
| 7 | +using System.Collections.Concurrent; |
7 | 8 | using System.Collections.Generic;
|
8 | 9 | using System.Collections.ObjectModel;
|
9 | 10 | using System.Diagnostics;
|
@@ -297,19 +298,16 @@ internal virtual bool IsValidContract()
|
297 | 298 |
|
298 | 299 | internal class DataContractCriticalHelper
|
299 | 300 | {
|
300 |
| - private static readonly Hashtable s_typeToIDCache = new Hashtable(new HashTableEqualityComparer()); |
| 301 | + private static readonly ConcurrentDictionary<nint, int> s_typeToIDCache = new(); |
301 | 302 | private static DataContract[] s_dataContractCache = new DataContract[32];
|
302 | 303 | private static int s_dataContractID;
|
303 |
| - private static Dictionary<Type, DataContract?>? s_typeToBuiltInContract; |
| 304 | + private static readonly ConcurrentDictionary<Type, DataContract?> s_typeToBuiltInContract = new(); |
304 | 305 | private static Dictionary<XmlQualifiedName, DataContract?>? s_nameToBuiltInContract;
|
305 | 306 | private static Dictionary<string, DataContract?>? s_typeNameToBuiltInContract;
|
306 | 307 | private static readonly Hashtable s_namespaces = new Hashtable();
|
307 | 308 | private static Dictionary<string, XmlDictionaryString>? s_clrTypeStrings;
|
308 | 309 | private static XmlDictionary? s_clrTypeStringsDictionary;
|
309 | 310 |
|
310 |
| - [ThreadStatic] |
311 |
| - private static TypeHandleRef? s_typeHandleRef; |
312 |
| - |
313 | 311 | private static readonly object s_cacheLock = new object();
|
314 | 312 | private static readonly object s_createDataContractLock = new object();
|
315 | 313 | private static readonly object s_initBuiltInContractsLock = new object();
|
@@ -393,36 +391,29 @@ private static bool ContractMatches(DataContract contract, DataContract cachedCo
|
393 | 391 | internal static int GetId(RuntimeTypeHandle typeHandle)
|
394 | 392 | {
|
395 | 393 | typeHandle = GetDataContractAdapterTypeHandle(typeHandle);
|
396 |
| - s_typeHandleRef ??= new TypeHandleRef(); |
397 |
| - s_typeHandleRef.Value = typeHandle; |
398 | 394 |
|
399 |
| - object? value = s_typeToIDCache[s_typeHandleRef]; |
400 |
| - if (value != null) |
401 |
| - return ((IntRef)value).Value; |
| 395 | + if (s_typeToIDCache.TryGetValue(typeHandle.Value, out int id)) |
| 396 | + return id; |
402 | 397 |
|
403 | 398 | try
|
404 | 399 | {
|
405 | 400 | lock (s_cacheLock)
|
406 | 401 | {
|
407 |
| - value = s_typeToIDCache[s_typeHandleRef]; |
408 |
| - if (value != null) |
409 |
| - return ((IntRef)value).Value; |
410 |
| - |
411 |
| - int nextId = s_dataContractID++; |
412 |
| - if (nextId >= s_dataContractCache.Length) |
| 402 | + return s_typeToIDCache.GetOrAdd(typeHandle.Value, static _ => |
413 | 403 | {
|
414 |
| - int newSize = (nextId < int.MaxValue / 2) ? nextId * 2 : int.MaxValue; |
415 |
| - if (newSize <= nextId) |
| 404 | + int nextId = s_dataContractID++; |
| 405 | + if (nextId >= s_dataContractCache.Length) |
416 | 406 | {
|
417 |
| - Debug.Fail("DataContract cache overflow"); |
418 |
| - throw new SerializationException(SR.DataContractCacheOverflow); |
| 407 | + int newSize = (nextId < int.MaxValue / 2) ? nextId * 2 : int.MaxValue; |
| 408 | + if (newSize <= nextId) |
| 409 | + { |
| 410 | + Debug.Fail("DataContract cache overflow"); |
| 411 | + throw new SerializationException(SR.DataContractCacheOverflow); |
| 412 | + } |
| 413 | + Array.Resize<DataContract>(ref s_dataContractCache, newSize); |
419 | 414 | }
|
420 |
| - Array.Resize<DataContract>(ref s_dataContractCache, newSize); |
421 |
| - } |
422 |
| - IntRef id = new IntRef(nextId); |
423 |
| - |
424 |
| - s_typeToIDCache.Add(new TypeHandleRef(typeHandle), id); |
425 |
| - return id.Value; |
| 415 | + return nextId; |
| 416 | + }); |
426 | 417 | }
|
427 | 418 | }
|
428 | 419 | catch (Exception ex) when (!ExceptionUtility.IsFatal(ex))
|
@@ -589,17 +580,11 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan
|
589 | 580 | if (type.IsInterface && !CollectionDataContract.IsCollectionInterface(type))
|
590 | 581 | type = Globals.TypeOfObject;
|
591 | 582 |
|
592 |
| - lock (s_initBuiltInContractsLock) |
| 583 | + return s_typeToBuiltInContract.GetOrAdd(type, static (Type key) => |
593 | 584 | {
|
594 |
| - s_typeToBuiltInContract ??= new Dictionary<Type, DataContract?>(); |
595 |
| - |
596 |
| - if (!s_typeToBuiltInContract.TryGetValue(type, out DataContract? dataContract)) |
597 |
| - { |
598 |
| - TryCreateBuiltInDataContract(type, out dataContract); |
599 |
| - s_typeToBuiltInContract.Add(type, dataContract); |
600 |
| - } |
| 585 | + TryCreateBuiltInDataContract(key, out DataContract? dataContract); |
601 | 586 | return dataContract;
|
602 |
| - } |
| 587 | + }); |
603 | 588 | }
|
604 | 589 |
|
605 | 590 | [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
|
@@ -945,19 +930,8 @@ internal static void ThrowInvalidDataContractException(string? message, Type? ty
|
945 | 930 | {
|
946 | 931 | if (type != null)
|
947 | 932 | {
|
948 |
| - lock (s_cacheLock) |
949 |
| - { |
950 |
| - s_typeHandleRef ??= new TypeHandleRef(); |
951 |
| - s_typeHandleRef.Value = GetDataContractAdapterTypeHandle(type.TypeHandle); |
952 |
| - |
953 |
| - if (s_typeToIDCache.ContainsKey(s_typeHandleRef)) |
954 |
| - { |
955 |
| - lock (s_cacheLock) |
956 |
| - { |
957 |
| - s_typeToIDCache.Remove(s_typeHandleRef); |
958 |
| - } |
959 |
| - } |
960 |
| - } |
| 933 | + RuntimeTypeHandle runtimeTypeHandle = GetDataContractAdapterTypeHandle(type.TypeHandle); |
| 934 | + s_typeToIDCache.TryRemove(runtimeTypeHandle.Value, out _); |
961 | 935 | }
|
962 | 936 |
|
963 | 937 | throw new InvalidDataContractException(message);
|
@@ -2515,62 +2489,4 @@ public override int GetHashCode()
|
2515 | 2489 | return _object1.GetHashCode() ^ _object2.GetHashCode();
|
2516 | 2490 | }
|
2517 | 2491 | }
|
2518 |
| - |
2519 |
| - internal sealed class HashTableEqualityComparer : IEqualityComparer |
2520 |
| - { |
2521 |
| - bool IEqualityComparer.Equals(object? x, object? y) |
2522 |
| - { |
2523 |
| - return ((TypeHandleRef)x!).Value.Equals(((TypeHandleRef)y!).Value); |
2524 |
| - } |
2525 |
| - |
2526 |
| - public int GetHashCode(object obj) |
2527 |
| - { |
2528 |
| - return ((TypeHandleRef)obj).Value.GetHashCode(); |
2529 |
| - } |
2530 |
| - } |
2531 |
| - |
2532 |
| - internal sealed class TypeHandleRefEqualityComparer : IEqualityComparer<TypeHandleRef> |
2533 |
| - { |
2534 |
| - public bool Equals(TypeHandleRef? x, TypeHandleRef? y) |
2535 |
| - { |
2536 |
| - return x!.Value.Equals(y!.Value); |
2537 |
| - } |
2538 |
| - |
2539 |
| - public int GetHashCode(TypeHandleRef obj) |
2540 |
| - { |
2541 |
| - return obj.Value.GetHashCode(); |
2542 |
| - } |
2543 |
| - } |
2544 |
| - |
2545 |
| - internal sealed class TypeHandleRef |
2546 |
| - { |
2547 |
| - private RuntimeTypeHandle _value; |
2548 |
| - |
2549 |
| - public TypeHandleRef() |
2550 |
| - { |
2551 |
| - } |
2552 |
| - |
2553 |
| - public TypeHandleRef(RuntimeTypeHandle value) |
2554 |
| - { |
2555 |
| - _value = value; |
2556 |
| - } |
2557 |
| - |
2558 |
| - public RuntimeTypeHandle Value |
2559 |
| - { |
2560 |
| - get => _value; |
2561 |
| - set => _value = value; |
2562 |
| - } |
2563 |
| - } |
2564 |
| - |
2565 |
| - internal sealed class IntRef |
2566 |
| - { |
2567 |
| - private readonly int _value; |
2568 |
| - |
2569 |
| - public IntRef(int value) |
2570 |
| - { |
2571 |
| - _value = value; |
2572 |
| - } |
2573 |
| - |
2574 |
| - public int Value => _value; |
2575 |
| - } |
2576 | 2492 | }
|
0 commit comments