Skip to content

Commit a173c23

Browse files
authored
Replace Hashtables with generic ConcurrentDictionaries (#218)
1 parent 96c4f47 commit a173c23

File tree

2 files changed

+49
-83
lines changed

2 files changed

+49
-83
lines changed

src/core/Microsoft.Dynamic/ComInterop/ComTypeDesc.cs

Lines changed: 41 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
#if FEATURE_COM
66

77
using System;
8-
using System.Collections;
8+
using System.Collections.Concurrent;
99
using System.Collections.Generic;
10+
using System.Globalization;
1011
using System.Runtime.InteropServices.ComTypes;
1112
using System.Threading;
1213

@@ -15,14 +16,8 @@ namespace Microsoft.Scripting.ComInterop {
1516
public class ComTypeDesc : ComTypeLibMemberDesc {
1617
private readonly string _typeName;
1718
private readonly string _documentation;
18-
//Hashtable is threadsafe for multiple readers single writer.
19-
//Enumerating and writing is mutually exclusive so require locking.
20-
private Hashtable _funcs;
21-
private Hashtable _puts;
22-
private Hashtable _putRefs;
2319
private ComMethodDesc _getItem;
2420
private ComMethodDesc _setItem;
25-
private Dictionary<string, ComEventDesc> _events;
2621
private static readonly Dictionary<string, ComEventDesc> _EmptyEventsDict = new();
2722

2823
internal ComTypeDesc(ITypeInfo typeInfo, ComType memberType, ComTypeLibDesc typeLibDesc) : base(memberType) {
@@ -51,122 +46,101 @@ internal static ComTypeDesc FromITypeInfo(ITypeInfo typeInfo, TYPEATTR typeAttr)
5146

5247
internal static ComTypeDesc CreateEmptyTypeDesc() {
5348
ComTypeDesc typeDesc = new ComTypeDesc(null, ComType.Interface, null);
54-
typeDesc._funcs = new Hashtable();
55-
typeDesc._puts = new Hashtable();
56-
typeDesc._putRefs = new Hashtable();
57-
typeDesc._events = _EmptyEventsDict;
49+
typeDesc.Funcs = new ConcurrentDictionary<string, ComMethodDesc>();
50+
typeDesc.Puts = new ConcurrentDictionary<string, ComMethodDesc>();
51+
typeDesc.PutRefs = new ConcurrentDictionary<string, ComMethodDesc>();
52+
typeDesc.Events = _EmptyEventsDict;
5853

5954
return typeDesc;
6055
}
6156

62-
internal static Dictionary<string, ComEventDesc> EmptyEvents {
63-
get { return _EmptyEventsDict; }
64-
}
57+
internal static Dictionary<string, ComEventDesc> EmptyEvents => _EmptyEventsDict;
6558

66-
internal Hashtable Funcs {
67-
get { return _funcs; }
68-
set { _funcs = value; }
69-
}
59+
internal ConcurrentDictionary<string, ComMethodDesc> Funcs { get; set; }
7060

71-
internal Hashtable Puts {
72-
get { return _puts; }
73-
set { _puts = value; }
74-
}
61+
internal ConcurrentDictionary<string, ComMethodDesc> Puts { get; set; }
7562

76-
internal Hashtable PutRefs {
77-
set { _putRefs = value; }
78-
}
63+
internal ConcurrentDictionary<string, ComMethodDesc> PutRefs { get; set; }
7964

80-
internal Dictionary<string, ComEventDesc> Events {
81-
get { return _events; }
82-
set { _events = value; }
83-
}
65+
internal Dictionary<string, ComEventDesc> Events { get; set; }
8466

8567
internal bool TryGetFunc(string name, out ComMethodDesc method) {
86-
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
87-
if (_funcs.ContainsKey(name)) {
88-
method = _funcs[name] as ComMethodDesc;
68+
name = name.ToUpper(CultureInfo.InvariantCulture);
69+
if (Funcs.TryGetValue(name, out method)) {
8970
return true;
9071
}
91-
method = null;
72+
9273
return false;
9374
}
9475

9576
internal void AddFunc(string name, ComMethodDesc method) {
96-
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
97-
lock (_funcs) {
98-
_funcs[name] = method;
99-
}
77+
name = name.ToUpper(CultureInfo.InvariantCulture);
78+
Funcs[name] = method;
10079
}
10180

10281
internal bool TryGetPut(string name, out ComMethodDesc method) {
103-
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
104-
if (_puts.ContainsKey(name)) {
105-
method = _puts[name] as ComMethodDesc;
82+
name = name.ToUpper(CultureInfo.InvariantCulture);
83+
if (Puts.TryGetValue(name, out method)) {
10684
return true;
10785
}
108-
method = null;
86+
10987
return false;
11088
}
11189

11290
internal void AddPut(string name, ComMethodDesc method) {
113-
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
114-
lock (_puts) {
115-
_puts[name] = method;
116-
}
91+
name = name.ToUpper(CultureInfo.InvariantCulture);
92+
Puts[name] = method;
11793
}
11894

11995
internal bool TryGetPutRef(string name, out ComMethodDesc method) {
120-
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
121-
if (_putRefs.ContainsKey(name)) {
122-
method = _putRefs[name] as ComMethodDesc;
96+
name = name.ToUpper(CultureInfo.InvariantCulture);
97+
if (PutRefs.TryGetValue(name, out method)) {
12398
return true;
12499
}
125-
method = null;
100+
126101
return false;
127102
}
128103
internal void AddPutRef(string name, ComMethodDesc method) {
129-
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
130-
lock (_putRefs) {
131-
_putRefs[name] = method;
132-
}
104+
name = name.ToUpper(CultureInfo.InvariantCulture);
105+
PutRefs[name] = method;
106+
133107
}
134108

135109
internal bool TryGetEvent(string name, out ComEventDesc @event) {
136-
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
137-
return _events.TryGetValue(name, out @event);
110+
name = name.ToUpper(CultureInfo.InvariantCulture);
111+
return Events.TryGetValue(name, out @event);
138112
}
139113

140114
internal string[] GetMemberNames(bool dataOnly) {
141115
var names = new Dictionary<string, object>();
142116

143-
lock (_funcs) {
144-
foreach (ComMethodDesc func in _funcs.Values) {
117+
lock (Funcs) {
118+
foreach (ComMethodDesc func in Funcs.Values) {
145119
if (!dataOnly || func.IsDataMember) {
146120
names.Add(func.Name, null);
147121
}
148122
}
149123
}
150124

151125
if (!dataOnly) {
152-
lock (_puts) {
153-
foreach (ComMethodDesc func in _puts.Values) {
126+
lock (Puts) {
127+
foreach (ComMethodDesc func in Puts.Values) {
154128
if (!names.ContainsKey(func.Name)) {
155129
names.Add(func.Name, null);
156130
}
157131
}
158132
}
159133

160-
lock (_putRefs) {
161-
foreach (ComMethodDesc func in _putRefs.Values) {
134+
lock (PutRefs) {
135+
foreach (ComMethodDesc func in PutRefs.Values) {
162136
if (!names.ContainsKey(func.Name)) {
163137
names.Add(func.Name, null);
164138
}
165139
}
166140
}
167141

168-
if (_events is not null && _events.Count > 0) {
169-
foreach (string name in _events.Keys) {
142+
if (Events is not null && Events.Count > 0) {
143+
foreach (string name in Events.Keys) {
170144
if (!names.ContainsKey(name)) {
171145
names.Add(name, null);
172146
}
@@ -180,30 +154,22 @@ internal string[] GetMemberNames(bool dataOnly) {
180154
}
181155

182156
// this property is public - accessed by an AST
183-
public string TypeName {
184-
get { return _typeName; }
185-
}
157+
public string TypeName => _typeName;
186158

187-
internal string Documentation {
188-
get { return _documentation; }
189-
}
159+
internal string Documentation => _documentation;
190160

191161
// this property is public - accessed by an AST
192162
public ComTypeLibDesc TypeLib { get; }
193163

194164
internal Guid Guid { get; set; }
195165

196-
internal ComMethodDesc GetItem {
197-
get { return _getItem; }
198-
}
166+
internal ComMethodDesc GetItem => _getItem;
199167

200168
internal void EnsureGetItem(ComMethodDesc candidate) {
201169
Interlocked.CompareExchange(ref _getItem, candidate, null);
202170
}
203171

204-
internal ComMethodDesc SetItem {
205-
get { return _setItem; }
206-
}
172+
internal ComMethodDesc SetItem => _setItem;
207173

208174
internal void EnsureSetItem(ComMethodDesc candidate) {
209175
Interlocked.CompareExchange(ref _setItem, candidate, null);

src/core/Microsoft.Dynamic/ComInterop/IDispatchComObject.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#pragma warning disable CA1416 // Validate platform compatibility
88

99
using System;
10-
using System.Collections;
10+
using System.Collections.Concurrent;
1111
using System.Collections.Generic;
1212
using System.Diagnostics;
1313
using System.Dynamic;
@@ -503,9 +503,9 @@ private void EnsureScanDefinedMethods() {
503503

504504
ComMethodDesc getItem = null;
505505
ComMethodDesc setItem = null;
506-
Hashtable funcs = new Hashtable(typeAttr.cFuncs);
507-
Hashtable puts = new Hashtable();
508-
Hashtable putrefs = new Hashtable();
506+
ConcurrentDictionary<string, ComMethodDesc> funcs = new ConcurrentDictionary<string, ComMethodDesc>(Environment.ProcessorCount, typeAttr.cFuncs);
507+
ConcurrentDictionary<string, ComMethodDesc> puts = new ConcurrentDictionary<string, ComMethodDesc>();
508+
ConcurrentDictionary<string, ComMethodDesc> putrefs = new ConcurrentDictionary<string, ComMethodDesc>();
509509

510510
for (int definedFuncIndex = 0; definedFuncIndex < typeAttr.cFuncs; definedFuncIndex++) {
511511
IntPtr funcDescHandleToRelease = IntPtr.Zero;
@@ -522,7 +522,7 @@ private void EnsureScanDefinedMethods() {
522522
string name = method.Name.ToUpper(CultureInfo.InvariantCulture);
523523

524524
if ((funcDesc.invkind & ComTypes.INVOKEKIND.INVOKE_PROPERTYPUT) != 0) {
525-
puts.Add(name, method);
525+
puts.TryAdd(name, method);
526526

527527
// for the special dispId == 0, we need to store
528528
// the method descriptor for the Do(SetItem) binder.
@@ -532,7 +532,7 @@ private void EnsureScanDefinedMethods() {
532532
continue;
533533
}
534534
if ((funcDesc.invkind & ComTypes.INVOKEKIND.INVOKE_PROPERTYPUTREF) != 0) {
535-
putrefs.Add(name, method);
535+
putrefs.TryAdd(name, method);
536536
// for the special dispId == 0, we need to store
537537
// the method descriptor for the Do(SetItem) binder.
538538
if (method.DispId == ComDispIds.DISPID_VALUE && setItem is null) {
@@ -542,11 +542,11 @@ private void EnsureScanDefinedMethods() {
542542
}
543543

544544
if (funcDesc.memid == ComDispIds.DISPID_NEWENUM) {
545-
funcs.Add("GETENUMERATOR", method);
545+
funcs.TryAdd("GETENUMERATOR", method);
546546
continue;
547547
}
548548

549-
funcs.Add(name, method);
549+
funcs.TryAdd(name, method);
550550

551551
// for the special dispId == 0, we need to store the method descriptor
552552
// for the Do(GetItem) binder.

0 commit comments

Comments
 (0)