diff --git a/Source/Editor/Content/Import/TextureImportEntry.cs b/Source/Editor/Content/Import/TextureImportEntry.cs index abffe0ce7..7ea0157fe 100644 --- a/Source/Editor/Content/Import/TextureImportEntry.cs +++ b/Source/Editor/Content/Import/TextureImportEntry.cs @@ -391,8 +391,8 @@ namespace FlaxEditor.Content.Import MaxSize = managed.MaxSize, TextureGroup = managed.TextureGroup, Size = managed.Size, - SpriteAreas = managed.SpriteAreas?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteAreas)))) : IntPtr.Zero, - SpriteNames = managed.SpriteNames?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteNames)))) : IntPtr.Zero, + SpriteAreas = managed.SpriteAreas?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteAreas)))) : IntPtr.Zero, + SpriteNames = managed.SpriteNames?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteNames)))) : IntPtr.Zero, }; } internal static void Free(InternalOptionsNative unmanaged) diff --git a/Source/Editor/GUI/EnumComboBox.cs b/Source/Editor/GUI/EnumComboBox.cs index 24f818d0d..fe2326b23 100644 --- a/Source/Editor/GUI/EnumComboBox.cs +++ b/Source/Editor/GUI/EnumComboBox.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using FlaxEditor.CustomEditors; using FlaxEditor.CustomEditors.Elements; using FlaxEditor.Scripting; @@ -170,7 +171,7 @@ namespace FlaxEditor.GUI BuildEntriesDefault(type, _entries, formatMode); var hasTooltips = false; - var entries = Utils.ExtractArrayFromList(_entries); + var entries = CollectionsMarshal.AsSpan(_entries); for (int i = 0; i < _entries.Count; i++) { ref var e = ref entries[i]; diff --git a/Source/Editor/ViewportDebugDrawData.cs b/Source/Editor/ViewportDebugDrawData.cs index a983af168..5c2461a79 100644 --- a/Source/Editor/ViewportDebugDrawData.cs +++ b/Source/Editor/ViewportDebugDrawData.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using FlaxEngine; namespace FlaxEditor @@ -20,7 +21,7 @@ namespace FlaxEditor private int[] _highlightIndicesSet; private Model _highlightTrianglesModel; - internal IntPtr[] ActorsPtrs => Utils.ExtractArrayFromList(_actors); + internal Span ActorsPtrs => CollectionsMarshal.AsSpan(_actors); internal int ActorsCount => _actors.Count; diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs index 9c8a97f95..a62205bc8 100644 --- a/Source/Editor/Windows/OutputLogWindow.cs +++ b/Source/Editor/Windows/OutputLogWindow.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Xml; @@ -366,7 +367,7 @@ namespace FlaxEditor.Windows // Try to add the line for multi-line logs if (_entries.Count != 0 && !line.StartsWith("======")) { - ref var last = ref Utils.ExtractArrayFromList(_entries)[_entries.Count - 1]; + ref var last = ref CollectionsMarshal.AsSpan(_entries)[_entries.Count - 1]; last.Message += '\n'; last.Message += line; } @@ -471,7 +472,7 @@ namespace FlaxEditor.Windows _output.ErrorStyle.Font.GetFont(); // Generate the output log - var entries = Utils.ExtractArrayFromList(_entries); + Span entries = CollectionsMarshal.AsSpan(_entries); var searchQuery = _searchBox.Text; for (int i = _textBufferCount; i < _entries.Count; i++) { diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 4c06527eb..ff0997eaa 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -25,7 +25,7 @@ namespace FlaxEngine #region Native structures [StructLayout(LayoutKind.Sequential)] - internal struct ManagedClass + internal struct NativeClassDefinitions { internal IntPtr typeHandle; internal IntPtr name; @@ -35,7 +35,7 @@ namespace FlaxEngine } [StructLayout(LayoutKind.Sequential)] - internal struct ClassMethod + internal struct NativeMethodDefinitions { internal IntPtr name; internal int numParameters; @@ -44,7 +44,7 @@ namespace FlaxEngine } [StructLayout(LayoutKind.Sequential)] - internal struct ClassField + internal struct NativeFieldDefinitions { internal IntPtr name; internal IntPtr fieldHandle; @@ -53,7 +53,7 @@ namespace FlaxEngine } [StructLayout(LayoutKind.Sequential)] - internal struct ClassProperty + internal struct NativePropertyDefinitions { internal IntPtr name; internal IntPtr getterHandle; @@ -63,7 +63,7 @@ namespace FlaxEngine } [StructLayout(LayoutKind.Sequential)] - internal struct ClassAttribute + internal struct NativeAttributeDefinitions { internal IntPtr name; internal IntPtr attributeHandle; @@ -132,43 +132,6 @@ namespace FlaxEngine int AsData5; } -#if false - [StructLayout(LayoutKind.Sequential)] - internal struct GuidNative - { - internal int A; - internal short B; - internal short C; - internal byte D; - internal byte E; - internal byte F; - internal byte G; - internal byte H; - internal byte I; - internal byte J; - internal byte K; - - internal GuidNative(Guid guid) - { - byte[] bytes = guid.ToByteArray(); - A = MemoryMarshal.Cast(bytes.AsSpan())[0]; - B = MemoryMarshal.Cast(bytes.AsSpan())[4]; - C = MemoryMarshal.Cast(bytes.AsSpan())[6]; - D = bytes[8]; - E = bytes[9]; - F = bytes[10]; - G = bytes[11]; - H = bytes[12]; - I = bytes[13]; - J = bytes[14]; - K = bytes[15]; - } - - internal static implicit operator Guid(GuidNative guid) => new Guid(guid.A, guid.B, guid.C, guid.D, guid.E, guid.F, guid.G, guid.H, guid.I, guid.J, guid.K); - internal static explicit operator GuidNative(Guid guid) => new GuidNative(guid); - } -#endif - [StructLayout(LayoutKind.Sequential)] internal struct VersionNative { @@ -200,40 +163,85 @@ namespace FlaxEngine /// internal unsafe class ManagedArray { - private Array array; private GCHandle pinnedArrayHandle; private IntPtr unmanagedData; private int elementSize; private int length; - internal ManagedArray(Array arr) + internal static ManagedArray WrapNewArray(Array arr) => new ManagedArray(arr); + + /// + /// Returns an instance of ManagedArray from shared pool. + /// + /// + /// The resources must be released by calling FreePooled() instead of Free()-method. + /// + internal static ManagedArray WrapPooledArray(Array arr) { - array = arr; - unmanagedData = IntPtr.Zero; + ManagedArray managedArray = ManagedArrayPool.Get(); + managedArray.WrapArray(arr); + return managedArray; + } + + internal static ManagedArray AllocateNewArray(T* ptr, int length) where T : unmanaged => new ManagedArray(ptr, length, Unsafe.SizeOf()); + + internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, int elementSize) => new ManagedArray(ptr.ToPointer(), length, elementSize); + + /// + /// Returns an instance of ManagedArray from shared pool. + /// + /// + /// The resources must be released by calling FreePooled() instead of Free()-method. + /// + internal static ManagedArray AllocatePooledArray(T* ptr, int length) where T : unmanaged + { + ManagedArray managedArray = ManagedArrayPool.Get(); + managedArray.Allocate(ptr, length); + return managedArray; + } + + internal ManagedArray(Array arr) => WrapArray(arr); + + internal void WrapArray(Array arr) + { + pinnedArrayHandle = GCHandle.Alloc(arr, GCHandleType.Pinned); + unmanagedData = Marshal.UnsafeAddrOfPinnedArrayElement(arr, 0); length = arr.Length; elementSize = Marshal.SizeOf(arr.GetType().GetElementType()); } - private ManagedArray(void* ptr, int length, int elementSize) + internal void Allocate(T* ptr, int length) where T : unmanaged { - array = null; - this.unmanagedData = new IntPtr(ptr); + unmanagedData = new IntPtr(ptr); + this.length = length; + elementSize = Unsafe.SizeOf(); + } + + internal void Allocate(IntPtr ptr, int length, int elementSize) + { + unmanagedData = ptr; this.length = length; this.elementSize = elementSize; } + private ManagedArray() { } + + private ManagedArray(void* ptr, int length, int elementSize) => Allocate(new IntPtr(ptr), length, elementSize); + ~ManagedArray() { - if (unmanagedData != IntPtr.Zero || array != null) - Release(); + if (unmanagedData != IntPtr.Zero) + Free(); } - internal void Release() + internal void Free() { GC.SuppressFinalize(this); if (pinnedArrayHandle.IsAllocated) + { pinnedArrayHandle.Free(); - array = null; + unmanagedData = IntPtr.Zero; + } if (unmanagedData != IntPtr.Zero) { Marshal.FreeHGlobal(unmanagedData); @@ -241,41 +249,63 @@ namespace FlaxEngine } } - internal IntPtr PointerToPinnedArray + internal void FreePooled() { - get - { - if (array != null) - { - // Pin the array when it's accessed for the first time - if (!pinnedArrayHandle.IsAllocated) - pinnedArrayHandle = GCHandle.Alloc(array); - return Marshal.UnsafeAddrOfPinnedArrayElement(array, 0); - } - else - return unmanagedData; - } + Free(); + ManagedArrayPool.Put(this); } - internal void SetValue(IntPtr value, int index) - { - if (array != null) - array.SetValue(value, index); - else - GetSpan()[index] = value; - } + internal IntPtr GetPointer => unmanagedData; internal int Length => length; internal int ElementSize => elementSize; - internal Span GetSpan() where T : struct => array != null ? new Span((T[]) array) : new Span(unmanagedData.ToPointer(), length); + internal Span GetSpan() where T : struct => new Span(unmanagedData.ToPointer(), length); - internal T[] GetArray() where T : struct => array != null ? (T[])array : new Span(unmanagedData.ToPointer(), length).ToArray(); + internal T[] GetArray() where T : struct => new Span(unmanagedData.ToPointer(), length).ToArray(); - internal static ManagedArray Get(Array arr) => new ManagedArray(arr); + /// + /// Provides a pool of pre-allocated ManagedArray that can be re-used. + /// + private static class ManagedArrayPool + { + private static List> pool = new List>(); - internal static ManagedArray Get(T* ptr, int length) where T : unmanaged => new ManagedArray(ptr, length, Unsafe.SizeOf()); + internal static ManagedArray Get() + { + for (int i = 0; i < pool.Count; i++) + { + if (!pool[i].Item1) + { + var tuple = pool[i]; + tuple.Item1 = true; + pool[i] = tuple; + return tuple.Item2; + } + } + + var newTuple = (true, new ManagedArray()); + pool.Add(newTuple); + return newTuple.Item2; + } + + internal static void Put(ManagedArray obj) + { + for (int i = 0; i < pool.Count; i++) + { + if (pool[i].Item2 == obj) + { + var tuple = pool[i]; + tuple.Item1 = false; + pool[i] = tuple; + return; + } + } + + throw new Exception("Tried to free non-pooled ManagedArray as pooled ManagedArray"); + } + } } internal static class ManagedString @@ -446,7 +476,7 @@ namespace FlaxEngine public void FromManaged(Array managed) { if (managed != null) - managedArray = ManagedArray.Get(managed); + managedArray = ManagedArray.WrapPooledArray(managed); } public IntPtr ToUnmanaged() @@ -462,8 +492,8 @@ namespace FlaxEngine { if (managedArray != null) { + managedArray.FreePooled(); handle.Free(); - managedArray.Release(); } } } @@ -567,7 +597,7 @@ namespace FlaxEngine return; GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged)); - (Unsafe.As(handle.Target)).Release(); + (Unsafe.As(handle.Target)).Free(); handle.Free(); } @@ -593,7 +623,7 @@ namespace FlaxEngine numElements = managed.Length; - ManagedArray managedArray = ManagedArray.Get((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length); + ManagedArray managedArray = ManagedArray.AllocatePooledArray((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length); var ptr = GCHandle.ToIntPtr(GCHandle.Alloc(managedArray)); return (TUnmanagedElement*)ptr; @@ -616,7 +646,7 @@ namespace FlaxEngine return; GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged)); - (Unsafe.As(handle.Target)).Release(); + (Unsafe.As(handle.Target)).FreePooled(); handle.Free(); } } @@ -633,7 +663,8 @@ namespace FlaxEngine return; managedArray = managed; - unmanagedArray = ManagedArray.Get((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length); + + unmanagedArray = ManagedArray.AllocatePooledArray((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length); handle = GCHandle.Alloc(unmanagedArray); } @@ -670,7 +701,7 @@ namespace FlaxEngine public void Free() { - unmanagedArray.Release(); + unmanagedArray.FreePooled(); handle.Free(); } } @@ -685,7 +716,7 @@ namespace FlaxEngine numElements = managed.Length; - ManagedArray managedArray = ManagedArray.Get((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length); + ManagedArray managedArray = ManagedArray.AllocatePooledArray((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length); IntPtr handle = GCHandle.ToIntPtr(GCHandle.Alloc(managedArray)); return (TUnmanagedElement*)handle; @@ -721,7 +752,7 @@ namespace FlaxEngine return; GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged)); - Unsafe.As(handle.Target).Release(); + Unsafe.As(handle.Target).FreePooled(); handle.Free(); } } @@ -1200,17 +1231,20 @@ namespace FlaxEngine /// /// Returns a reference to the value of the field. - /// + /// private static ref TField GetFieldReference(FieldInfo field, ref T fieldOwner) { - Assert.IsTrue(!field.IsInitOnly); - // Get the address of the field, source: https://stackoverflow.com/a/56512720 - byte* fieldPtr = (byte*)Unsafe.AsPointer(ref fieldOwner) + (Marshal.ReadInt32(field.FieldHandle.Value + 4 + IntPtr.Size) & 0xFFFFFF); if (typeof(T).IsValueType) + { + byte* fieldPtr = (byte*)Unsafe.AsPointer(ref fieldOwner) + (Marshal.ReadInt32(field.FieldHandle.Value + 4 + IntPtr.Size) & 0xFFFFFF); return ref Unsafe.AsRef(fieldPtr); + } else - return ref Unsafe.AsRef(fieldPtr + IntPtr.Size); + { + byte* fieldPtr = (byte*)Unsafe.As(ref fieldOwner) + IntPtr.Size + (Marshal.ReadInt32(field.FieldHandle.Value + 4 + IntPtr.Size) & 0xFFFFFF); + return ref Unsafe.AsRef(fieldPtr); + } } private static IntPtr EnsureAlignment(IntPtr ptr, int alignment) @@ -1278,18 +1312,8 @@ namespace FlaxEngine fieldOffset += (fieldPtr - startPtr).ToInt32(); } - if (field.IsInitOnly) - { - //TypedReference ownerRef = __makeref(fieldOwner); - //TField fieldValue = (TField)field.GetValueDirect(ownerRef); - TField fieldValue = (TField)field.GetValue(fieldOwner); - MarshalHelperValueType.ToNative(ref fieldValue, fieldPtr); - } - else - { - ref TField fieldValueRef = ref GetFieldReference(field, ref fieldOwner); - MarshalHelperValueType.ToNative(ref fieldValueRef, fieldPtr); - } + ref TField fieldValueRef = ref GetFieldReference(field, ref fieldOwner); + MarshalHelperValueType.ToNative(ref fieldValueRef, fieldPtr); } } @@ -1304,18 +1328,8 @@ namespace FlaxEngine internal static void ToNativeField(FieldInfo field, ref T fieldOwner, IntPtr fieldPtr, out int fieldOffset) { - if (field.IsInitOnly) - { - //TypedReference ownerRef = __makeref(fieldOwner); - //TField fieldValue = (TField)field.GetValueDirect(ownerRef); - TField fieldValue = (TField)field.GetValue(fieldOwner); - MarshalHelperReferenceType.ToNative(ref fieldValue, fieldPtr); - } - else - { - ref TField fieldValueRef = ref GetFieldReference(field, ref fieldOwner); - MarshalHelperReferenceType.ToNative(ref fieldValueRef, fieldPtr); - } + ref TField fieldValueRef = ref GetFieldReference(field, ref fieldOwner); + MarshalHelperReferenceType.ToNative(ref fieldValueRef, fieldPtr); fieldOffset = IntPtr.Size; } } @@ -1466,27 +1480,15 @@ namespace FlaxEngine Unsafe.Write(nativePtr.ToPointer(), managedPtr); } } - - internal class FieldBlob - { - internal FieldInfo field; - internal MarshalToNativeFieldDelegate toNativeMarshaller; - internal FieldBlob(FieldInfo field, Type type) - { - this.field = field; - toNativeMarshaller = GetToNativeFieldMarshallerDelegate(type); - } - } - - internal class MethodBlob + internal class MethodHolder { internal Type[] parameterTypes; internal MethodInfo method; private Invoker.MarshalAndInvokeDelegate invokeDelegate; private object delegInvoke; - internal MethodBlob(MethodInfo method) + internal MethodHolder(MethodInfo method) { this.method = method; parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray(); @@ -1529,10 +1531,10 @@ namespace FlaxEngine internal static GCHandle GetMethodGCHandle(MethodInfo method) { - MethodBlob methodBlob = new MethodBlob(method); + MethodHolder methodHolder = new MethodHolder(method); - GCHandle handle = GCHandle.Alloc(methodBlob); - if (methodBlob.parameterTypes.Any(x => x.IsCollectible) || method.IsCollectible) + GCHandle handle = GCHandle.Alloc(methodHolder); + if (methodHolder.parameterTypes.Any(x => x.IsCollectible) || method.IsCollectible) methodHandlesCollectible.Add(handle); else methodHandles.Add(handle); @@ -1550,24 +1552,24 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static unsafe void GetManagedClasses(IntPtr assemblyHandle, ManagedClass** managedClasses, int* managedClassCount) + internal static unsafe void GetManagedClasses(IntPtr assemblyHandle, NativeClassDefinitions** managedClasses, int* managedClassCount) { Assembly assembly = Unsafe.As(GCHandle.FromIntPtr(assemblyHandle).Target); var assemblyTypes = GetAssemblyTypes(assembly); - ManagedClass* arr = (ManagedClass*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * assemblyTypes.Length).ToPointer(); + NativeClassDefinitions* arr = (NativeClassDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * assemblyTypes.Length).ToPointer(); for (int i = 0; i < assemblyTypes.Length; i++) { var type = assemblyTypes[i]; - IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); + IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); bool isStatic = type.IsAbstract && type.IsSealed; bool isInterface = type.IsInterface; bool isAbstract = type.IsAbstract; GCHandle typeHandle = GetOrAddTypeGCHandle(type); - ManagedClass managedClass = new ManagedClass() + NativeClassDefinitions managedClass = new NativeClassDefinitions() { typeHandle = GCHandle.ToIntPtr(typeHandle), name = Marshal.StringToCoTaskMemAnsi(type.Name), @@ -1583,12 +1585,12 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static unsafe void GetManagedClassFromType(IntPtr typeHandle, ManagedClass* managedClass, IntPtr* assemblyHandle) + internal static unsafe void GetManagedClassFromType(IntPtr typeHandle, NativeClassDefinitions* managedClass, IntPtr* assemblyHandle) { Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); GCHandle classTypeHandle = GetOrAddTypeGCHandle(type); - *managedClass = new ManagedClass() + *managedClass = new NativeClassDefinitions() { typeHandle = GCHandle.ToIntPtr(classTypeHandle), name = Marshal.StringToCoTaskMemAnsi(type.Name), @@ -1600,7 +1602,7 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static void GetClassMethods(IntPtr typeHandle, ClassMethod** classMethods, int* classMethodsCount) + internal static void GetClassMethods(IntPtr typeHandle, NativeMethodDefinitions** classMethods, int* classMethodsCount) { Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); @@ -1612,11 +1614,11 @@ namespace FlaxEngine foreach (MethodInfo method in instanceMethods) methods.Add(method); - ClassMethod* arr = (ClassMethod*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * methods.Count).ToPointer(); + NativeMethodDefinitions* arr = (NativeMethodDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * methods.Count).ToPointer(); for (int i = 0; i < methods.Count; i++) { - IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); - ClassMethod classMethod = new ClassMethod() + IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); + NativeMethodDefinitions classMethod = new NativeMethodDefinitions() { name = Marshal.StringToCoTaskMemAnsi(methods[i].Name), numParameters = methods[i].GetParameters().Length, @@ -1629,31 +1631,43 @@ namespace FlaxEngine *classMethodsCount = methods.Count; } + internal class FieldHolder + { + internal FieldInfo field; + internal MarshalToNativeFieldDelegate toNativeMarshaller; + + internal FieldHolder(FieldInfo field, Type type) + { + this.field = field; + toNativeMarshaller = GetToNativeFieldMarshallerDelegate(type); + } + } + [UnmanagedCallersOnly] - internal static void GetClassFields(IntPtr typeHandle, ClassField** classFields, int* classFieldsCount) + internal static void GetClassFields(IntPtr typeHandle, NativeFieldDefinitions** classFields, int* classFieldsCount) { Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - ClassField* arr = (ClassField*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * fields.Length).ToPointer(); + NativeFieldDefinitions* arr = (NativeFieldDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * fields.Length).ToPointer(); for (int i = 0; i < fields.Length; i++) { - IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); + IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); - FieldBlob fieldBlob = new FieldBlob(fields[i], type); + FieldHolder fieldHolder = new FieldHolder(fields[i], type); - GCHandle fieldHandle = GCHandle.Alloc(fieldBlob); + GCHandle fieldHandle = GCHandle.Alloc(fieldHolder); if (type.IsCollectible) fieldHandleCacheCollectible.Add(fieldHandle); else fieldHandleCache.Add(fieldHandle); - ClassField classField = new ClassField() + NativeFieldDefinitions classField = new NativeFieldDefinitions() { - name = Marshal.StringToCoTaskMemAnsi(fieldBlob.field.Name), + name = Marshal.StringToCoTaskMemAnsi(fieldHolder.field.Name), fieldHandle = GCHandle.ToIntPtr(fieldHandle), - fieldTypeHandle = GCHandle.ToIntPtr(GetOrAddTypeGCHandle(fieldBlob.field.FieldType)), - fieldAttributes = (uint)fieldBlob.field.Attributes, + fieldTypeHandle = GCHandle.ToIntPtr(GetOrAddTypeGCHandle(fieldHolder.field.FieldType)), + fieldAttributes = (uint)fieldHolder.field.Attributes, }; Unsafe.Write(ptr.ToPointer(), classField); } @@ -1662,20 +1676,20 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static void GetClassProperties(IntPtr typeHandle, ClassProperty** classProperties, int* classPropertiesCount) + internal static void GetClassProperties(IntPtr typeHandle, NativePropertyDefinitions** classProperties, int* classPropertiesCount) { Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - ClassProperty* arr = (ClassProperty*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * properties.Length).ToPointer(); + NativePropertyDefinitions* arr = (NativePropertyDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * properties.Length).ToPointer(); for (int i = 0; i < properties.Length; i++) { - IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); + IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); var getterMethod = properties[i].GetGetMethod(true); var setterMethod = properties[i].GetSetMethod(true); - ClassProperty classProperty = new ClassProperty() + NativePropertyDefinitions classProperty = new NativePropertyDefinitions() { name = Marshal.StringToCoTaskMemAnsi(properties[i].Name), }; @@ -1696,16 +1710,16 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static void GetClassAttributes(IntPtr typeHandle, ClassAttribute** classAttributes, int* classAttributesCount) + internal static void GetClassAttributes(IntPtr typeHandle, NativeAttributeDefinitions** classAttributes, int* classAttributesCount) { Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); object[] attributeValues = type.GetCustomAttributes(false); Type[] attributeTypes = type.GetCustomAttributes(false).Select(x => x.GetType()).ToArray(); - ClassAttribute* arr = (ClassAttribute*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * attributeTypes.Length).ToPointer(); + NativeAttributeDefinitions* arr = (NativeAttributeDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * attributeTypes.Length).ToPointer(); for (int i = 0; i < attributeTypes.Length; i++) { - IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); + IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); if (!classAttributesCacheCollectible.TryGetValue(attributeValues[i], out GCHandle attributeHandle)) { @@ -1714,7 +1728,7 @@ namespace FlaxEngine } GCHandle attributeTypeHandle = GetOrAddTypeGCHandle(attributeTypes[i]); - ClassAttribute classAttribute = new ClassAttribute() + NativeAttributeDefinitions classAttribute = new NativeAttributeDefinitions() { name = Marshal.StringToCoTaskMemAnsi(attributeTypes[i].Name), attributeTypeHandle = GCHandle.ToIntPtr(attributeTypeHandle), @@ -1763,8 +1777,8 @@ namespace FlaxEngine [UnmanagedCallersOnly] internal static IntPtr GetMethodReturnType(IntPtr methodHandle) { - MethodBlob methodBlob = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); - Type returnType = methodBlob.method.ReturnType; + MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + Type returnType = methodHolder.method.ReturnType; return GCHandle.ToIntPtr(GetTypeGCHandle(returnType)); } @@ -1772,13 +1786,13 @@ namespace FlaxEngine [UnmanagedCallersOnly] internal static void GetMethodParameterTypes(IntPtr methodHandle, IntPtr* typeHandles) { - MethodBlob methodBlob = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); - Type returnType = methodBlob.method.ReturnType; + MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + Type returnType = methodHolder.method.ReturnType; - IntPtr arr = Marshal.AllocCoTaskMem(IntPtr.Size * methodBlob.parameterTypes.Length); - for (int i = 0; i < methodBlob.parameterTypes.Length; i++) + IntPtr arr = Marshal.AllocCoTaskMem(IntPtr.Size * methodHolder.parameterTypes.Length); + for (int i = 0; i < methodHolder.parameterTypes.Length; i++) { - GCHandle typeHandle = GetOrAddTypeGCHandle(methodBlob.parameterTypes[i]); + GCHandle typeHandle = GetOrAddTypeGCHandle(methodHolder.parameterTypes[i]); Marshal.WriteIntPtr(IntPtr.Add(new IntPtr(arr), IntPtr.Size * i), GCHandle.ToIntPtr(typeHandle)); } *typeHandles = arr; @@ -1813,18 +1827,14 @@ namespace FlaxEngine internal static class ArrayFactory { - private static class Internal - { - internal static Array CreateArrayDelegate(long size) => new T[size]; - } - private delegate Array CreateArrayDelegate(long size); + private static ConcurrentDictionary marshalledTypes = new ConcurrentDictionary(1, 3); private static ConcurrentDictionary createArrayDelegates = new ConcurrentDictionary(1, 3); - private static CreateArrayDelegate GetCreateArrayDelegate(Type type) + internal static Type GetMarshalledType(Type elementType) { - static CreateArrayDelegate Factory(Type type) + static Type Factory(Type type) { Type marshalType; if (IsBlittable(type)) @@ -1832,28 +1842,52 @@ namespace FlaxEngine else marshalType = GetInternalType(type) ?? typeof(IntPtr); - MethodInfo method = typeof(Internal<>).MakeGenericType(marshalType).GetMethod(nameof(Internal.CreateArrayDelegate), BindingFlags.Static | BindingFlags.NonPublic); + return marshalType; + } + + if (marshalledTypes.TryGetValue(elementType, out var marshalledType)) + return marshalledType; + return marshalledTypes.GetOrAdd(elementType, Factory); + } + + internal static Array CreateArray(Type type, long size) + { + static CreateArrayDelegate Factory(Type type) + { + Type marshalledType = GetMarshalledType(type); + MethodInfo method = typeof(Internal<>).MakeGenericType(marshalledType).GetMethod(nameof(Internal.CreateArrayDelegate), BindingFlags.Static | BindingFlags.NonPublic); return method.CreateDelegate(); } if (createArrayDelegates.TryGetValue(type, out var deleg)) - return deleg; - return createArrayDelegates.GetOrAdd(type, Factory); + return deleg(size); + return createArrayDelegates.GetOrAdd(type, Factory)(size); } - internal static Array CreateArray(Type type, long size) => GetCreateArrayDelegate(type)(size); - internal static Type GetMarshalledType(Type elementType) => GetCreateArrayDelegate(elementType).Method.DeclaringType.GenericTypeArguments[0]; + private static class Internal + { + internal static Array CreateArrayDelegate(long size) => new T[size]; + } } [UnmanagedCallersOnly] internal static IntPtr NewArray(IntPtr typeHandle, long size) { Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); - - Array arr = ArrayFactory.CreateArray(type, size); - ManagedArray managedArray = ManagedArray.Get(arr); - return GCHandle.ToIntPtr(GCHandle.Alloc(managedArray/*, GCHandleType.Weak*/)); + + Type marshalledType = ArrayFactory.GetMarshalledType(type); + if (marshalledType.IsValueType) + { + ManagedArray managedArray = ManagedArray.AllocateNewArray(Marshal.AllocHGlobal(Marshal.SizeOf(marshalledType) * (int)size), (int)size, Marshal.SizeOf(marshalledType)); + return GCHandle.ToIntPtr(GCHandle.Alloc(managedArray/*, GCHandleType.Weak*/)); + } + else + { + Array arr = ArrayFactory.CreateArray(type, size); + ManagedArray managedArray = ManagedArray.WrapNewArray(arr); + return GCHandle.ToIntPtr(GCHandle.Alloc(managedArray/*, GCHandleType.Weak*/)); + } } [UnmanagedCallersOnly] @@ -1864,7 +1898,7 @@ namespace FlaxEngine return IntPtr.Zero; Assert.IsTrue(index >= 0 && index < managedArray.Length); - return IntPtr.Add(managedArray.PointerToPinnedArray, size * index); + return IntPtr.Add(managedArray.GetPointer, size * index); } [UnmanagedCallersOnly] @@ -1979,15 +2013,16 @@ namespace FlaxEngine [UnmanagedCallersOnly] internal static IntPtr InvokeMethod(IntPtr instancePtr, IntPtr methodHandle, IntPtr paramPtr, IntPtr exceptionPtr) { - MethodBlob methodBlob = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); - object returnObject; - if (methodBlob.TryGetDelegate(out var methodDelegate, out var methodDelegateContext)) + + if (methodHolder.TryGetDelegate(out var methodDelegate, out var methodDelegateContext)) { // Fast path, invoke the method with minimal allocations + IntPtr returnValue; try { - returnObject = methodDelegate(methodDelegateContext, instancePtr, paramPtr); + returnValue = methodDelegate(methodDelegateContext, instancePtr, paramPtr); } catch (Exception exception) { @@ -1997,23 +2032,25 @@ namespace FlaxEngine Marshal.WriteIntPtr(exceptionPtr, GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak))); return IntPtr.Zero; } + return returnValue; } else { // Slow path, method parameters needs to be stored in heap - int numParams = methodBlob.parameterTypes.Length; + object returnObject; + int numParams = methodHolder.parameterTypes.Length; IntPtr* nativePtrs = stackalloc IntPtr[numParams]; object[] methodParameters = new object[numParams]; for (int i = 0; i < numParams; i++) { nativePtrs[i] = Marshal.ReadIntPtr(IntPtr.Add(paramPtr, sizeof(IntPtr) * i)); - methodParameters[i] = MarshalToManaged(nativePtrs[i], methodBlob.parameterTypes[i]); + methodParameters[i] = MarshalToManaged(nativePtrs[i], methodHolder.parameterTypes[i]); } try { - returnObject = methodBlob.method.Invoke(instancePtr != IntPtr.Zero ? GCHandle.FromIntPtr(instancePtr).Target : null, methodParameters); + returnObject = methodHolder.method.Invoke(instancePtr != IntPtr.Zero ? GCHandle.FromIntPtr(instancePtr).Target : null, methodParameters); } catch (Exception exception) { @@ -2035,45 +2072,45 @@ namespace FlaxEngine // Marshal reference parameters back to original unmanaged references for (int i = 0; i < numParams; i++) { - Type parameterType = methodBlob.parameterTypes[i]; + Type parameterType = methodHolder.parameterTypes[i]; if (parameterType.IsByRef) MarshalToNative(methodParameters[i], nativePtrs[i], parameterType.GetElementType()); } - } - if (returnObject is not null) - { - if (methodBlob.method.ReturnType == typeof(string)) - return ManagedString.ToNative(Unsafe.As(returnObject)); - else if (methodBlob.method.ReturnType == typeof(IntPtr)) - return (IntPtr)returnObject; - else if (methodBlob.method.ReturnType == typeof(bool)) - return (bool)returnObject ? boolTruePtr : boolFalsePtr; - else if (methodBlob.method.ReturnType == typeof(Type)) - return GCHandle.ToIntPtr(GetOrAddTypeGCHandle(Unsafe.As(returnObject))); - else if (methodBlob.method.ReturnType == typeof(object[])) - return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); - else - return GCHandle.ToIntPtr(GCHandle.Alloc(returnObject, GCHandleType.Weak)); + if (returnObject is not null) + { + if (methodHolder.method.ReturnType == typeof(string)) + return ManagedString.ToNative(Unsafe.As(returnObject)); + else if (methodHolder.method.ReturnType == typeof(IntPtr)) + return (IntPtr)returnObject; + else if (methodHolder.method.ReturnType == typeof(bool)) + return (bool)returnObject ? boolTruePtr : boolFalsePtr; + else if (methodHolder.method.ReturnType == typeof(Type)) + return GCHandle.ToIntPtr(GetOrAddTypeGCHandle(Unsafe.As(returnObject))); + else if (methodHolder.method.ReturnType == typeof(object[])) + return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); + else + return GCHandle.ToIntPtr(GCHandle.Alloc(returnObject, GCHandleType.Weak)); + } + return IntPtr.Zero; } - return IntPtr.Zero; } [UnmanagedCallersOnly] internal static IntPtr GetMethodUnmanagedFunctionPointer(IntPtr methodHandle) { - MethodBlob methodBlob = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); // Wrap the method call, this is needed to get the object instance from GCHandle and to pass the exception back to native side MethodInfo invokeThunk = typeof(ThunkContext).GetMethod(nameof(ThunkContext.InvokeThunk)); Type delegateType = DelegateHelpers.MakeNewCustomDelegate(invokeThunk.GetParameters().Select(x => x.ParameterType).Append(invokeThunk.ReturnType).ToArray()); - ThunkContext context = new ThunkContext(methodBlob.method); + ThunkContext context = new ThunkContext(methodHolder.method); Delegate methodDelegate = invokeThunk.CreateDelegate(delegateType, context); IntPtr functionPtr = Marshal.GetFunctionPointerForDelegate(methodDelegate); // Keep a reference to the delegate to prevent it from being garbage collected - if (methodBlob.method.IsCollectible) + if (methodHolder.method.IsCollectible) cachedDelegatesCollectible[functionPtr] = methodDelegate; else cachedDelegates[functionPtr] = methodDelegate; @@ -2085,7 +2122,7 @@ namespace FlaxEngine internal static void FieldSetValue(IntPtr fieldOwnerHandle, IntPtr fieldHandle, IntPtr valuePtr) { object fieldOwner = GCHandle.FromIntPtr(fieldOwnerHandle).Target; - FieldBlob field = Unsafe.As(GCHandle.FromIntPtr(fieldHandle).Target); + FieldHolder field = Unsafe.As(GCHandle.FromIntPtr(fieldHandle).Target); field.field.SetValue(fieldOwner, Marshal.PtrToStructure(valuePtr, field.field.FieldType)); } @@ -2093,7 +2130,7 @@ namespace FlaxEngine internal static void FieldGetValue(IntPtr fieldOwnerHandle, IntPtr fieldHandle, IntPtr valuePtr) { object fieldOwner = GCHandle.FromIntPtr(fieldOwnerHandle).Target; - FieldBlob field = Unsafe.As(GCHandle.FromIntPtr(fieldHandle).Target); + FieldHolder field = Unsafe.As(GCHandle.FromIntPtr(fieldHandle).Target); field.toNativeMarshaller(field.field, fieldOwner, valuePtr, out int fieldOffset); } @@ -2101,8 +2138,8 @@ namespace FlaxEngine internal static void SetArrayValueReference(IntPtr arrayHandle, IntPtr elementPtr, IntPtr valueHandle) { ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(arrayHandle).Target); - int index = (int)(elementPtr.ToInt64() - managedArray.PointerToPinnedArray.ToInt64()) / managedArray.ElementSize; - managedArray.SetValue(valueHandle, index); + int index = (int)(elementPtr.ToInt64() - managedArray.GetPointer.ToInt64()) / managedArray.ElementSize; + managedArray.GetSpan()[index] = valueHandle; } [UnmanagedCallersOnly] @@ -2290,8 +2327,8 @@ namespace FlaxEngine [UnmanagedCallersOnly] internal static byte GetMethodParameterIsOut(IntPtr methodHandle, int parameterNum) { - MethodBlob methodBlob = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); - ParameterInfo parameterInfo = methodBlob.method.GetParameters()[parameterNum]; + MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + ParameterInfo parameterInfo = methodHolder.method.GetParameters()[parameterNum]; return (byte)(parameterInfo.IsOut ? 1 : 0); } @@ -2606,13 +2643,13 @@ namespace FlaxEngine public IntPtr InvokeThunk(IntPtr instancePtr, IntPtr param1, IntPtr param2, IntPtr param3, IntPtr param4, IntPtr param5, IntPtr param6, IntPtr param7) { IntPtr* nativePtrs = stackalloc IntPtr[] { param1, param2, param3, param4, param5, param6, param7 }; - object returnObject; if (methodDelegate != null) { + IntPtr returnValue; try { - returnObject = methodDelegate(methodDelegateContext, instancePtr, nativePtrs); + returnValue = methodDelegate(methodDelegateContext, instancePtr, nativePtrs); } catch (Exception exception) { @@ -2624,10 +2661,12 @@ namespace FlaxEngine Marshal.WriteIntPtr(exceptionPtr, GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak))); return IntPtr.Zero; } + return returnValue; } else { // The parameters are wrapped in GCHandles + object returnObject; int numParams = parameterTypes.Length; object[] methodParameters = new object[numParams]; for (int i = 0; i < numParams; i++) @@ -2647,24 +2686,24 @@ namespace FlaxEngine Marshal.WriteIntPtr(exceptionPtr, GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak))); return IntPtr.Zero; } - } - if (returnObject is not null) - { - if (method.ReturnType == typeof(string)) - return ManagedString.ToNative(Unsafe.As(returnObject)); - else if (method.ReturnType == typeof(IntPtr)) - return (IntPtr)returnObject; - else if (method.ReturnType == typeof(bool)) - return (bool)returnObject ? boolTruePtr : boolFalsePtr; - else if (method.ReturnType == typeof(Type)) - return GCHandle.ToIntPtr(GetOrAddTypeGCHandle(Unsafe.As(returnObject))); - else if (method.ReturnType == typeof(object[])) - return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); - else - return GCHandle.ToIntPtr(GCHandle.Alloc(returnObject, GCHandleType.Weak)); + if (returnObject is not null) + { + if (method.ReturnType == typeof(string)) + return ManagedString.ToNative(Unsafe.As(returnObject)); + else if (method.ReturnType == typeof(IntPtr)) + return (IntPtr)returnObject; + else if (method.ReturnType == typeof(bool)) + return (bool)returnObject ? boolTruePtr : boolFalsePtr; + else if (method.ReturnType == typeof(Type)) + return GCHandle.ToIntPtr(GetOrAddTypeGCHandle(Unsafe.As(returnObject))); + else if (method.ReturnType == typeof(object[])) + return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); + else + return GCHandle.ToIntPtr(GCHandle.Alloc(returnObject, GCHandleType.Weak)); + } + return IntPtr.Zero; } - return IntPtr.Zero; } } } diff --git a/Source/Engine/Engine/NativeInterop_Invoker.cs b/Source/Engine/Engine/NativeInterop_Invoker.cs index 5ca7bcc3c..1426565ef 100644 --- a/Source/Engine/Engine/NativeInterop_Invoker.cs +++ b/Source/Engine/Engine/NativeInterop_Invoker.cs @@ -7,6 +7,7 @@ using System.Linq.Expressions; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; +using System.Diagnostics; namespace FlaxEngine { @@ -14,8 +15,8 @@ namespace FlaxEngine { internal static class Invoker { - internal delegate object MarshalAndInvokeDelegate(object delegateContext, IntPtr instancePtr, IntPtr paramPtr); - internal delegate object InvokeThunkDelegate(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs); + internal delegate IntPtr MarshalAndInvokeDelegate(object delegateContext, IntPtr instancePtr, IntPtr paramPtr); + internal delegate IntPtr InvokeThunkDelegate(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs); internal static T* ToPointer(IntPtr ptr) where T : unmanaged { @@ -48,6 +49,22 @@ namespace FlaxEngine return lambda.Compile(); } + internal static IntPtr MarshalReturnValue(ref TRet returnValue) + { + if (typeof(TRet) == typeof(string)) + return ManagedString.ToNative(Unsafe.As(returnValue)); + else if (typeof(TRet) == typeof(IntPtr)) + return (IntPtr)(object)returnValue; + else if (typeof(TRet) == typeof(bool)) + return (bool)(object)returnValue ? boolTruePtr : boolFalsePtr; + else if (typeof(TRet) == typeof(Type)) + return returnValue != null ? GCHandle.ToIntPtr(GetOrAddTypeGCHandle(Unsafe.As(returnValue))) : IntPtr.Zero; + else if (typeof(TRet) == typeof(object[])) + return returnValue != null ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnValue))), GCHandleType.Weak)) : IntPtr.Zero; + else + return returnValue != null ? GCHandle.ToIntPtr(GCHandle.Alloc(returnValue, GCHandleType.Weak)) : IntPtr.Zero; + } + internal static class InvokerNoRet0 { @@ -64,22 +81,24 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); deleg(GCHandle.FromIntPtr(instancePtr).Target); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); deleg(GCHandle.FromIntPtr(instancePtr).Target); - return null; + return IntPtr.Zero; } } @@ -98,7 +117,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -113,10 +133,11 @@ namespace FlaxEngine if (types[0].IsByRef) MarshalHelper.ToNative(ref param1, param1Ptr); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -124,7 +145,7 @@ namespace FlaxEngine deleg(GCHandle.FromIntPtr(instancePtr).Target, param1); - return null; + return IntPtr.Zero; } } @@ -143,7 +164,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -163,10 +185,11 @@ namespace FlaxEngine if (types[1].IsByRef) MarshalHelper.ToNative(ref param2, param2Ptr); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -175,7 +198,7 @@ namespace FlaxEngine deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2); - return null; + return IntPtr.Zero; } } @@ -194,7 +217,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -219,10 +243,11 @@ namespace FlaxEngine if (types[2].IsByRef) MarshalHelper.ToNative(ref param3, param3Ptr); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -232,7 +257,7 @@ namespace FlaxEngine deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2, param3); - return null; + return IntPtr.Zero; } } @@ -251,7 +276,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -281,10 +307,11 @@ namespace FlaxEngine if (types[3].IsByRef) MarshalHelper.ToNative(ref param4, param4Ptr); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -295,7 +322,7 @@ namespace FlaxEngine deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2, param3, param4); - return null; + return IntPtr.Zero; } } @@ -314,22 +341,24 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); deleg(); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); deleg(); - return null; + return IntPtr.Zero; } } @@ -348,7 +377,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -363,10 +393,11 @@ namespace FlaxEngine if (types[0].IsByRef) MarshalHelper.ToNative(ref param1, param1Ptr); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -374,7 +405,7 @@ namespace FlaxEngine deleg(param1); - return null; + return IntPtr.Zero; } } @@ -393,7 +424,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -413,10 +445,11 @@ namespace FlaxEngine if (types[1].IsByRef) MarshalHelper.ToNative(ref param2, param2Ptr); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -425,7 +458,7 @@ namespace FlaxEngine deleg(param1, param2); - return null; + return IntPtr.Zero; } } @@ -444,7 +477,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -469,10 +503,11 @@ namespace FlaxEngine if (types[2].IsByRef) MarshalHelper.ToNative(ref param3, param3Ptr); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -482,7 +517,7 @@ namespace FlaxEngine deleg(param1, param2, param3); - return null; + return IntPtr.Zero; } } @@ -501,7 +536,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -531,10 +567,11 @@ namespace FlaxEngine if (types[3].IsByRef) MarshalHelper.ToNative(ref param4, param4Ptr); - return null; + return IntPtr.Zero; } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -545,7 +582,7 @@ namespace FlaxEngine deleg(param1, param2, param3, param4); - return null; + return IntPtr.Zero; } } @@ -564,22 +601,24 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target); - return ret; + return MarshalReturnValue(ref ret); } } @@ -598,7 +637,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -613,10 +653,11 @@ namespace FlaxEngine if (types[0].IsByRef) MarshalHelper.ToNative(ref param1, param1Ptr); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -624,7 +665,7 @@ namespace FlaxEngine TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, param1); - return ret; + return MarshalReturnValue(ref ret); } } @@ -643,7 +684,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -663,10 +705,11 @@ namespace FlaxEngine if (types[1].IsByRef) MarshalHelper.ToNative(ref param2, param2Ptr); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -675,7 +718,7 @@ namespace FlaxEngine TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2); - return ret; + return MarshalReturnValue(ref ret); } } @@ -694,7 +737,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -719,10 +763,11 @@ namespace FlaxEngine if (types[2].IsByRef) MarshalHelper.ToNative(ref param3, param3Ptr); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -732,7 +777,7 @@ namespace FlaxEngine TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2, param3); - return ret; + return MarshalReturnValue(ref ret); } } @@ -751,7 +796,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -781,10 +827,11 @@ namespace FlaxEngine if (types[3].IsByRef) MarshalHelper.ToNative(ref param4, param4Ptr); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -795,7 +842,7 @@ namespace FlaxEngine TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2, param3, param4); - return ret; + return MarshalReturnValue(ref ret); } } @@ -814,22 +861,24 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); TRet ret = deleg(); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); TRet ret = deleg(); - return ret; + return MarshalReturnValue(ref ret); } } @@ -848,7 +897,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -863,10 +913,11 @@ namespace FlaxEngine if (types[0].IsByRef) MarshalHelper.ToNative(ref param1, param1Ptr); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -874,7 +925,7 @@ namespace FlaxEngine TRet ret = deleg(param1); - return ret; + return MarshalReturnValue(ref ret); } } @@ -893,7 +944,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -913,10 +965,11 @@ namespace FlaxEngine if (types[1].IsByRef) MarshalHelper.ToNative(ref param2, param2Ptr); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -925,7 +978,7 @@ namespace FlaxEngine TRet ret = deleg(param1, param2); - return ret; + return MarshalReturnValue(ref ret); } } @@ -944,7 +997,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -969,10 +1023,11 @@ namespace FlaxEngine if (types[2].IsByRef) MarshalHelper.ToNative(ref param3, param3Ptr); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -982,7 +1037,7 @@ namespace FlaxEngine TRet ret = deleg(param1, param2, param3); - return ret; + return MarshalReturnValue(ref ret); } } @@ -1001,7 +1056,8 @@ namespace FlaxEngine return Unsafe.As(CreateDelegateFromMethod(method, false)); } - internal static object MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + [DebuggerStepThrough] + internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -1031,10 +1087,11 @@ namespace FlaxEngine if (types[3].IsByRef) MarshalHelper.ToNative(ref param4, param4Ptr); - return ret; + return MarshalReturnValue(ref ret); } - internal static unsafe object InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + [DebuggerStepThrough] + internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -1045,7 +1102,7 @@ namespace FlaxEngine TRet ret = deleg(param1, param2, param3, param4); - return ret; + return MarshalReturnValue(ref ret); } } } diff --git a/Source/Engine/Renderer/Renderer.cs b/Source/Engine/Renderer/Renderer.cs index 9efe13e75..0fb11af01 100644 --- a/Source/Engine/Renderer/Renderer.cs +++ b/Source/Engine/Renderer/Renderer.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. using System.Collections.Generic; +using System.Runtime.InteropServices; namespace FlaxEngine { @@ -15,7 +16,7 @@ namespace FlaxEngine /// The custom set of actors to render. If empty, the loaded scenes will be rendered. public static void DrawSceneDepth(GPUContext context, SceneRenderTask task, GPUTexture output, List customActors) { - var temp = Utils.ExtractArrayFromList(customActors); + var temp = CollectionsMarshal.AsSpan(customActors).ToArray(); // FIXME var tempCount = temp.Length; Internal_DrawSceneDepth(FlaxEngine.Object.GetUnmanagedPtr(context), FlaxEngine.Object.GetUnmanagedPtr(task), FlaxEngine.Object.GetUnmanagedPtr(output), ref temp, ref tempCount); } diff --git a/Source/Engine/Scripting/DotNet/MonoApi.cpp b/Source/Engine/Scripting/DotNet/MonoApi.cpp index f01fac1d2..d1150daca 100644 --- a/Source/Engine/Scripting/DotNet/MonoApi.cpp +++ b/Source/Engine/Scripting/DotNet/MonoApi.cpp @@ -26,7 +26,7 @@ struct CoreCLRProperty; struct CoreCLRClass; // Structures used to pass information from runtime, must match with the structures in managed side -struct ManagedClass +struct NativeClassDefinitions { void* typeHandle; const char* name; @@ -35,7 +35,7 @@ struct ManagedClass uint32 typeAttributes; }; -struct ClassMethod +struct NativeMethodDefinitions { const char* name; int numParameters; @@ -43,7 +43,7 @@ struct ClassMethod uint32 methodAttributes; }; -struct ClassField +struct NativeFieldDefinitions { const char* name; void* fieldHandle; @@ -51,7 +51,7 @@ struct ClassField uint32 fieldAttributes; }; -struct ClassProperty +struct NativePropertyDefinitions { const char* name; void* getterHandle; @@ -88,9 +88,9 @@ public: _name = name; _fullname = fullname; - ManagedClass* managedClasses; + NativeClassDefinitions* managedClasses; int classCount; - CoreCLR::CallStaticMethod(GetManagedClassesPtr, _assemblyHandle, &managedClasses, &classCount); + CoreCLR::CallStaticMethod(GetManagedClassesPtr, _assemblyHandle, &managedClasses, &classCount); for (int i = 0; i < classCount; i++) { CoreCLRClass* mci = New(managedClasses[i].typeHandle, StringAnsi(managedClasses[i].name), StringAnsi(managedClasses[i].fullname), StringAnsi(managedClasses[i].namespace_), managedClasses[i].typeAttributes, this); @@ -161,6 +161,7 @@ private: Array _properties; bool _cachedInterfaces = false; Array _interfaces; + int _monoType; public: CoreCLRClass(void* typeHandle, StringAnsi name, StringAnsi fullname, StringAnsi namespace_, uint32 typeAttributes, CoreCLRAssembly* image) @@ -233,9 +234,9 @@ public: static void* GetClassMethodsPtr = CoreCLR::GetStaticMethodPointer(TEXT("GetClassMethods")); - ClassMethod* foundMethods; + NativeMethodDefinitions* foundMethods; int numMethods; - CoreCLR::CallStaticMethod(GetClassMethodsPtr, _typeHandle, &foundMethods, &numMethods); + CoreCLR::CallStaticMethod(GetClassMethodsPtr, _typeHandle, &foundMethods, &numMethods); for (int i = 0; i < numMethods; i++) { CoreCLRMethod* method = New(StringAnsi(foundMethods[i].name), foundMethods[i].numParameters, foundMethods[i].handle, foundMethods[i].methodAttributes, this); @@ -256,9 +257,9 @@ public: static void* GetClassFieldsPtr = CoreCLR::GetStaticMethodPointer(TEXT("GetClassFields")); - ClassField* foundFields; + NativeFieldDefinitions* foundFields; int numFields; - CoreCLR::CallStaticMethod(GetClassFieldsPtr, _typeHandle, &foundFields, &numFields); + CoreCLR::CallStaticMethod(GetClassFieldsPtr, _typeHandle, &foundFields, &numFields); for (int i = 0; i < numFields; i++) { CoreCLRField* field = New(StringAnsi(foundFields[i].name), foundFields[i].fieldHandle, foundFields[i].fieldType, foundFields[i].fieldAttributes, this); @@ -279,9 +280,9 @@ public: static void* GetClassPropertiesPtr = CoreCLR::GetStaticMethodPointer(TEXT("GetClassProperties")); - ClassProperty* foundProperties; + NativePropertyDefinitions* foundProperties; int numProperties; - CoreCLR::CallStaticMethod(GetClassPropertiesPtr, _typeHandle, &foundProperties, &numProperties); + CoreCLR::CallStaticMethod(GetClassPropertiesPtr, _typeHandle, &foundProperties, &numProperties); for (int i = 0; i < numProperties; i++) { CoreCLRProperty* prop = New(StringAnsi(foundProperties[i].name), foundProperties[i].getterHandle, foundProperties[i].setterHandle, foundProperties[i].getterFlags, foundProperties[i].setterFlags, this); @@ -339,6 +340,16 @@ public: _cachedInterfaces = true; return _interfaces; } + + int GetMonoType() + { + if (_monoType == 0) + { + static void* GetTypeMonoTypeEnumPtr = CoreCLR::GetStaticMethodPointer(TEXT("GetTypeMonoTypeEnum")); + _monoType = CoreCLR::CallStaticMethod(GetTypeMonoTypeEnumPtr, _typeHandle); + } + return _monoType; + } }; struct CoreCLRMethod @@ -543,7 +554,7 @@ CoreCLRClass* GetOrCreateClass(void* type) { static void* GetManagedClassFromTypePtr = CoreCLR::GetStaticMethodPointer(TEXT("GetManagedClassFromType")); - ManagedClass classInfo; + NativeClassDefinitions classInfo; void* assemblyHandle; CoreCLR::CallStaticMethod(GetManagedClassFromTypePtr, type, &classInfo, &assemblyHandle); CoreCLRAssembly* image = GetAssembly(assemblyHandle); @@ -1450,8 +1461,8 @@ MONO_API mono_bool mono_type_is_byref(MonoType* type) MONO_API int mono_type_get_type(MonoType* type) { - static void* GetTypeMonoTypeEnumPtr = CoreCLR::GetStaticMethodPointer(TEXT("GetTypeMonoTypeEnum")); - return CoreCLR::CallStaticMethod(GetTypeMonoTypeEnumPtr, type); + CoreCLRClass* klass = GetOrCreateClass((void*)type); + return klass->GetMonoType(); } MONO_API MonoClass* mono_type_get_class(MonoType* type) diff --git a/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs b/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs index c65b7caf0..b3c19365f 100644 --- a/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs +++ b/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. using System.Collections.Generic; +using System.Runtime.InteropServices; using FlaxEngine.Utilities; namespace FlaxEngine.GUI @@ -224,7 +225,7 @@ namespace FlaxEngine.GUI private void OnLineAdded(ref ParsingContext context, int lineEnd) { // Calculate size of the line - var textBlocks = Utils.ExtractArrayFromList(_textBlocks); + var textBlocks = CollectionsMarshal.AsSpan(_textBlocks); var lineOrigin = textBlocks[context.LineStartTextBlockIndex].Bounds.Location; var lineSize = Float2.Zero; var lineAscender = 0.0f; diff --git a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs index 4f9e20d5d..9d98de6ce 100644 --- a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; namespace FlaxEngine.GUI { @@ -44,7 +45,7 @@ namespace FlaxEngine.GUI /// True if got text block, otherwise false. public bool GetTextBlock(int index, out TextBlock result) { - var textBlocks = Utils.ExtractArrayFromList(_textBlocks); + var textBlocks = CollectionsMarshal.AsSpan(_textBlocks); var count = _textBlocks.Count; for (int i = 0; i < count; i++) { @@ -95,7 +96,7 @@ namespace FlaxEngine.GUI public override Float2 GetTextSize() { var count = _textBlocks.Count; - var textBlocks = Utils.ExtractArrayFromList(_textBlocks); + var textBlocks = CollectionsMarshal.AsSpan(_textBlocks); var max = Float2.Zero; for (int i = 0; i < count; i++) { @@ -109,7 +110,7 @@ namespace FlaxEngine.GUI public override Float2 GetCharPosition(int index, out float height) { var count = _textBlocks.Count; - var textBlocks = Utils.ExtractArrayFromList(_textBlocks); + var textBlocks = CollectionsMarshal.AsSpan(_textBlocks); // Check if text is empty if (count == 0) @@ -181,7 +182,7 @@ namespace FlaxEngine.GUI { location = Float2.Clamp(location, Float2.Zero, _textSize); - var textBlocks = Utils.ExtractArrayFromList(_textBlocks); + var textBlocks = CollectionsMarshal.AsSpan(_textBlocks); var count = _textBlocks.Count; for (int i = 0; i < count; i++) { @@ -242,7 +243,7 @@ namespace FlaxEngine.GUI Render2D.PushTransform(Matrix3x3.Translation2D(-_viewOffset)); // Calculate text blocks for drawing - var textBlocks = Utils.ExtractArrayFromList(_textBlocks); + var textBlocks = CollectionsMarshal.AsSpan(_textBlocks); var textBlocksCount = _textBlocks?.Count ?? 0; var hasSelection = HasSelection; var selection = new TextRange(SelectionLeft, SelectionRight); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index 9103f82a4..890f0524b 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -1499,25 +1499,25 @@ namespace Flax.Build.Bindings string originalElementTypeMarshaller = originalElementType + "Marshaller"; string internalElementType = $"{originalElementTypeMarshaller}.{originalElementType}Internal"; toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.NativeArrayToManagedArray<{originalElementType}, {internalElementType}>(((ManagedArray)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target).GetSpan<{internalElementType}>(), {originalElementTypeMarshaller}.ToManaged) : null"); - toNativeContent.Append($"GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(managed.{fieldInfo.Name}), GCHandleType.Weak))"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = ((ManagedArray)handle.Target).GetSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} ((ManagedArray)handle.Target).Release(); handle.Free(); }}"); - freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = ((ManagedArray)handle.Target).GetSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} ((ManagedArray)handle.Target).Release(); handle.Free(); }}"); + toNativeContent.Append($"GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak))"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = ((ManagedArray)handle.Target).GetSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = ((ManagedArray)handle.Target).GetSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); } else if (fieldInfo.Type.GenericArgs[0].IsObjectRef) { // Array elements passed as GCHandles toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>((ManagedArray)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null"); - toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(NativeInterop.ManagedArrayToGCHandleArray(managed.{fieldInfo.Name})), GCHandleType.Weak)) : IntPtr.Zero"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = ((ManagedArray)handle.Target).GetSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ GCHandle.FromIntPtr(ptr).Free(); }} }} ((ManagedArray)handle.Target).Release(); handle.Free(); }}"); - freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = ((ManagedArray)handle.Target).GetSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ GCHandle.FromIntPtr(ptr).Free(); }} }} ((ManagedArray)handle.Target).Release(); handle.Free(); }}"); + toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.{fieldInfo.Name})), GCHandleType.Weak)) : IntPtr.Zero"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = ((ManagedArray)handle.Target).GetSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ GCHandle.FromIntPtr(ptr).Free(); }} }} ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = ((ManagedArray)handle.Target).GetSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ GCHandle.FromIntPtr(ptr).Free(); }} }} ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); } else { // Blittable array elements toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ((ManagedArray)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target).GetArray<{originalElementType}>() : null"); - toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(managed.{fieldInfo.Name}), GCHandleType.Weak)) : IntPtr.Zero"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); ((ManagedArray)handle.Target).Release(); handle.Free(); }}"); - freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); ((ManagedArray)handle.Target).Release(); handle.Free(); }}"); + toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak)) : IntPtr.Zero"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); } } else if (fieldInfo.Type.Type == "Version")