_net8 wip
This commit is contained in:
@@ -766,42 +766,233 @@ namespace FlaxEngine.Interop
|
||||
#endif
|
||||
{
|
||||
// Slow path, method parameters needs to be stored in heap
|
||||
// TODO: Benchmark again against the fast path
|
||||
object returnObject;
|
||||
object instance = instanceHandle.IsAllocated ? instanceHandle.Target : null;
|
||||
int numParams = methodHolder.parameterTypes.Length;
|
||||
object[] methodParameters = new object[numParams];
|
||||
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||
methodParameters[i] = MarshalToManaged(nativePtr, methodHolder.parameterTypes[i]);
|
||||
}
|
||||
//if (numParams > maxnumpars)
|
||||
// maxnumpars = numParams;
|
||||
|
||||
try
|
||||
#if false
|
||||
if (numParams > 4)
|
||||
#else
|
||||
if (true)
|
||||
#endif
|
||||
{
|
||||
returnObject = methodHolder.method.Invoke(instanceHandle.IsAllocated ? instanceHandle.Target : null, methodParameters);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// The internal exception thrown in MethodInfo.Invoke is caught here
|
||||
Exception realException = exception;
|
||||
if (exception.InnerException != null && exception.TargetSite.ReflectedType.Name == "MethodInvoker")
|
||||
realException = exception.InnerException;
|
||||
|
||||
if (exceptionPtr != IntPtr.Zero)
|
||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||
else
|
||||
throw realException;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// Marshal reference parameters back to original unmanaged references
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
Type parameterType = methodHolder.parameterTypes[i];
|
||||
if (parameterType.IsByRef)
|
||||
object[] methodParameters = new object[numParams];
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||
MarshalToNative(methodParameters[i], nativePtr, parameterType.GetElementType());
|
||||
methodParameters[i] = MarshalToManaged(nativePtr, methodHolder.parameterTypes[i]);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
returnObject = methodHolder.method.Invoke(instance, methodParameters);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// The internal exception thrown in MethodInfo.Invoke is caught here
|
||||
Exception realException = exception;
|
||||
if (exception.InnerException != null && exception.TargetSite.ReflectedType.Name == "MethodInvoker")
|
||||
realException = exception.InnerException;
|
||||
|
||||
if (exceptionPtr != IntPtr.Zero)
|
||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||
else
|
||||
throw realException;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// Marshal reference parameters back to original unmanaged references
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
Type parameterType = methodHolder.parameterTypes[i];
|
||||
if (parameterType.IsByRef)
|
||||
{
|
||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||
MarshalToNative(methodParameters[i], nativePtr, parameterType.GetElementType());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numParams == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
returnObject = methodHolder.methodInvoker.Invoke(instance);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// The internal exception thrown in MethodInfo.Invoke is caught here
|
||||
Exception realException = exception;
|
||||
if (exception.InnerException != null && exception.TargetSite.ReflectedType.Name == "MethodInvoker")
|
||||
realException = exception.InnerException;
|
||||
|
||||
if (exceptionPtr != IntPtr.Zero)
|
||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||
else
|
||||
throw realException;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
else if (numParams == 1)
|
||||
{
|
||||
IntPtr nativePtr1 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 0)).ToPointer());
|
||||
Span<object?> paramSpan = [
|
||||
MarshalToManaged(nativePtr1, methodHolder.parameterTypes[0])
|
||||
];
|
||||
|
||||
try
|
||||
{
|
||||
returnObject = methodHolder.methodInvoker.Invoke(instance, paramSpan);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// The internal exception thrown in MethodInfo.Invoke is caught here
|
||||
Exception realException = exception;
|
||||
if (exception.InnerException != null && exception.TargetSite.ReflectedType.Name == "MethodInvoker")
|
||||
realException = exception.InnerException;
|
||||
|
||||
if (exceptionPtr != IntPtr.Zero)
|
||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||
else
|
||||
throw realException;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// Marshal reference parameters back to original unmanaged references
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
Type parameterType = methodHolder.parameterTypes[i];
|
||||
if (parameterType.IsByRef)
|
||||
{
|
||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||
MarshalToNative(paramSpan[i], nativePtr, parameterType.GetElementType());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (numParams == 2)
|
||||
{
|
||||
IntPtr nativePtr1 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 0)).ToPointer());
|
||||
IntPtr nativePtr2 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 1)).ToPointer());
|
||||
Span<object?> paramSpan = [
|
||||
MarshalToManaged(nativePtr1, methodHolder.parameterTypes[0]),
|
||||
MarshalToManaged(nativePtr2, methodHolder.parameterTypes[1])
|
||||
];
|
||||
|
||||
try
|
||||
{
|
||||
returnObject = methodHolder.methodInvoker.Invoke(instance, paramSpan);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// The internal exception thrown in MethodInfo.Invoke is caught here
|
||||
Exception realException = exception;
|
||||
if (exception.InnerException != null && exception.TargetSite.ReflectedType.Name == "MethodInvoker")
|
||||
realException = exception.InnerException;
|
||||
|
||||
if (exceptionPtr != IntPtr.Zero)
|
||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||
else
|
||||
throw realException;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// Marshal reference parameters back to original unmanaged references
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
Type parameterType = methodHolder.parameterTypes[i];
|
||||
if (parameterType.IsByRef)
|
||||
{
|
||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||
MarshalToNative(paramSpan[i], nativePtr, parameterType.GetElementType());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (numParams == 3)
|
||||
{
|
||||
IntPtr nativePtr1 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 0)).ToPointer());
|
||||
IntPtr nativePtr2 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 1)).ToPointer());
|
||||
IntPtr nativePtr3 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 2)).ToPointer());
|
||||
Span<object?> paramSpan = [
|
||||
MarshalToManaged(nativePtr1, methodHolder.parameterTypes[0]),
|
||||
MarshalToManaged(nativePtr2, methodHolder.parameterTypes[1]),
|
||||
MarshalToManaged(nativePtr3, methodHolder.parameterTypes[2])
|
||||
];
|
||||
|
||||
try
|
||||
{
|
||||
returnObject = methodHolder.methodInvoker.Invoke(instance, paramSpan);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// The internal exception thrown in MethodInfo.Invoke is caught here
|
||||
Exception realException = exception;
|
||||
if (exception.InnerException != null && exception.TargetSite.ReflectedType.Name == "MethodInvoker")
|
||||
realException = exception.InnerException;
|
||||
|
||||
if (exceptionPtr != IntPtr.Zero)
|
||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||
else
|
||||
throw realException;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// Marshal reference parameters back to original unmanaged references
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
Type parameterType = methodHolder.parameterTypes[i];
|
||||
if (parameterType.IsByRef)
|
||||
{
|
||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||
MarshalToNative(paramSpan[i], nativePtr, parameterType.GetElementType());
|
||||
}
|
||||
}
|
||||
}
|
||||
else //if (numParams == 4)
|
||||
{
|
||||
IntPtr nativePtr1 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 0)).ToPointer());
|
||||
IntPtr nativePtr2 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 1)).ToPointer());
|
||||
IntPtr nativePtr3 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 2)).ToPointer());
|
||||
IntPtr nativePtr4 = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * 3)).ToPointer());
|
||||
Span<object?> paramSpan = [
|
||||
MarshalToManaged(nativePtr1, methodHolder.parameterTypes[0]),
|
||||
MarshalToManaged(nativePtr2, methodHolder.parameterTypes[1]),
|
||||
MarshalToManaged(nativePtr3, methodHolder.parameterTypes[2]),
|
||||
MarshalToManaged(nativePtr4, methodHolder.parameterTypes[3])
|
||||
];
|
||||
|
||||
try
|
||||
{
|
||||
returnObject = methodHolder.methodInvoker.Invoke(instance, paramSpan);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// The internal exception thrown in MethodInfo.Invoke is caught here
|
||||
Exception realException = exception;
|
||||
if (exception.InnerException != null && exception.TargetSite.ReflectedType.Name == "MethodInvoker")
|
||||
realException = exception.InnerException;
|
||||
|
||||
if (exceptionPtr != IntPtr.Zero)
|
||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||
else
|
||||
throw realException;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// Marshal reference parameters back to original unmanaged references
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
Type parameterType = methodHolder.parameterTypes[i];
|
||||
if (parameterType.IsByRef)
|
||||
{
|
||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||
MarshalToNative(paramSpan[i], nativePtr, parameterType.GetElementType());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,16 +116,39 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
#if !USE_AOT
|
||||
#if !NET8_0_OR_GREATER
|
||||
// Cache offsets to frequently accessed fields of FlaxEngine.Object
|
||||
private static int unmanagedPtrFieldOffset = IntPtr.Size + (Unsafe.Read<int>((typeof(FlaxEngine.Object).GetField("__unmanagedPtr", BindingFlags.Instance | BindingFlags.NonPublic).FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF);
|
||||
private static int internalIdFieldOffset = IntPtr.Size + (Unsafe.Read<int>((typeof(FlaxEngine.Object).GetField("__internalId", BindingFlags.Instance | BindingFlags.NonPublic).FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF);
|
||||
#endif
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void ScriptingObjectSetInternalValues(ManagedHandle objectHandle, IntPtr unmanagedPtr, IntPtr idPtr)
|
||||
{
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
//Object obj2 = objectHandle.Target as Object;
|
||||
object obj = objectHandle.Target;
|
||||
if (obj is not Object)
|
||||
if (obj is not Object obj2)
|
||||
return;
|
||||
{
|
||||
ref IntPtr fieldRef = ref SetObjectUnmanagedPtr(obj2);
|
||||
fieldRef = unmanagedPtr;
|
||||
}
|
||||
if (idPtr != IntPtr.Zero)
|
||||
{
|
||||
ref Guid nativeId = ref Unsafe.AsRef<Guid>(idPtr.ToPointer());
|
||||
ref Guid fieldRef = ref SetObjectInternalId(obj2);
|
||||
fieldRef = nativeId;
|
||||
}
|
||||
|
||||
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "__unmanagedPtr")]
|
||||
extern static ref IntPtr SetObjectUnmanagedPtr(Object obj);
|
||||
|
||||
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "__internalId")]
|
||||
extern static ref Guid SetObjectInternalId(Object obj);
|
||||
#else
|
||||
object obj = objectHandle.Target;
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<IntPtr>(unmanagedPtrFieldOffset, ref obj);
|
||||
fieldRef = unmanagedPtr;
|
||||
@@ -136,6 +159,7 @@ namespace FlaxEngine.Interop
|
||||
ref Guid fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<Guid>(internalIdFieldOffset, ref obj);
|
||||
fieldRef = nativeId;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
@@ -155,7 +179,7 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
#endif
|
||||
|
||||
internal static void* NativeAlloc(int byteCount)
|
||||
internal static void* NativeAlloc(int byteCount)
|
||||
{
|
||||
return NativeMemory.AlignedAlloc((UIntPtr)byteCount, 16);
|
||||
}
|
||||
@@ -1272,6 +1296,9 @@ namespace FlaxEngine.Interop
|
||||
internal class MethodHolder
|
||||
{
|
||||
internal Type[] parameterTypes;
|
||||
#if NET8_0_OR_GREATER
|
||||
internal MethodInvoker methodInvoker;
|
||||
#endif
|
||||
internal MethodInfo method;
|
||||
internal Type returnType;
|
||||
#if !USE_AOT
|
||||
@@ -1284,6 +1311,10 @@ namespace FlaxEngine.Interop
|
||||
this.method = method;
|
||||
returnType = method.ReturnType;
|
||||
parameterTypes = method.GetParameterTypes();
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
methodInvoker = MethodInvoker.Create(method);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !USE_AOT
|
||||
@@ -1388,7 +1419,11 @@ namespace FlaxEngine.Interop
|
||||
{
|
||||
internal Type type;
|
||||
internal Type wrappedType;
|
||||
#if NET8_0_OR_GREATER
|
||||
internal MethodInvoker ctorInvoker;
|
||||
#else
|
||||
internal ConstructorInfo ctor;
|
||||
#endif
|
||||
internal IntPtr managedClassPointer; // MClass*
|
||||
|
||||
internal TypeHolder(Type type)
|
||||
@@ -1404,7 +1439,13 @@ namespace FlaxEngine.Interop
|
||||
wrappedType = abstractWrapper;
|
||||
}
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
ConstructorInfo ctor = wrappedType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
|
||||
if (ctor != null)
|
||||
ctorInvoker = MethodInvoker.Create(ctor);
|
||||
#else
|
||||
ctor = wrappedType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal object CreateObject()
|
||||
@@ -1416,9 +1457,29 @@ namespace FlaxEngine.Interop
|
||||
internal object CreateScriptingObject(IntPtr unmanagedPtr, IntPtr idPtr)
|
||||
{
|
||||
object obj = RuntimeHelpers.GetUninitializedObject(wrappedType);
|
||||
#if NET8_0_OR_GREATER
|
||||
if (obj is Object obj2)
|
||||
{
|
||||
{
|
||||
ref IntPtr fieldRef = ref SetObjectUnmanagedPtr(obj2);
|
||||
fieldRef = unmanagedPtr;
|
||||
}
|
||||
if (idPtr != IntPtr.Zero)
|
||||
{
|
||||
ref Guid nativeId = ref Unsafe.AsRef<Guid>(idPtr.ToPointer());
|
||||
ref Guid fieldRef = ref SetObjectInternalId(obj2);
|
||||
fieldRef = nativeId;
|
||||
}
|
||||
|
||||
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "__unmanagedPtr")]
|
||||
extern static ref IntPtr SetObjectUnmanagedPtr(Object obj);
|
||||
|
||||
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "__internalId")]
|
||||
extern static ref Guid SetObjectInternalId(Object obj);
|
||||
}
|
||||
#else
|
||||
if (obj is Object)
|
||||
{
|
||||
// TODO: use UnsafeAccessorAttribute on .NET 8 and use this path on all platforms (including non-Desktop, see MCore::ScriptingObject::CreateScriptingObject)
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<IntPtr>(unmanagedPtrFieldOffset, ref obj);
|
||||
fieldRef = unmanagedPtr;
|
||||
@@ -1430,8 +1491,14 @@ namespace FlaxEngine.Interop
|
||||
fieldRef = nativeId;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if NET8_0_OR_GREATER
|
||||
if (ctorInvoker != null)
|
||||
ctorInvoker.Invoke(obj);
|
||||
#else
|
||||
if (ctor != null)
|
||||
ctor.Invoke(obj, null);
|
||||
#endif
|
||||
else
|
||||
throw new NativeInteropException($"Missing empty constructor in type '{wrappedType}'.");
|
||||
return obj;
|
||||
|
||||
Reference in New Issue
Block a user