Skip to content

Commit

Permalink
Replace Hashtables with generic ConcurrentDictionaries
Browse files Browse the repository at this point in the history
  • Loading branch information
gpetrou committed Oct 26, 2019
1 parent 506a1c8 commit 758fcdb
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 89 deletions.
120 changes: 43 additions & 77 deletions Src/Microsoft.Dynamic/ComInterop/ComTypeDesc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,19 @@
#if FEATURE_COM

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices.ComTypes;
using System.Threading;

namespace Microsoft.Scripting.ComInterop {

public class ComTypeDesc : ComTypeLibMemberDesc {
private string _typeName;
private string _documentation;
//Hashtable is threadsafe for multiple readers single writer.
//Enumerating and writing is mutually exclusive so require locking.
private Hashtable _funcs;
private Hashtable _puts;
private Hashtable _putRefs;
private readonly string _typeName;
private readonly string _documentation;
private ComMethodDesc _getItem;
private ComMethodDesc _setItem;
private Dictionary<string, ComEventDesc> _events;
private static readonly Dictionary<string, ComEventDesc> _EmptyEventsDict = new Dictionary<string, ComEventDesc>();

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

internal static ComTypeDesc CreateEmptyTypeDesc() {
ComTypeDesc typeDesc = new ComTypeDesc(null, ComType.Interface, null);
typeDesc._funcs = new Hashtable();
typeDesc._puts = new Hashtable();
typeDesc._putRefs = new Hashtable();
typeDesc._events = _EmptyEventsDict;
typeDesc.Funcs = new ConcurrentDictionary<string, ComMethodDesc>();
typeDesc.Puts = new ConcurrentDictionary<string, ComMethodDesc>();
typeDesc.PutRefs = new ConcurrentDictionary<string, ComMethodDesc>();
typeDesc.Events = _EmptyEventsDict;

return typeDesc;
}

internal static Dictionary<string, ComEventDesc> EmptyEvents {
get { return _EmptyEventsDict; }
}
internal static Dictionary<string, ComEventDesc> EmptyEvents => _EmptyEventsDict;

internal Hashtable Funcs {
get { return _funcs; }
set { _funcs = value; }
}
internal ConcurrentDictionary<string, ComMethodDesc> Funcs { get; set; }

internal Hashtable Puts {
get { return _puts; }
set { _puts = value; }
}
internal ConcurrentDictionary<string, ComMethodDesc> Puts { get; set; }

internal Hashtable PutRefs {
set { _putRefs = value; }
}
internal ConcurrentDictionary<string, ComMethodDesc> PutRefs { get; set; }

internal Dictionary<string, ComEventDesc> Events {
get { return _events; }
set { _events = value; }
}
internal Dictionary<string, ComEventDesc> Events { get; set; }

internal bool TryGetFunc(string name, out ComMethodDesc method) {
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
if (_funcs.ContainsKey(name)) {
method = _funcs[name] as ComMethodDesc;
name = name.ToUpper(CultureInfo.InvariantCulture);
if (Funcs.TryGetValue(name, out method)) {
return true;
}
method = null;

return false;
}

internal void AddFunc(string name, ComMethodDesc method) {
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
lock (_funcs) {
_funcs[name] = method;
}
name = name.ToUpper(CultureInfo.InvariantCulture);
Funcs[name] = method;
}

internal bool TryGetPut(string name, out ComMethodDesc method) {
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
if (_puts.ContainsKey(name)) {
method = _puts[name] as ComMethodDesc;
name = name.ToUpper(CultureInfo.InvariantCulture);
if (Puts.TryGetValue(name, out method)) {
return true;
}
method = null;

return false;
}

internal void AddPut(string name, ComMethodDesc method) {
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
lock (_puts) {
_puts[name] = method;
}
name = name.ToUpper(CultureInfo.InvariantCulture);
Puts[name] = method;
}

internal bool TryGetPutRef(string name, out ComMethodDesc method) {
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
if (_putRefs.ContainsKey(name)) {
method = _putRefs[name] as ComMethodDesc;
name = name.ToUpper(CultureInfo.InvariantCulture);
if (PutRefs.TryGetValue(name, out method)) {
return true;
}
method = null;

return false;
}
internal void AddPutRef(string name, ComMethodDesc method) {
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
lock (_putRefs) {
_putRefs[name] = method;
}
name = name.ToUpper(CultureInfo.InvariantCulture);
PutRefs[name] = method;

}

internal bool TryGetEvent(string name, out ComEventDesc @event) {
name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
return _events.TryGetValue(name, out @event);
name = name.ToUpper(CultureInfo.InvariantCulture);
return Events.TryGetValue(name, out @event);
}

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

lock (_funcs) {
foreach (ComMethodDesc func in _funcs.Values) {
lock (Funcs) {
foreach (ComMethodDesc func in Funcs.Values) {
if (!dataOnly || func.IsDataMember) {
names.Add(func.Name, null);
}
}
}

if (!dataOnly) {
lock (_puts) {
foreach (ComMethodDesc func in _puts.Values) {
lock (Puts) {
foreach (ComMethodDesc func in Puts.Values) {
if (!names.ContainsKey(func.Name)) {
names.Add(func.Name, null);
}
}
}

lock (_putRefs) {
foreach (ComMethodDesc func in _putRefs.Values) {
lock (PutRefs) {
foreach (ComMethodDesc func in PutRefs.Values) {
if (!names.ContainsKey(func.Name)) {
names.Add(func.Name, null);
}
}
}

if (_events != null && _events.Count > 0) {
foreach (string name in _events.Keys) {
if (Events != null && Events.Count > 0) {
foreach (string name in Events.Keys) {
if (!names.ContainsKey(name)) {
names.Add(name, null);
}
Expand All @@ -180,30 +154,22 @@ internal static ComTypeDesc FromITypeInfo(ITypeInfo typeInfo, TYPEATTR typeAttr)
}

// this property is public - accessed by an AST
public string TypeName {
get { return _typeName; }
}
public string TypeName => _typeName;

internal string Documentation {
get { return _documentation; }
}
internal string Documentation => _documentation;

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

internal Guid Guid { get; set; }

internal ComMethodDesc GetItem {
get { return _getItem; }
}
internal ComMethodDesc GetItem => _getItem;

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

internal ComMethodDesc SetItem {
get { return _setItem; }
}
internal ComMethodDesc SetItem => _setItem;

internal void EnsureSetItem(ComMethodDesc candidate) {
Interlocked.CompareExchange(ref _setItem, candidate, null);
Expand Down
23 changes: 11 additions & 12 deletions Src/Microsoft.Dynamic/ComInterop/IDispatchComObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@
// See the LICENSE file in the project root for more information.

#if FEATURE_COM
using System.Linq.Expressions;

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.Globalization;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;

using ComTypes = System.Runtime.InteropServices.ComTypes;
using System.Dynamic;

namespace Microsoft.Scripting.ComInterop {

Expand Down Expand Up @@ -501,9 +500,9 @@ internal IDispatchComObject(IDispatch rcw)

ComMethodDesc getItem = null;
ComMethodDesc setItem = null;
Hashtable funcs = new Hashtable(typeAttr.cFuncs);
Hashtable puts = new Hashtable();
Hashtable putrefs = new Hashtable();
ConcurrentDictionary<string, ComMethodDesc> funcs = new ConcurrentDictionary<string, ComMethodDesc>(Environment.ProcessorCount, typeAttr.cFuncs);
ConcurrentDictionary<string, ComMethodDesc> puts = new ConcurrentDictionary<string, ComMethodDesc>();
ConcurrentDictionary<string, ComMethodDesc> putrefs = new ConcurrentDictionary<string, ComMethodDesc>();

for (int definedFuncIndex = 0; definedFuncIndex < typeAttr.cFuncs; definedFuncIndex++) {
IntPtr funcDescHandleToRelease = IntPtr.Zero;
Expand All @@ -520,7 +519,7 @@ internal IDispatchComObject(IDispatch rcw)
string name = method.Name.ToUpper(CultureInfo.InvariantCulture);

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

// for the special dispId == 0, we need to store
// the method descriptor for the Do(SetItem) binder.
Expand All @@ -530,7 +529,7 @@ internal IDispatchComObject(IDispatch rcw)
continue;
}
if ((funcDesc.invkind & ComTypes.INVOKEKIND.INVOKE_PROPERTYPUTREF) != 0) {
putrefs.Add(name, method);
putrefs.TryAdd(name, method);
// for the special dispId == 0, we need to store
// the method descriptor for the Do(SetItem) binder.
if (method.DispId == ComDispIds.DISPID_VALUE && setItem == null) {
Expand All @@ -540,11 +539,11 @@ internal IDispatchComObject(IDispatch rcw)
}

if (funcDesc.memid == ComDispIds.DISPID_NEWENUM) {
funcs.Add("GETENUMERATOR", method);
funcs.TryAdd("GETENUMERATOR", method);
continue;
}

funcs.Add(name, method);
funcs.TryAdd(name, method);

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

0 comments on commit 758fcdb

Please sign in to comment.