Fix managed method delegate creation to be thread-safe
This commit is contained in:
@@ -1331,39 +1331,50 @@ namespace FlaxEngine.Interop
|
||||
// Skip using in-built delegate for value types (eg. Transform) to properly handle instance value passing to method
|
||||
if (invokeDelegate == null && !method.DeclaringType.IsValueType)
|
||||
{
|
||||
List<Type> methodTypes = new List<Type>();
|
||||
if (!method.IsStatic)
|
||||
methodTypes.Add(method.DeclaringType);
|
||||
if (returnType != typeof(void))
|
||||
methodTypes.Add(returnType);
|
||||
methodTypes.AddRange(parameterTypes);
|
||||
|
||||
List<Type> genericParamTypes = new List<Type>();
|
||||
foreach (var type in methodTypes)
|
||||
// Thread-safe creation
|
||||
lock (typeCache)
|
||||
{
|
||||
if (type.IsByRef)
|
||||
genericParamTypes.Add(type.GetElementType());
|
||||
else if (type.IsPointer)
|
||||
genericParamTypes.Add(typeof(IntPtr));
|
||||
else
|
||||
genericParamTypes.Add(type);
|
||||
}
|
||||
|
||||
string invokerTypeName = $"{typeof(Invoker).FullName}+Invoker{(method.IsStatic ? "Static" : "")}{(returnType != typeof(void) ? "Ret" : "NoRet")}{parameterTypes.Length}{(genericParamTypes.Count > 0 ? "`" + genericParamTypes.Count : "")}";
|
||||
Type invokerType = Type.GetType(invokerTypeName);
|
||||
if (invokerType != null)
|
||||
{
|
||||
if (genericParamTypes.Count != 0)
|
||||
invokerType = invokerType.MakeGenericType(genericParamTypes.ToArray());
|
||||
invokeDelegate = invokerType.GetMethod(nameof(Invoker.InvokerStaticNoRet0.MarshalAndInvoke), BindingFlags.Static | BindingFlags.NonPublic).CreateDelegate<Invoker.MarshalAndInvokeDelegate>();
|
||||
delegInvoke = invokerType.GetMethod(nameof(Invoker.InvokerStaticNoRet0.CreateDelegate), BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { method });
|
||||
if (invokeDelegate == null)
|
||||
{
|
||||
TryCreateDelegate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outDeleg = invokeDelegate;
|
||||
outDelegInvoke = delegInvoke;
|
||||
return outDeleg != null;
|
||||
}
|
||||
|
||||
private void TryCreateDelegate()
|
||||
{
|
||||
var methodTypes = new List<Type>();
|
||||
if (!method.IsStatic)
|
||||
methodTypes.Add(method.DeclaringType);
|
||||
if (returnType != typeof(void))
|
||||
methodTypes.Add(returnType);
|
||||
methodTypes.AddRange(parameterTypes);
|
||||
|
||||
var genericParamTypes = new List<Type>();
|
||||
foreach (var type in methodTypes)
|
||||
{
|
||||
if (type.IsByRef)
|
||||
genericParamTypes.Add(type.GetElementType());
|
||||
else if (type.IsPointer)
|
||||
genericParamTypes.Add(typeof(IntPtr));
|
||||
else
|
||||
genericParamTypes.Add(type);
|
||||
}
|
||||
|
||||
string invokerTypeName = $"{typeof(Invoker).FullName}+Invoker{(method.IsStatic ? "Static" : "")}{(returnType != typeof(void) ? "Ret" : "NoRet")}{parameterTypes.Length}{(genericParamTypes.Count > 0 ? "`" + genericParamTypes.Count : "")}";
|
||||
Type invokerType = Type.GetType(invokerTypeName);
|
||||
if (invokerType != null)
|
||||
{
|
||||
if (genericParamTypes.Count != 0)
|
||||
invokerType = invokerType.MakeGenericType(genericParamTypes.ToArray());
|
||||
delegInvoke = invokerType.GetMethod(nameof(Invoker.InvokerStaticNoRet0.CreateDelegate), BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { method });
|
||||
invokeDelegate = invokerType.GetMethod(nameof(Invoker.InvokerStaticNoRet0.MarshalAndInvoke), BindingFlags.Static | BindingFlags.NonPublic).CreateDelegate<Invoker.MarshalAndInvokeDelegate>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user