initial nativestring and nativearray marshalling
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled

This commit is contained in:
2026-01-03 16:00:55 +02:00
parent c7326ea483
commit 7088ce8742
25 changed files with 1958 additions and 341 deletions

View File

@@ -47,6 +47,7 @@ static_assert(sizeof(InternalImpulse) == sizeof(AnimGraphImpulse), "Please updat
DEFINE_INTERNAL_CALL(bool) AnimGraphInternal_HasConnection(InternalContext* context, int32 boxId)
{
PLATFORM_DEBUG_BREAK;
const auto box = context->Node->TryGetBox(boxId);
if (box == nullptr)
DebugLog::ThrowArgumentOutOfRange("boxId");
@@ -55,6 +56,7 @@ DEFINE_INTERNAL_CALL(bool) AnimGraphInternal_HasConnection(InternalContext* cont
DEFINE_INTERNAL_CALL(MObject*) AnimGraphInternal_GetInputValue(InternalContext* context, int32 boxId)
{
PLATFORM_DEBUG_BREAK;
const auto box = context->Node->TryGetBox(boxId);
if (box == nullptr)
DebugLog::ThrowArgumentOutOfRange("boxId");
@@ -72,6 +74,7 @@ DEFINE_INTERNAL_CALL(MObject*) AnimGraphInternal_GetInputValue(InternalContext*
DEFINE_INTERNAL_CALL(AnimGraphImpulse*) AnimGraphInternal_GetOutputImpulseData(InternalContext* context)
{
PLATFORM_DEBUG_BREAK;
const auto nodes = context->Node->GetNodes(context->GraphExecutor);
context->GraphExecutor->InitNodes(nodes);
return nodes;

View File

@@ -27,7 +27,7 @@ namespace FlaxEditor.Content.Settings
/// <returns>The layers.</returns>
public static string[] GetCurrentLayers()
{
return GetCurrentLayers(out int _);
return Internal_GetCurrentLayers();
}
/// <summary>
@@ -56,7 +56,7 @@ namespace FlaxEditor.Content.Settings
}
[LibraryImport("FlaxEngine", EntryPoint = "LayersAndTagsSettingsInternal_GetCurrentLayers", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
[return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "layerCount")]
internal static partial string[] GetCurrentLayers(out int layerCount);
[return: MarshalUsing(typeof(FlaxEngine.Interop.NativeSpanMarshaller<string, FlaxEngine.Interop.NativeString>), ConstantElementCount = FlaxEngine.Interop.MarshallerFlags.SkipDisposeElements)]
internal static partial string[] Internal_GetCurrentLayers();
}
}

View File

@@ -183,11 +183,11 @@ namespace FlaxEngine.Interop
if (returnType == typeof(string))
return ManagedString.ToNative/*Weak*/(Unsafe.As<string>(returnObject));
if (returnType == typeof(IntPtr))
return (IntPtr)(object)returnObject;
return (IntPtr)returnObject;
if (returnType == typeof(ManagedHandle))
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
return ManagedHandle.ToIntPtr((ManagedHandle)returnObject);
if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
return returnObject != null ? ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As<Type>(returnObject))) : IntPtr.Zero;
return ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As<Type>(returnObject)));
if (returnType.IsArray)
{
var elementType = returnType.GetElementType();

View File

@@ -1,5 +1,5 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#pragma warning disable CS0162
#define USE_CONCURRENT_DICT
#define USE_GCHANDLE
//#define TRACK_HANDLES
@@ -311,20 +311,24 @@ namespace FlaxEngine.Interop
{
internal static ManagedHandle EmptyStringHandle = ManagedHandle.Alloc(string.Empty);
[System.Diagnostics.DebuggerStepThrough]
//[System.Diagnostics.DebuggerStepThrough]
public static unsafe IntPtr ToNative(string str)
{
if (str == null)
return IntPtr.Zero;
else if (str == string.Empty)
return ManagedHandle.ToIntPtr(EmptyStringHandle);
Assert.IsTrue(str.Length > 0);
return ManagedHandle.ToIntPtr(str);
//else if (str == string.Empty)
// return ManagedHandle.ToIntPtr(EmptyStringHandle);
//return ManagedHandle.ToIntPtr(str);
NativeString* nativeString = (NativeString*)NativeMemory.AlignedAlloc((UIntPtr)Unsafe.SizeOf<NativeString>(), 16);
*nativeString = new NativeString(str);
return (IntPtr)nativeString;
}
[System.Diagnostics.DebuggerStepThrough]
//[System.Diagnostics.DebuggerStepThrough]
public static unsafe IntPtr ToNativeWeak(string str)
{
throw new Exception("not used");
if (str == null)
return IntPtr.Zero;
else if (str == string.Empty)
@@ -333,28 +337,39 @@ namespace FlaxEngine.Interop
return ManagedHandle.ToIntPtr(str, GCHandleType.Weak);
}
[System.Diagnostics.DebuggerStepThrough]
public static string ToManaged(IntPtr ptr)
//[System.Diagnostics.DebuggerStepThrough]
public static unsafe string ToManaged(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return null;
return Unsafe.As<string>(ManagedHandle.FromIntPtr(ptr).Target);
//return Unsafe.As<string>(ManagedHandle.FromIntPtr(ptr).Target);
NativeString* str = (NativeString*)ptr.ToPointer();
return str->ToString();
}
[System.Diagnostics.DebuggerStepThrough]
public static void Free(IntPtr ptr)
//[System.Diagnostics.DebuggerStepThrough]
public static unsafe void Free(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return;
ManagedHandle handle = ManagedHandle.FromIntPtr(ptr);
if (handle == EmptyStringHandle)
return;
handle.Free();
//ManagedHandle handle = ManagedHandle.FromIntPtr(ptr);
//if (handle == EmptyStringHandle)
// return;
//handle.Free();
Free((NativeString*)ptr.ToPointer());
}
//[System.Diagnostics.DebuggerStepThrough]
public static unsafe void Free(NativeString* str)
{
if (str->Data != null)
NativeMemory.AlignedFree(str->Data);
}
[System.Diagnostics.DebuggerStepThrough]
public static void Free(ManagedHandle handle)
{
throw new Exception("not used");
if (handle == EmptyStringHandle)
return;
handle.Free();
@@ -537,7 +552,8 @@ namespace FlaxEngine.Interop
internal static class ManagedHandlePool
{
[ThreadStatic]
private static List<(bool InUse, ManagedHandle Handle)> _pool;
private static List<(bool InUse, ManagedHandle Handle)> __poolField;
private static List<(bool InUse, ManagedHandle Handle)> _pool => __poolField ??= [];
internal static void TryCollectWeakHandles(bool force = false)
{

File diff suppressed because it is too large Load Diff

View File

@@ -527,34 +527,49 @@ namespace FlaxEngine.Interop
}
[UnmanagedCallersOnly]
internal static ManagedHandle NewArray(ManagedHandle typeHandle, long size)
internal static IntPtr NewArray(ManagedHandle typeHandle, long size)
{
Type elementType = Unsafe.As<TypeHolder>(typeHandle.Target);
Type marshalledType = ArrayFactory.GetMarshalledType(elementType);
Type arrayType = ArrayFactory.GetArrayType(elementType);
if (marshalledType.IsValueType)
{
ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, arrayType, marshalledType);
return ManagedHandle.Alloc(managedArray);
IntPtr arrayPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)Unsafe.SizeOf<NativeArrayTypeless>(), 16);
IntPtr dataPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)(RuntimeHelpers.SizeOf(marshalledType.TypeHandle) * size), 16);
Unsafe.Write<IntPtr>(arrayPtr.ToPointer(), dataPtr);
Unsafe.Write<long>(IntPtr.Add(arrayPtr, Unsafe.SizeOf<IntPtr>()).ToPointer(), size);
return arrayPtr;
//ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, arrayType, marshalledType);
//return ManagedHandle.Alloc(managedArray);
}
else
{
Array arr = ArrayFactory.CreateArray(elementType, size);
/*Array arr = ArrayFactory.CreateArray(elementType, size);
ManagedArray managedArray = ManagedArray.WrapNewArray(arr, arrayType);
return ManagedHandle.Alloc(managedArray);
return ManagedHandle.Alloc(managedArray);*/
IntPtr arrayPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)Unsafe.SizeOf<NativeArrayTypeless>(), 16);
IntPtr dataPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)(Unsafe.SizeOf<IntPtr>() * size), 16);
Unsafe.Write<IntPtr>(arrayPtr.ToPointer(), dataPtr);
Unsafe.Write<long>(IntPtr.Add(arrayPtr, Unsafe.SizeOf<IntPtr>()).ToPointer(), size);
return arrayPtr;
}
}
[UnmanagedCallersOnly]
internal static void FreeArray(ManagedHandle handle)
internal static void FreeArray(void* ptr)
{
if (!handle.IsAllocated)
if (ptr == null)
return;
ManagedArray managedArray = Unsafe.As<ManagedArray>(handle.Target);
NativeArrayTypeless* array = (NativeArrayTypeless*)ptr;
array->Free();
/*ManagedArray managedArray = Unsafe.As<ManagedArray>(handle.Target);
if (managedArray.ElementType.IsValueType)
managedArray.Free();
else
managedArray.FreePooled();
managedArray.FreePooled();*/
}
[UnmanagedCallersOnly]
@@ -575,14 +590,15 @@ namespace FlaxEngine.Interop
}
[UnmanagedCallersOnly]
internal static IntPtr GetArrayPointer(ManagedHandle arrayHandle)
internal static IntPtr GetArrayPointer(void* ptr)
{
if (!arrayHandle.IsAllocated)
if (ptr == null)
return IntPtr.Zero;
ManagedArray managedArray = Unsafe.As<ManagedArray>(arrayHandle.Target);
if (managedArray.Length == 0)
NativeArrayTypeless* array = (NativeArrayTypeless*)ptr;
if (array->Length == 0)
return IntPtr.Zero;
return managedArray.Pointer;
return (IntPtr)array->Data;
}
[UnmanagedCallersOnly]
@@ -599,12 +615,16 @@ namespace FlaxEngine.Interop
}
[UnmanagedCallersOnly]
internal static int GetArrayLength(ManagedHandle arrayHandle)
internal static int GetArrayLength(void* ptr)
{
if (!arrayHandle.IsAllocated)
return 0;
ManagedArray managedArray = Unsafe.As<ManagedArray>(arrayHandle.Target);
return managedArray.Length;
//if (ptr == null)
// return 0;
NativeArrayTypeless* array = (NativeArrayTypeless*)ptr;
return array->Length;
/* if (!arrayHandle.IsAllocated)
return 0;
ManagedArray managedArray = Unsafe.As<ManagedArray>(arrayHandle.Target);
return managedArray.Length;*/
}
[UnmanagedCallersOnly]
@@ -626,9 +646,9 @@ namespace FlaxEngine.Interop
}
[UnmanagedCallersOnly]
internal static void FreeString(ManagedHandle handle)
internal static void FreeString(NativeString* str)
{
ManagedString.Free(handle);
ManagedString.Free(str);
}
[UnmanagedCallersOnly]

View File

@@ -198,8 +198,8 @@ namespace FlaxEngine.Interop
public static T[] GCHandleArrayToManagedArray<T>(NativeArray<IntPtr> ptrArray, T[] buffer = null) where T : class
{
ReadOnlySpan<IntPtr> span = ptrArray.AsReadOnlySpan();
if (buffer != null)
buffer = buffer;
//if (buffer != null)
// buffer = buffer;
if (buffer == null || buffer.Length < ptrArray.Length)
buffer = new T[ptrArray.Length];
for (int i = 0; i < ptrArray.Length; i++)
@@ -426,7 +426,7 @@ namespace FlaxEngine.Interop
if (!toManagedMarshallers.TryGetValue(type, out var deleg))
deleg = toManagedMarshallers.GetOrAdd(type, Factory);
return deleg(nativePtr, type.IsByRef);
return deleg(nativePtr, type.IsByRef && false);
}
internal static void MarshalToNative(object managedObject, IntPtr nativePtr, Type type)
@@ -552,6 +552,7 @@ namespace FlaxEngine.Interop
internal static int[] marshallableFieldOffsets;
internal static MarshalFieldTypedDelegate[] toManagedFieldMarshallers;
internal static MarshalFieldTypedDelegate[] toNativeFieldMarshallers;
private static int marshalledSize;
private static MarshalToNativeTypedDelegate toNativeTypedMarshaller;
private static MarshalToManagedTypedDelegate toManagedTypedMarshaller;
@@ -582,7 +583,36 @@ namespace FlaxEngine.Interop
MethodInfo toManagedFieldMethod;
MethodInfo toNativeFieldMethod;
if (fieldType.IsPointer)
if (fieldType == typeof(string))
fieldType = fieldType;
if (fieldType == typeof(SoftTypeReference))
{
if (type.IsValueType)
{
toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToManagedFieldSoftTypeReferenceValueType), bindingFlags);
toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToNativeFieldSoftTypeReferenceValueType), bindingFlags);
}
else
{
toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToManagedFieldSoftTypeReferenceReferenceType), bindingFlags);
toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToNativeFieldSoftTypeReferenceReferenceType), bindingFlags);
}
}
else if (fieldType == typeof(string))
{
if (type.IsValueType)
{
toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToManagedFieldStringValueType), bindingFlags);
toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToNativeFieldStringValueType), bindingFlags);
}
else
{
toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToManagedFieldStringReferenceType), bindingFlags);
toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToNativeFieldStringReferenceType), bindingFlags);
}
}
else if (fieldType.IsPointer)
{
if (type.IsValueType)
{
@@ -666,6 +696,15 @@ namespace FlaxEngine.Interop
}
}
/*if (marshallableFieldOffsets != null)
{
for (int i = 1; i < marshallableFieldOffsets.Length; i++)
{
if (marshallableFieldOffsets[i - 1] > marshallableFieldOffsets[i])
throw new NativeInteropException("marshal field offsets");
}
}*/
// Setup marshallers for managed and native directions
MethodInfo toManagedMethod;
if (type.IsValueType)
@@ -682,18 +721,31 @@ namespace FlaxEngine.Interop
//toManagedDelegate = toManagedMethod.CreateDelegate();//.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(type, toManagedMethod.GetParameters()[0].ParameterType));
string methodName = nameof(MarshalInternalHelper<ValueTypePlaceholder, ValueTypePlaceholder>.ToManagedMarshaller);
toManagedMethod = typeof(MarshalInternalHelper<,>).MakeGenericType(types).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
marshalledSize = RuntimeHelpers.SizeOf(internalType.TypeHandle);
}
else
{
string methodName;
if (type == typeof(IntPtr))
{
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedPointer);
marshalledSize = Unsafe.SizeOf<IntPtr>();
}
else if (type == typeof(ManagedHandle))
{
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedHandle);
marshalledSize = Unsafe.SizeOf<IntPtr>();
}
else if (marshallableFields != null)
{
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedWithMarshallableFields);
marshalledSize = RuntimeHelpers.SizeOf(type.TypeHandle);
}
else
{
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManaged);
marshalledSize = RuntimeHelpers.SizeOf(type.TypeHandle);
}
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
}
}
@@ -707,10 +759,14 @@ namespace FlaxEngine.Interop
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedArray);
else
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedArrayMarshalled);
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(type.GetElementType()).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(elementType).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
marshalledSize = RuntimeHelpers.SizeOf(elementType.TypeHandle);
}
else
toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(type.GetElementType()).GetMethod(nameof(MarshalHelperReferenceType<ReferenceTypePlaceholder>.ToManagedArray), BindingFlags.Static | BindingFlags.NonPublic);
{
toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(elementType).GetMethod(nameof(MarshalHelperReferenceType<ReferenceTypePlaceholder>.ToManagedArray), BindingFlags.Static | BindingFlags.NonPublic);
marshalledSize = Unsafe.SizeOf<IntPtr>();
}
}
else
{
@@ -726,7 +782,10 @@ namespace FlaxEngine.Interop
else
throw new NativeInteropException($"Unsupported type '{type.FullName}'");
toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
marshalledSize = Unsafe.SizeOf<IntPtr>();
}
if (marshalledSize <= 0)
throw new NativeInteropException($"Missing marshalled size for type '{type.FullName}'");
toManagedTypedMarshaller = toManagedMethod.CreateDelegate<MarshalToManagedTypedDelegate>();
MethodInfo toNativeMethod;
@@ -802,6 +861,18 @@ namespace FlaxEngine.Interop
return arr;
}
internal static Array ToManagedArray2(NativeArrayTypeless nativeArray)
{
T[] arr = new T[nativeArray.Length];
IntPtr nativePtr = (IntPtr)nativeArray.Data;
for (int i = 0; i < arr.Length; i++)
{
toManagedTypedMarshaller(ref arr[i], nativePtr, false);
nativePtr += marshalledSize;
}
return arr;
}
internal static void ToNative(ref T managedValue, IntPtr nativePtr)
{
toNativeTypedMarshaller(ref managedValue, nativePtr);
@@ -871,6 +942,106 @@ namespace FlaxEngine.Interop
fieldSize = IntPtr.Size;
}
private static void ToManagedFieldStringValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
{
fieldSize = Unsafe.SizeOf<NativeString>();
NativeString nativeValue = Unsafe.Read<NativeString>(nativeFieldPtr.ToPointer());
string value = nativeValue.ToString();
#if USE_AOT || DOTNET_HOST_MONO
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
#else
ref string fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, string>(fieldOffset, ref fieldOwner);
fieldValueRef = value;
#endif
}
private static void ToManagedFieldStringReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
{
fieldSize = Unsafe.SizeOf<NativeString>();
NativeString nativeValue = Unsafe.Read<NativeString>(nativeFieldPtr.ToPointer());
string value = nativeValue.ToString();
#if USE_AOT || DOTNET_HOST_MONO
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
#else
ref string fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, string>(fieldOffset, ref fieldOwner);
fieldValueRef = value;
#endif
}
private static void ToNativeFieldStringValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
{
fieldSize = Unsafe.SizeOf<NativeString>();
#if USE_AOT || DOTNET_HOST_MONO
string fieldValue = field.GetValue(fieldOwner);
#else
string fieldValue = FieldHelper.GetValueTypeFieldReference<T, string>(fieldOffset, ref fieldOwner);
#endif
NativeString value = new NativeString(fieldValue);
Unsafe.Write<NativeString>(nativeFieldPtr.ToPointer(), value);
}
private static void ToNativeFieldStringReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
{
fieldSize = Unsafe.SizeOf<NativeString>();
#if USE_AOT || DOTNET_HOST_MONO
string fieldValue = field.GetValue(fieldOwner);
#else
string fieldValue = FieldHelper.GetReferenceTypeFieldReference<T, string>(fieldOffset, ref fieldOwner);
#endif
NativeString value = new NativeString(fieldValue);
Unsafe.Write<NativeString>(nativeFieldPtr.ToPointer(), value);
}
private static void ToManagedFieldSoftTypeReferenceValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
{
fieldSize = Unsafe.SizeOf<NativeString>();
NativeString nativeValue = Unsafe.Read<NativeString>(nativeFieldPtr.ToPointer());
SoftTypeReference value = new SoftTypeReference(nativeValue.ToString());
#if USE_AOT || DOTNET_HOST_MONO
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
#else
ref SoftTypeReference fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, SoftTypeReference>(fieldOffset, ref fieldOwner);
fieldValueRef = value;
#endif
}
private static void ToManagedFieldSoftTypeReferenceReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
{
fieldSize = Unsafe.SizeOf<NativeString>();
NativeString nativeValue = Unsafe.Read<NativeString>(nativeFieldPtr.ToPointer());
SoftTypeReference value = new SoftTypeReference(nativeValue.ToString());
#if USE_AOT || DOTNET_HOST_MONO
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
#else
ref SoftTypeReference fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, SoftTypeReference>(fieldOffset, ref fieldOwner);
fieldValueRef = value;
#endif
}
private static void ToNativeFieldSoftTypeReferenceValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
{
fieldSize = Unsafe.SizeOf<NativeString>();
#if USE_AOT || DOTNET_HOST_MONO
SoftTypeReference fieldValue = field.GetValue(fieldOwner);
#else
SoftTypeReference fieldValue = FieldHelper.GetValueTypeFieldReference<T, SoftTypeReference>(fieldOffset, ref fieldOwner);
#endif
NativeString value = new NativeString(fieldValue);
Unsafe.Write<NativeString>(nativeFieldPtr.ToPointer(), value);
}
private static void ToNativeFieldSoftTypeReferenceReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
{
fieldSize = Unsafe.SizeOf<NativeString>();
#if USE_AOT || DOTNET_HOST_MONO
SoftTypeReference fieldValue = field.GetValue(fieldOwner);
#else
SoftTypeReference fieldValue = FieldHelper.GetReferenceTypeFieldReference<T, SoftTypeReference>(fieldOffset, ref fieldOwner);
#endif
NativeString value = new NativeString(fieldValue);
Unsafe.Write<NativeString>(nativeFieldPtr.ToPointer(), value);
}
private static IntPtr EnsureAlignment(IntPtr ptr, int alignment)
{
if (ptr % alignment != 0)
@@ -1203,9 +1374,8 @@ namespace FlaxEngine.Interop
if (nativePtr != IntPtr.Zero)
{
int length = Unsafe.Read<int>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer());
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
var span = new Span<T>(nativePtr.ToPointer(), length);
IntPtr data = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
var span = new Span<T>(data.ToPointer(), length);
managedValue = span.ToArray();
//ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
//managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>());
@@ -1221,8 +1391,12 @@ namespace FlaxEngine.Interop
if (nativePtr != IntPtr.Zero)
{
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray(managedArray));
int length = Unsafe.Read<int>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer());
IntPtr data = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
NativeArrayTypeless array = new(data, length);
managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray2(array)); // element size for internal structure needed here
//ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
//managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray(managedArray));
}
else
managedValue = null;
@@ -1234,6 +1408,13 @@ namespace FlaxEngine.Interop
var fields = MarshalHelper<T>.marshallableFields;
var offsets = MarshalHelper<T>.marshallableFieldOffsets;
var marshallers = MarshalHelper<T>.toNativeFieldMarshallers;
for (int i = 1; i < offsets.Length; i++)
{
if (offsets[i - 1] > offsets[i])
fieldPtr = fieldPtr;
}
for (int i = 0; i < fields.Length; i++)
{
marshallers[i](fields[i], offsets[i], ref managedValue, nativePtr, out int fieldSize);
@@ -1297,8 +1478,9 @@ namespace FlaxEngine.Interop
if (nativePtr != IntPtr.Zero)
{
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray(managedArray.ToSpan<IntPtr>()));
NativeArray<IntPtr>* array = (NativeArray<IntPtr>*)nativePtr;
var span = array->AsSpan();
managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray(span));
}
else
managedValue = null;
@@ -1329,34 +1511,59 @@ namespace FlaxEngine.Interop
internal static void ToNativeArray(ref T managedValue, IntPtr nativePtr)
{
IntPtr managedPtr;
IntPtr arrayDataPtr;
int arrayLength;
if (managedValue == null)
managedPtr = IntPtr.Zero;
{
arrayDataPtr = IntPtr.Zero;
arrayLength = 0;
}
else
{
Type type = typeof(T);
var elementType = type.GetElementType();
var arr = Unsafe.As<Array>(managedValue);
arrayLength = arr.Length;
var marshalledType = ArrayFactory.GetMarshalledType(elementType);
ManagedArray managedArray;
if (marshalledType == elementType)
managedArray = ManagedArray.WrapNewArray(arr, type);
{
var elementLength = RuntimeHelpers.SizeOf(marshalledType.TypeHandle);
var bytesLength = elementLength * arrayLength;
byte* ptr = (byte*)NativeMemory.AlignedAlloc((UIntPtr)bytesLength, 16);
arrayDataPtr = (IntPtr)ptr;
for (int i = 0; i < arr.Length; i++)
{
MarshalToNative(arr.GetValue(i), (IntPtr)ptr, elementType);
ptr += elementLength;
}
}
else if (elementType.IsValueType)
{
// Convert array of custom structures into internal native layout
managedArray = ManagedArray.AllocateNewArray(arr.Length, type, marshalledType);
IntPtr managedArrayPtr = managedArray.Pointer;
var elementLength = RuntimeHelpers.SizeOf(marshalledType.TypeHandle);
var bytesLength = elementLength * arrayLength;
byte* ptr = (byte*)NativeMemory.AlignedAlloc((UIntPtr)bytesLength, 16);
arrayDataPtr = (IntPtr)ptr;
for (int i = 0; i < arr.Length; i++)
{
MarshalToNative(arr.GetValue(i), managedArrayPtr, elementType);
managedArrayPtr += managedArray.ElementSize;
MarshalToNative(arr.GetValue(i), (IntPtr)ptr, elementType);
ptr += elementLength;
}
}
else
managedArray = ManagedArrayToGCHandleWrappedArray(arr);
managedPtr = ManagedHandle.ToIntPtr(managedArray/*, GCHandleType.Weak*/);
{
byte* ptr = (byte*)NativeMemory.AlignedAlloc((UIntPtr)(Unsafe.SizeOf<IntPtr>() * arrayLength), 16);
arrayDataPtr = (IntPtr)ptr;
for (int i = 0; i < arr.Length; i++)
{
var obj = arr.GetValue(i);
Unsafe.Write<IntPtr>(ptr, obj != null ? ManagedHandle.ToIntPtr(obj) : IntPtr.Zero);
ptr += Unsafe.SizeOf<IntPtr>();
}
}
}
Unsafe.Write<IntPtr>(nativePtr.ToPointer(), managedPtr);
Unsafe.Write<IntPtr>(nativePtr.ToPointer(), arrayDataPtr);
Unsafe.Write<long>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer(), arrayLength);
}
internal static void ToNative(ref T managedValue, IntPtr nativePtr)
@@ -1819,7 +2026,7 @@ namespace FlaxEngine.Interop
internal static void InitMethods()
{
return;
#if false
MakeNewCustomDelegateFunc =
typeof(Expression).Assembly.GetType("System.Linq.Expressions.Compiler.DelegateHelpers")
.GetMethod("MakeNewCustomDelegate", BindingFlags.NonPublic | BindingFlags.Static).CreateDelegate<Func<Type[], Type>>();
@@ -1851,6 +2058,7 @@ namespace FlaxEngine.Interop
var ret = MakeNewCustomDelegateFuncCollectible(new[] { typeof(void) });
Assert.IsTrue(ret.IsCollectible);
}
#endif
#endif
}
@@ -1871,7 +2079,7 @@ namespace FlaxEngine.Interop
return MakeNewCustomDelegateFunc(parameters);
}
#endif
}
}
internal static class ObjectArrayPool
{
@@ -1978,8 +2186,8 @@ namespace FlaxEngine.Interop
internal MethodInfo method;
internal MethodInvoker invoker;
internal Type[] parameterTypes;
internal Invoker.InvokeThunkDelegate methodDelegate;
internal object methodDelegateContext;
//internal Invoker.InvokeThunkDelegate methodDelegate;
//internal object methodDelegateContext;
internal static object[] objectPool = new object[128];
internal static int objectPoolIndex = 0;
@@ -2137,7 +2345,7 @@ namespace FlaxEngine.Interop
}
}
#endif
}
}
internal class NativeInteropException : Exception
{

View File

@@ -35,6 +35,11 @@ DEFINE_INTERNAL_CALL(MObject*) UtilsInternal_ExtractArrayFromList(MObject* obj)
}
#endif
//#if USE_NETCORE
//APgI_TYPEDEF() typedef MString* ManagedString;
API_TYPEDEF() typedef String* ManagedString;
//#endif
DEFINE_INTERNAL_CALL(void) PlatformInternal_MemoryCopy(void* dst, const void* src, uint64 size)
{
Platform::MemoryCopy(dst, src, size);
@@ -50,24 +55,33 @@ DEFINE_INTERNAL_CALL(int32) PlatformInternal_MemoryCompare(const void* buf1, con
return Platform::MemoryCompare(buf1, buf2, size);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_LogWrite(LogType level, MString* msgObj)
{
#if LOG_ENABLE
StringView msg;
MUtils::ToString(msgObj, msg);
Log::Logger::Write(level, msg);
#endif
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_Log(LogType level, MString* msgObj, ScriptingObject* obj, MString* stackTrace)
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_LogWrite(LogType level, ManagedString msgObj)
{
#if LOG_ENABLE
if (msgObj == nullptr)
return;
#if USE_NETCORE
StringView msg(*msgObj);
#else
StringView msg;
MUtils::ToString(msgObj, msg);
#endif
Log::Logger::Write(level, msg);
#endif
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_Log(LogType level, ManagedString msgObj, ScriptingObject* obj, ManagedString stackTrace)
{
#if LOG_ENABLE
if (msgObj == nullptr)
return;
#if USE_NETCORE
StringView msg(*msgObj);
#else
// Get info
StringView msg;
MUtils::ToString(msgObj, msg);
#endif
//const String objName = obj ? obj->ToString() : String::Empty;
// Send event
@@ -79,6 +93,7 @@ DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_Log(LogType level, MString* m
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_LogException(MObject* exception, ScriptingObject* obj)
{
PLATFORM_DEBUG_BREAK;
#if USE_CSHARP
if (exception == nullptr)
return;
@@ -117,11 +132,17 @@ namespace
#endif
}
DEFINE_INTERNAL_CALL(void) ProfilerInternal_BeginEvent(MString* nameObj)
DEFINE_INTERNAL_CALL(void) ProfilerInternal_BeginEvent(ManagedString nameObj)
{
#if COMPILE_WITH_PROFILER
if (nameObj == nullptr)
return;
#if USE_NETCORE
StringView name(*nameObj);
#else
StringView name;
MUtils::ToString(nameObj, name);
#endif
ProfilerCPU::BeginEvent(*name);
#if TRACY_ENABLE
#if PROFILE_CPU_USE_TRANSIENT_DATA
@@ -173,10 +194,16 @@ DEFINE_INTERNAL_CALL(void) ProfilerInternal_EndEvent()
#endif
}
DEFINE_INTERNAL_CALL(void) ProfilerInternal_BeginEventGPU(MString* nameObj)
DEFINE_INTERNAL_CALL(void) ProfilerInternal_BeginEventGPU(ManagedString nameObj)
{
#if COMPILE_WITH_PROFILER
#if USE_NETCORE
if (nameObj == nullptr)
return;
const StringView nameChars(*nameObj);
#else
const StringView nameChars = MCore::String::GetChars(nameObj);
#endif
const auto index = ProfilerGPU::BeginEvent(nameChars.Get());
ManagedEventsGPU.Push(index);
#endif
@@ -197,6 +224,7 @@ DEFINE_INTERNAL_CALL(bool) ScriptingInternal_HasGameModulesLoaded()
DEFINE_INTERNAL_CALL(bool) ScriptingInternal_IsTypeFromGameScripts(MTypeObject* type)
{
PLATFORM_DEBUG_BREAK;
return Scripting::IsTypeFromGameScripts(MUtils::GetClass(INTERNAL_TYPE_OBJECT_GET(type)));
}

View File

@@ -43,6 +43,7 @@ void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, MOb
// Write result data
stream.RawValue(MCore::String::GetChars(invokeResultStr));
MCore::String::Free(invokeResultStr);
}
void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream, MObject* object, MObject* other)
@@ -79,6 +80,7 @@ void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream,
// Write result data
stream.RawValue(MCore::String::GetChars(invokeResultStr));
MCore::String::Free(invokeResultStr);
}
void ManagedSerialization::Deserialize(ISerializable::DeserializeStream& stream, MObject* object)

View File

@@ -41,6 +41,118 @@ namespace
}
}
#if USE_NETCORE
StringView MUtils::ToString(MString* str)
{
if (str == nullptr)
return StringView::Empty;
return StringView(*(String*)str);
}
StringAnsi MUtils::ToStringAnsi(MString* str)
{
if (str == nullptr)
return StringAnsi::Empty;
return StringAnsi(*(String*)str);
}
void MUtils::ToString(MString* str, String& result)
{
if (str)
{
const StringView chars = StringView(*(String*)str);
result.Set(chars.Get(), chars.Length());
}
else
result.Clear();
}
void MUtils::ToString(MString* str, StringView& result)
{
if (str)
result = StringView(*(String*)str);
else
result = StringView();
}
void MUtils::ToString(MString* str, Variant& result)
{
result.SetString(str ? StringView(*(String*)str) : StringView::Empty);
}
void MUtils::ToString(MString* str, StringAnsi& result)
{
if (str)
{
const StringView chars = StringView(*(String*)str);
result.Set(chars.Get(), chars.Length());
}
else
result.Clear();
}
MString* MUtils::ToString(const char* str)
{
CRASH;
if (str == nullptr || *str == 0)
return (MString*)(New<String>());
return (MString*)(New<String>(str, StringUtils::Length(str)));
}
MString* MUtils::ToString(const StringAnsi& str)
{
CRASH;
const int32 len = str.Length();
if (len <= 0)
return (MString*)(New<String>());
return (MString*)(New<String>(str.Get(), len));
}
MString* MUtils::ToString(const String& str)
{
CRASH;
const int32 len = str.Length();
if (len <= 0)
return (MString*)(New<String>());
return (MString*)(New<String>(str.Get(), len));
}
MString* MUtils::ToString(const String& str, MDomain* domain)
{
CRASH;
const int32 len = str.Length();
if (len <= 0)
return (MString*)(New<String>());
return (MString*)(New<String>(str.Get(), len));
}
MString* MUtils::ToString(const StringAnsiView& str)
{
CRASH;
const int32 len = str.Length();
if (len <= 0)
return (MString*)(New<String>());
return (MString*)(New<String>(str.Get(), len));
}
MString* MUtils::ToString(const StringView& str)
{
CRASH;
const int32 len = str.Length();
if (len <= 0)
return (MString*)(New<String>());
return (MString*)(New<String>(str.Get(), len));
}
MString* MUtils::ToString(const StringView& str, MDomain* domain)
{
CRASH;
const int32 len = str.Length();
if (len <= 0)
return (MString*)(New<String>());
return (MString*)(New<String>(str.Get(), len));
}
#else
StringView MUtils::ToString(MString* str)
{
if (str == nullptr)
@@ -144,6 +256,7 @@ MString* MUtils::ToString(const StringView& str, MDomain* domain)
return MCore::String::GetEmpty(domain);
return MCore::String::New(str.Get(), len, domain);
}
#endif
ScriptingTypeHandle MUtils::UnboxScriptingTypeHandle(MTypeObject* value)
{

View File

@@ -85,6 +85,41 @@ struct NativeArray
}
};
/// <summary>
/// A simple POD type Span used with interop between managed and unmanaged sides.
/// </summary>
template<typename T>
struct NativeSpan
{
public:
T* Data;
int32 Length;
public:
static NativeSpan<T> AsSpan(T* data, int32 length)
{
return { data, length };
}
};
template<typename T>
NativeSpan<T> ToNativeSpan(const T* data, int32 length)
{
return { data, length };
}
template<typename T>
NativeSpan<T> ToNativeSpan(const Array<T>& array)
{
return { array.Get(), array.Count() };
}
template<typename T>
NativeSpan<T> ToNativeSpan(const Span<T>& span)
{
return { span.Get(), span.Length() };
}
#if USE_NETCORE
// Special case for boolean values, the handles are fixed and should not be removed
template<>
@@ -128,7 +163,7 @@ struct MConverter<bool>
void FreeManagedArray(MArray* array)
{
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
#endif
@@ -176,7 +211,7 @@ struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class
void FreeManagedArray(MArray* array)
{
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -241,12 +276,13 @@ struct MConverter<String>
void FreeManagedArray(MArray* array)
{
PLATFORM_DEBUG_BREAK;
MString** dataPtr = MCore::Array::GetAddress<MString*>(array);
auto length = MCore::Array::GetLength(array);
for (int32 i = 0; i < length; i++)
MCore::String::Free(dataPtr[i]);
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -299,12 +335,13 @@ struct MConverter<StringAnsi>
void FreeManagedArray(MArray* array)
{
PLATFORM_DEBUG_BREAK;
MString** dataPtr = MCore::Array::GetAddress<MString*>(array);
auto length = MCore::Array::GetLength(array);
for (int32 i = 0; i < length; i++)
MCore::String::Free(dataPtr[i]);
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -368,7 +405,7 @@ struct MConverter<StringView>
for (int32 i = 0; i < length; i++)
MCore::String::Free(dataPtr[i]);
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -427,7 +464,7 @@ struct MConverter<Variant>
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -485,7 +522,6 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
void FreeManagedArray(MArray* array)
{
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -540,7 +576,7 @@ struct MConverter<T, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Val
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -602,7 +638,7 @@ struct MConverter<ScriptingObjectReference<T>>
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -663,7 +699,7 @@ struct MConverter<AssetReference<T>>
void FreeManagedArray(MArray* array)
{
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -725,7 +761,7 @@ struct MConverter<SoftAssetReference<T>>
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -778,7 +814,7 @@ struct MConverter<Array<T>>
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
//MCore::GCHandle::Free(*(MGCHandle*)&array);
}
};
@@ -1031,6 +1067,27 @@ namespace MUtils
}
#if USE_NETCORE
/// <summary>
///
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
FORCE_INLINE String ToNativeString(const StringAnsi& str)
{
return String(str);
}
/// <summary>
///
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
FORCE_INLINE String ToNativeString(const StringAnsiView& str)
{
return String(str);
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
@@ -1040,7 +1097,7 @@ namespace MUtils
FORCE_INLINE T* ToNativeArray(const Array<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
T* arr = (T*)MCore::GC::AllocateMemory(data.Count() * sizeof(T), true);
T* arr = (T*)MCore::GC::AllocateMemory(data.Count() * sizeof(T), false);
Platform::MemoryCopy(arr, data.Get(), data.Count() * sizeof(T));
return arr;
}
@@ -1116,7 +1173,7 @@ namespace MUtils
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<U> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true) : nullptr;
arr.data = arr.length > 0 ? (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), false) : nullptr;
// Convert to managed
MConverter<T, U> converter;
@@ -1136,7 +1193,7 @@ namespace MUtils
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), false) : nullptr;
// Convert to managed
MConverter<T> converter;
@@ -1188,7 +1245,7 @@ namespace MUtils
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), false) : nullptr;
// Convert to managed
MConverter<T, U> converter;
@@ -1208,7 +1265,7 @@ namespace MUtils
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), false) : nullptr;
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
return arr;
}
@@ -1239,7 +1296,7 @@ namespace MUtils
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), false) : nullptr;
//Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
// Convert to managed
@@ -1261,7 +1318,7 @@ namespace MUtils
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), false) : nullptr;
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
return arr;
}
@@ -1302,7 +1359,7 @@ namespace MUtils
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<MObject*> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (MObject**)MCore::GC::AllocateMemory(arr.length * sizeof(MObject*), true) : nullptr;
arr.data = arr.length > 0 ? (MObject**)MCore::GC::AllocateMemory(arr.length * sizeof(MObject*), false) : nullptr;
// Convert to managed
MConverter<T> converter;
@@ -1320,7 +1377,7 @@ namespace MUtils
FORCE_INLINE bool* ToBoolArray(const Array<bool>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
bool* arr = (bool*)MCore::GC::AllocateMemory(data.Count() * sizeof(bool), true);
bool* arr = (bool*)MCore::GC::AllocateMemory(data.Count() * sizeof(bool), false);
memcpy(arr, data.Get(), data.Count() * sizeof(bool));
return arr;
}
@@ -1334,7 +1391,7 @@ namespace MUtils
FORCE_INLINE bool* ToBoolArray(const BitArray<AllocationType>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
bool* arr = (bool*)MCore::GC::AllocateMemory(data.Count() * sizeof(bool), true);
bool* arr = (bool*)MCore::GC::AllocateMemory(data.Count() * sizeof(bool), false);
for (int i = 0; i < data.Count(); i++)
arr[i] = data[i];
return arr;

View File

@@ -290,7 +290,7 @@ namespace FlaxEngine
/// </summary>
/// <param name="ptr">The pointer to the unmanaged (native) object.</param>
/// <returns>The object.</returns>
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_FromUnmanagedPtr", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_FromUnmanagedPtr")]
public static partial Object FromUnmanagedPtr(IntPtr ptr);
/// <summary>
@@ -315,37 +315,43 @@ namespace FlaxEngine
#region Internal Calls
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_Create1", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_Create1")]
internal static partial Object Internal_Create1([MarshalUsing(typeof(Interop.SystemTypeMarshaller))] Type type);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_Create2", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
internal static partial Object Internal_Create2(string typeName);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceCreated", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceCreated")]
internal static partial void Internal_ManagedInstanceCreated(Object managedInstance, IntPtr typeClass);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceDeleted", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceDeleted")]
internal static partial void Internal_ManagedInstanceDeleted(IntPtr nativeInstance);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_Destroy", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_Destroy")]
internal static partial void Internal_Destroy(IntPtr obj, float timeLeft);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_DestroyNow", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_DestroyNow")]
internal static partial void Internal_DestroyNow(IntPtr obj);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_GetTypeName", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
internal static partial string Internal_GetTypeName(IntPtr obj);
internal static string Internal_GetTypeName(IntPtr obj)
{
Internal_GetTypeName(obj, out string typeName);
return typeName;
}
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_FindObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_GetTypeName", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
internal static partial void Internal_GetTypeName(IntPtr obj, [MarshalUsing(typeof(Interop.StringAnsiViewMarshaller))] out string typeName);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_FindObject")]
internal static partial Object Internal_FindObject(ref Guid id, [MarshalUsing(typeof(Interop.SystemTypeMarshaller))] Type type, [MarshalAs(UnmanagedType.U1)] bool skipLog = false);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_TryFindObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_TryFindObject")]
internal static partial Object Internal_TryFindObject(ref Guid id, [MarshalUsing(typeof(Interop.SystemTypeMarshaller))] Type type);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ChangeID", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ChangeID")]
internal static partial void Internal_ChangeID(IntPtr obj, ref Guid id);
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_GetUnmanagedInterface", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_GetUnmanagedInterface")]
internal static partial IntPtr Internal_GetUnmanagedInterface(IntPtr obj, [MarshalUsing(typeof(Interop.SystemTypeMarshaller))] Type type);
#endregion

View File

@@ -431,6 +431,7 @@ MClass* MCore::Object::GetClass(const MObject* obj)
MString* MCore::Object::ToString(const MObject* obj)
{
CRASH;
static void* GetObjectStringPtr = GetStaticMethodPointer(TEXT("GetObjectString"));
return (MString*)CallStaticMethod<void*, const void*>(GetObjectStringPtr, obj);
}
@@ -443,28 +444,34 @@ int32 MCore::Object::GetHashCode(const MObject* obj)
MString* MCore::String::GetEmpty(const MDomain* domain)
{
CRASH;
static void* GetStringEmptyPtr = GetStaticMethodPointer(TEXT("GetStringEmpty"));
return (MString*)CallStaticMethod<void*>(GetStringEmptyPtr);
}
MString* MCore::String::New(const char* str, int32 length, const MDomain* domain)
{
CRASH;
static void* NewStringUTF8Ptr = GetStaticMethodPointer(TEXT("NewStringUTF8"));
return (MString*)CallStaticMethod<void*, const char*, int>(NewStringUTF8Ptr, str, length);
}
MString* MCore::String::New(const Char* str, int32 length, const MDomain* domain)
{
CRASH;
static void* NewStringUTF16Ptr = GetStaticMethodPointer(TEXT("NewStringUTF16"));
return (MString*)CallStaticMethod<void*, const Char*, int>(NewStringUTF16Ptr, str, length);
}
StringView MCore::String::GetChars(const MString* obj)
{
int32 length = 0;
::String& str = *(::String*)obj;
return StringView(str);
//CRASH;
/*int32 length = 0;
static void* GetStringPointerPtr = GetStaticMethodPointer(TEXT("GetStringPointer"));
const Char* chars = CallStaticMethod<const Char*, const void*, int*>(GetStringPointerPtr, obj, &length);
return StringView(chars, length);
return StringView(chars, length);*/
}
void MCore::String::Free(const MString* obj)
@@ -605,6 +612,8 @@ void MCore::GC::WriteArrayRef(MArray* dst, Span<MObject*> refs)
void* MCore::GC::AllocateMemory(int32 size, bool coTaskMem)
{
if (coTaskMem == true)
coTaskMem = coTaskMem;
static void* AllocMemoryPtr = GetStaticMethodPointer(TEXT("AllocMemory"));
return CallStaticMethod<void*, int, bool>(AllocMemoryPtr, size, coTaskMem);
}
@@ -613,6 +622,8 @@ void MCore::GC::FreeMemory(void* ptr, bool coTaskMem)
{
if (!ptr)
return;
if (coTaskMem == true)
coTaskMem = coTaskMem;
static void* FreeMemoryPtr = GetStaticMethodPointer(TEXT("FreeMemory"));
CallStaticMethod<void, void*, bool>(FreeMemoryPtr, ptr, coTaskMem);
}
@@ -1323,11 +1334,13 @@ MException::MException(MObject* exception)
MMethod* exceptionMsgGetter = exceptionMsgProp->GetGetMethod();
MString* exceptionMsg = (MString*)exceptionMsgGetter->Invoke(exception, nullptr, nullptr);
Message = MUtils::ToString(exceptionMsg);
MCore::String::Free(exceptionMsg);
MProperty* exceptionStackProp = exceptionClass->GetProperty("StackTrace");
MMethod* exceptionStackGetter = exceptionStackProp->GetGetMethod();
MString* exceptionStackTrace = (MString*)exceptionStackGetter->Invoke(exception, nullptr, nullptr);
StackTrace = MUtils::ToString(exceptionStackTrace);
MCore::String::Free(exceptionStackTrace);
MProperty* innerExceptionProp = exceptionClass->GetProperty("InnerException");
MMethod* innerExceptionGetter = innerExceptionProp->GetGetMethod();

View File

@@ -395,7 +395,7 @@ namespace FlaxEngine
/// Returns true if game scripts assembly has been loaded.
/// </summary>
/// <returns>True if game scripts assembly is loaded, otherwise false.</returns>
[LibraryImport("FlaxEngine", EntryPoint = "ScriptingInternal_HasGameModulesLoaded", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ScriptingInternal_HasGameModulesLoaded")]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool HasGameModulesLoaded();
@@ -403,14 +403,14 @@ namespace FlaxEngine
/// Returns true if given type is from one of the game scripts assemblies.
/// </summary>
/// <returns>True if the type is from game assembly, otherwise false.</returns>
[LibraryImport("FlaxEngine", EntryPoint = "ScriptingInternal_IsTypeFromGameScripts", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ScriptingInternal_IsTypeFromGameScripts")]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool IsTypeFromGameScripts([MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
/// <summary>
/// Flushes the removed objects (disposed objects using Object.Destroy).
/// </summary>
[LibraryImport("FlaxEngine", EntryPoint = "ScriptingInternal_FlushRemovedObjects", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ScriptingInternal_FlushRemovedObjects")]
public static partial void FlushRemovedObjects();
}
@@ -426,26 +426,26 @@ namespace FlaxEngine
/// Begins profiling a piece of code with a custom label.
/// </summary>
/// <param name="name">The name of the event.</param>
[LibraryImport("FlaxEngine", EntryPoint = "ProfilerInternal_BeginEvent", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ProfilerInternal_BeginEvent", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
public static partial void BeginEvent(string name);
/// <summary>
/// Ends profiling an event.
/// </summary>
[LibraryImport("FlaxEngine", EntryPoint = "ProfilerInternal_EndEvent", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ProfilerInternal_EndEvent", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
public static partial void EndEvent();
/// <summary>
/// Begins GPU profiling a piece of code with a custom label.
/// </summary>
/// <param name="name">The name of the event.</param>
[LibraryImport("FlaxEngine", EntryPoint = "ProfilerInternal_BeginEventGPU", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ProfilerInternal_BeginEventGPU", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
public static partial void BeginEventGPU(string name);
/// <summary>
/// Ends GPU profiling an event.
/// </summary>
[LibraryImport("FlaxEngine", EntryPoint = "ProfilerInternal_EndEventGPU", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[LibraryImport("FlaxEngine", EntryPoint = "ProfilerInternal_EndEventGPU")]
public static partial void EndEventGPU();
}
}

View File

@@ -26,6 +26,15 @@
#define ScriptingObject_unmanagedPtr "__unmanagedPtr"
#define ScriptingObject_id "__internalId"
//#if USE_NETCORE
//APgI_TYPEDEF() typedef MString* ManagedString;
//APgI_TYPEDEF() typedef MString* ManagedStringView;
//APgI_TYPEDEF() typedef MString* ManagedStringAnsiView;
API_TYPEDEF() typedef String ManagedString;
API_TYPEDEF() typedef StringView ManagedStringView;
API_TYPEDEF() typedef StringAnsiView ManagedStringAnsiView;
//#endif
// TODO: don't leak memory (use some kind of late manual GC for those wrapper objects)
typedef Pair<ScriptingObject*, ScriptingTypeHandle> ScriptingObjectsInterfaceKey;
Dictionary<ScriptingObjectsInterfaceKey, void*> ScriptingObjectsInterfaceWrappers;
@@ -611,12 +620,16 @@ DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_Create1(MTypeObject* type)
return managedInstance;
}
DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_Create2(MString* typeNameObj)
DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_Create2(ManagedStringView typeNameObj)
{
// Get typename
if (typeNameObj == nullptr)
DebugLog::ThrowArgumentNull("typeName");
#if USE_NETCORE
const StringView typeNameChars = typeNameObj;
#else
const StringView typeNameChars = MCore::String::GetChars(typeNameObj);
#endif
const StringAsANSI<100> typeNameData(typeNameChars.Get(), typeNameChars.Length());
const StringAnsiView typeName(typeNameData.Get(), typeNameChars.Length());
@@ -711,10 +724,15 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_DestroyNow(ScriptingObject* obj)
obj->DeleteObjectNow();
}
DEFINE_INTERNAL_CALL(MString*) ObjectInternal_GetTypeName(ScriptingObject* obj)
DEFINE_INTERNAL_CALL(void) ObjectInternal_GetTypeName(ScriptingObject* obj, ManagedStringAnsiView* typeName)
{
#if USE_NETCORE
INTERNAL_CALL_CHECK(obj);
*typeName = obj->GetType().Fullname;
#else
INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
return MUtils::ToString(obj->GetType().Fullname);
*typeName = MUtils::ToString(obj->GetType().Fullname);
#endif
}
DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_FindObject(Guid* id, MTypeObject* type, bool skipLog = false)

View File

@@ -99,6 +99,7 @@ void UICanvas::Serialize(SerializeStream& stream, const void* otherObj)
// Write result data
stream.RawValue(MCore::String::GetChars(invokeResultStr));
}
MCore::String::Free(invokeResultStr);
#endif
}

View File

@@ -118,6 +118,7 @@ void UIControl::Serialize(SerializeStream& stream, const void* otherObj)
const StringView invokeResultStrChars = MCore::String::GetChars(invokeResultStr);
stream.JKEY("Data");
stream.RawValue(invokeResultStrChars);
MCore::String::Free(invokeResultStr);
#endif
}