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
|
// Skip using in-built delegate for value types (eg. Transform) to properly handle instance value passing to method
|
||||||
if (invokeDelegate == null && !method.DeclaringType.IsValueType)
|
if (invokeDelegate == null && !method.DeclaringType.IsValueType)
|
||||||
{
|
{
|
||||||
List<Type> methodTypes = new List<Type>();
|
// Thread-safe creation
|
||||||
if (!method.IsStatic)
|
lock (typeCache)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (type.IsByRef)
|
if (invokeDelegate == null)
|
||||||
genericParamTypes.Add(type.GetElementType());
|
{
|
||||||
else if (type.IsPointer)
|
TryCreateDelegate();
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outDeleg = invokeDelegate;
|
outDeleg = invokeDelegate;
|
||||||
outDelegInvoke = delegInvoke;
|
outDelegInvoke = delegInvoke;
|
||||||
return outDeleg != null;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user