From 8b80f736419fcfe38c815889ae3d2aa9eddaa7f9 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 30 Dec 2022 22:09:53 +0200 Subject: [PATCH 1/4] Implement ManagedHandle replacement for GCHandles Allows for more controlled management of weak handles, increasing their lifetime for slightly longer than with GCHandles. --- .../Content/Import/TextureImportEntry.cs | 4 +- Source/Engine/Animations/AnimationGraph.cs | 2 +- Source/Engine/Engine/NativeInterop.cs | 701 +++++++++++------- Source/Engine/Engine/NativeInterop_Invoker.cs | 212 +++--- Source/Engine/Scripting/Scripting.cs | 8 +- .../Bindings/BindingsGenerator.CSharp.cs | 94 +-- 6 files changed, 608 insertions(+), 413 deletions(-) diff --git a/Source/Editor/Content/Import/TextureImportEntry.cs b/Source/Editor/Content/Import/TextureImportEntry.cs index 7ea0157fe..a20c3d0ca 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.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteAreas)))) : IntPtr.Zero, - SpriteNames = managed.SpriteNames?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteNames)))) : IntPtr.Zero, + SpriteAreas = managed.SpriteAreas?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteAreas)))) : IntPtr.Zero, + SpriteNames = managed.SpriteNames?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteNames)))) : IntPtr.Zero, }; } internal static void Free(InternalOptionsNative unmanaged) diff --git a/Source/Engine/Animations/AnimationGraph.cs b/Source/Engine/Animations/AnimationGraph.cs index 4bebecab0..40b1f202f 100644 --- a/Source/Engine/Animations/AnimationGraph.cs +++ b/Source/Engine/Animations/AnimationGraph.cs @@ -265,7 +265,7 @@ namespace FlaxEngine internal static partial bool Internal_HasConnection(ref AnimationGraph.CustomNode.Context context, int boxId); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetInputValue")] - [return: MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))] + [return: MarshalUsing(typeof(FlaxEngine.ManagedHandleMarshaller))] internal static partial object Internal_GetInputValue(ref AnimationGraph.CustomNode.Context context, int boxId); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData")] diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index b23170a26..9efbcaabe 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -16,6 +16,7 @@ using FlaxEngine.Visject; using System.Buffers; using System.Collections.Concurrent; using System.Text; +using System.Threading; #pragma warning disable 1591 @@ -26,7 +27,7 @@ namespace FlaxEngine [StructLayout(LayoutKind.Sequential)] internal struct NativeClassDefinitions { - internal IntPtr typeHandle; + internal ManagedHandle typeHandle; internal IntPtr name; internal IntPtr fullname; internal IntPtr @namespace; @@ -38,7 +39,7 @@ namespace FlaxEngine { internal IntPtr name; internal int numParameters; - internal IntPtr typeHandle; + internal ManagedHandle typeHandle; internal uint methodAttributes; } @@ -46,8 +47,8 @@ namespace FlaxEngine internal struct NativeFieldDefinitions { internal IntPtr name; - internal IntPtr fieldHandle; - internal IntPtr fieldTypeHandle; + internal ManagedHandle fieldHandle; + internal ManagedHandle fieldTypeHandle; internal uint fieldAttributes; } @@ -55,8 +56,8 @@ namespace FlaxEngine internal struct NativePropertyDefinitions { internal IntPtr name; - internal IntPtr getterHandle; - internal IntPtr setterHandle; + internal ManagedHandle getterHandle; + internal ManagedHandle setterHandle; internal uint getterFlags; internal uint setterFlags; } @@ -65,8 +66,8 @@ namespace FlaxEngine internal struct NativeAttributeDefinitions { internal IntPtr name; - internal IntPtr attributeHandle; - internal IntPtr attributeTypeHandle; + internal ManagedHandle attributeHandle; + internal ManagedHandle attributeTypeHandle; } [StructLayout(LayoutKind.Explicit)] @@ -162,7 +163,7 @@ namespace FlaxEngine /// internal unsafe class ManagedArray { - private GCHandle pinnedArrayHandle; + private ManagedHandle pinnedArrayHandle; private IntPtr unmanagedData; private int elementSize; private int length; @@ -218,7 +219,7 @@ namespace FlaxEngine internal void WrapArray(Array arr) { - pinnedArrayHandle = GCHandle.Alloc(arr, GCHandleType.Pinned); + pinnedArrayHandle = ManagedHandle.Alloc(arr, GCHandleType.Pinned); unmanagedData = Marshal.UnsafeAddrOfPinnedArrayElement(arr, 0); length = arr.Length; elementSize = Marshal.SizeOf(arr.GetType().GetElementType()); @@ -324,7 +325,7 @@ namespace FlaxEngine internal static class ManagedString { - internal static GCHandle EmptyStringHandle = GCHandle.Alloc(string.Empty); + internal static ManagedHandle EmptyStringHandle = ManagedHandle.Alloc(string.Empty); [System.Diagnostics.DebuggerStepThrough] internal static unsafe IntPtr ToNative(string str) @@ -332,9 +333,9 @@ namespace FlaxEngine if (str == null) return IntPtr.Zero; else if (str == string.Empty) - return GCHandle.ToIntPtr(EmptyStringHandle); + return ManagedHandle.ToIntPtr(EmptyStringHandle); Assert.IsTrue(str.Length > 0); - return GCHandle.ToIntPtr(GCHandle.Alloc(str, GCHandleType.Weak)); + return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(str, GCHandleType.Weak)); } [System.Diagnostics.DebuggerStepThrough] @@ -342,7 +343,7 @@ namespace FlaxEngine { if (ptr == IntPtr.Zero) return null; - return Unsafe.As(GCHandle.FromIntPtr(ptr).Target); + return Unsafe.As(ManagedHandle.FromIntPtr(ptr).Target); } [System.Diagnostics.DebuggerStepThrough] @@ -350,31 +351,227 @@ namespace FlaxEngine { if (ptr == IntPtr.Zero) return; - GCHandle handle = GCHandle.FromIntPtr(ptr); + ManagedHandle handle = ManagedHandle.FromIntPtr(ptr); if (handle == EmptyStringHandle) return; handle.Free(); } } + /// + /// Handle to managed objects which can be stored in native code. + /// + public struct ManagedHandle + { + private IntPtr handle; + + private ManagedHandle(IntPtr handle) + { + this.handle = handle; + } + + private ManagedHandle(object value, GCHandleType type) + { + handle = ManagedHandlePool.AllocateHandle(value, type); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedHandle Alloc(object value) => new ManagedHandle(value, GCHandleType.Normal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedHandle Alloc(object value, GCHandleType type) => new ManagedHandle(value, type); + + public void Free() + { + if (handle != IntPtr.Zero) + { + ManagedHandlePool.FreeHandle(handle); + handle = IntPtr.Zero; + } + + ManagedHandlePool.TryCollectWeakHandles(); + } + + public object Target + { + get => ManagedHandlePool.GetObject(handle); + set => ManagedHandlePool.SetObject(handle, value); + } + + public bool IsAllocated => handle != IntPtr.Zero; + + public static explicit operator ManagedHandle(IntPtr value) => FromIntPtr(value); + + public static ManagedHandle FromIntPtr(IntPtr value) => new ManagedHandle(value); + + public static explicit operator IntPtr(ManagedHandle value) => ToIntPtr(value); + + public static IntPtr ToIntPtr(ManagedHandle value) => value.handle; + + public override int GetHashCode() => handle.GetHashCode(); + + public override bool Equals(object o) => o is ManagedHandle other && Equals(other); + + public bool Equals(ManagedHandle other) => handle == other.handle; + + public static bool operator ==(ManagedHandle a, ManagedHandle b) => a.handle == b.handle; + + public static bool operator !=(ManagedHandle a, ManagedHandle b) => a.handle != b.handle; + + private static class ManagedHandlePool + { + private static ulong normalHandleAccumulator = 0; + private static ulong pinnedHandleAccumulator = 0; + private static ulong weakHandleAccumulator = 0; + + private static object poolLock = new object(); + private static Dictionary persistentPool = new Dictionary(); + private static Dictionary pinnedPool = new Dictionary(); + + private static Dictionary weakPool1 = new Dictionary(); + private static Dictionary weakPool2 = new Dictionary(); + private static Dictionary weakPool = weakPool1; + private static Dictionary weakPoolOther = weakPool2; + + private static int nextCollection = GC.CollectionCount(0) + 2; + + /// + /// Tries to free all references to old weak handles so GC can collect them. + /// + internal static void TryCollectWeakHandles() + { + if (GC.CollectionCount(0) < nextCollection) + return; + + lock (poolLock) + { + // During initialization we might want to skip + // few generations between collections due to high GC pressure. + nextCollection = GC.CollectionCount(0) + 2; + + var swap = weakPoolOther; + weakPoolOther = weakPool; + weakPool = swap; + + weakPoolOther.Clear(); + } + } + + private static IntPtr NewHandle(GCHandleType type) + { + IntPtr handle; + if (type == GCHandleType.Normal) + handle = (IntPtr)Interlocked.Increment(ref normalHandleAccumulator); + else if (type == GCHandleType.Pinned) + handle = (IntPtr)Interlocked.Increment(ref pinnedHandleAccumulator); + else //if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection) + handle = (IntPtr)Interlocked.Increment(ref weakHandleAccumulator); + + // Two bits reserved for the type + handle |= (IntPtr)(((ulong)type << 62) & 0xC000000000000000); + return handle; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static GCHandleType GetHandleType(IntPtr handle) + { + return (GCHandleType)(((ulong)handle & 0xC000000000000000) >> 62); + } + + internal static IntPtr AllocateHandle(object value, GCHandleType type) + { + IntPtr handle = NewHandle(type); + lock (poolLock) + { + if (type == GCHandleType.Normal) + persistentPool.Add(handle, value); + else if (type == GCHandleType.Pinned) + pinnedPool.Add(handle, GCHandle.Alloc(value, GCHandleType.Pinned)); + else if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection) + weakPool.Add(handle, value); + } + + return handle; + } + + internal static object GetObject(IntPtr handle) + { + object value; + GCHandleType type = GetHandleType(handle); + lock (poolLock) + { + if (type == GCHandleType.Normal && persistentPool.TryGetValue(handle, out value)) + return value; + else if (type == GCHandleType.Pinned && pinnedPool.TryGetValue(handle, out GCHandle gchandle)) + return gchandle.Target; + else if (weakPool.TryGetValue(handle, out value)) + return value; + else if (weakPoolOther.TryGetValue(handle, out value)) + return value; + } + + throw new Exception("Invalid ManagedHandle"); + } + + internal static void SetObject(IntPtr handle, object value) + { + GCHandleType type = GetHandleType(handle); + lock (poolLock) + { + if (type == GCHandleType.Normal && persistentPool.ContainsKey(handle)) + persistentPool[handle] = value; + else if (type == GCHandleType.Pinned && pinnedPool.TryGetValue(handle, out GCHandle gchandle)) + gchandle.Target = value; + else if (weakPool.ContainsKey(handle)) + weakPool[handle] = value; + else if (weakPoolOther.ContainsKey(handle)) + weakPoolOther[handle] = value; + else + throw new Exception("Invalid ManagedHandle"); + } + } + + internal static void FreeHandle(IntPtr handle) + { + GCHandleType type = GetHandleType(handle); + lock (poolLock) + { + if (type == GCHandleType.Normal && persistentPool.Remove(handle)) + return; + else if (type == GCHandleType.Pinned && pinnedPool.Remove(handle, out GCHandle gchandle)) + { + gchandle.Free(); + return; + } + else if (weakPool.Remove(handle)) + return; + else if (weakPoolOther.Remove(handle)) + return; + } + + throw new Exception("Invalid ManagedHandle"); + } + } + } + #endregion #region Marshallers - [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedIn, typeof(GCHandleMarshaller.ManagedToNative))] - [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedOut, typeof(GCHandleMarshaller.ManagedToNative))] - [CustomMarshaller(typeof(object), MarshalMode.ElementIn, typeof(GCHandleMarshaller.ManagedToNative))] - [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedOut, typeof(GCHandleMarshaller.NativeToManaged))] - [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedIn, typeof(GCHandleMarshaller.NativeToManaged))] - [CustomMarshaller(typeof(object), MarshalMode.ElementOut, typeof(GCHandleMarshaller.NativeToManaged))] - [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedRef, typeof(GCHandleMarshaller.Bidirectional))] - [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(GCHandleMarshaller.Bidirectional))] - [CustomMarshaller(typeof(object), MarshalMode.ElementRef, typeof(GCHandleMarshaller))] - public static class GCHandleMarshaller + [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedHandleMarshaller.ManagedToNative))] + [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedOut, typeof(ManagedHandleMarshaller.ManagedToNative))] + [CustomMarshaller(typeof(object), MarshalMode.ElementIn, typeof(ManagedHandleMarshaller.ManagedToNative))] + [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedOut, typeof(ManagedHandleMarshaller.NativeToManaged))] + [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedIn, typeof(ManagedHandleMarshaller.NativeToManaged))] + [CustomMarshaller(typeof(object), MarshalMode.ElementOut, typeof(ManagedHandleMarshaller.NativeToManaged))] + [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedRef, typeof(ManagedHandleMarshaller.Bidirectional))] + [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(ManagedHandleMarshaller.Bidirectional))] + [CustomMarshaller(typeof(object), MarshalMode.ElementRef, typeof(ManagedHandleMarshaller))] + public static class ManagedHandleMarshaller { public static class NativeToManaged { - public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : GCHandle.FromIntPtr(unmanaged).Target; + public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target; public static void Free(IntPtr unmanaged) { // This is a permanent handle, do not release it @@ -382,12 +579,12 @@ namespace FlaxEngine } public static class ManagedToNative { - public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero; + public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero; public static void Free(IntPtr unmanaged) { if (unmanaged == IntPtr.Zero) return; - GCHandle.FromIntPtr(unmanaged).Free(); + ManagedHandle.FromIntPtr(unmanaged).Free(); } } public struct Bidirectional @@ -395,41 +592,41 @@ namespace FlaxEngine object managed; IntPtr unmanaged; public void FromManaged(object managed) { this.managed = managed; } - public IntPtr ToUnmanaged() { unmanaged = GCHandleMarshaller.ToNative(managed); return unmanaged; } + public IntPtr ToUnmanaged() { unmanaged = ManagedHandleMarshaller.ToNative(managed); return unmanaged; } public void FromUnmanaged(IntPtr unmanaged) { this.unmanaged = unmanaged; } - public object ToManaged() { managed = GCHandleMarshaller.ToManaged(unmanaged); unmanaged = IntPtr.Zero; return managed; } + public object ToManaged() { managed = ManagedHandleMarshaller.ToManaged(unmanaged); unmanaged = IntPtr.Zero; return managed; } public void Free() { // FIXME, might be a permanent handle or a temporary one throw new NotImplementedException(); /*if (unmanaged == IntPtr.Zero) return; - GCHandle.FromIntPtr(unmanaged).Free();*/ + unmanaged.Free();*/ } } public static object ConvertToManaged(IntPtr unmanaged) => ToManaged(unmanaged); public static IntPtr ConvertToUnmanaged(object managed) => ToNative(managed); - public static object ToManaged(IntPtr managed) => managed != IntPtr.Zero ? GCHandle.FromIntPtr(managed).Target : null; - public static IntPtr ToNative(object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero; + public static object ToManaged(IntPtr managed) => managed != IntPtr.Zero ? ManagedHandle.FromIntPtr(managed).Target : null; + public static IntPtr ToNative(object managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero; public static void Free(IntPtr unmanaged) { if (unmanaged == IntPtr.Zero) return; - GCHandle.FromIntPtr(unmanaged).Free(); + ManagedHandle.FromIntPtr(unmanaged).Free(); } } [CustomMarshaller(typeof(Type), MarshalMode.Default, typeof(SystemTypeMarshaller))] public static class SystemTypeMarshaller { - public static Type ConvertToManaged(IntPtr unmanaged) => Unsafe.As(GCHandleMarshaller.ConvertToManaged(unmanaged)); + public static Type ConvertToManaged(IntPtr unmanaged) => Unsafe.As(ManagedHandleMarshaller.ConvertToManaged(unmanaged)); public static IntPtr ConvertToUnmanaged(Type managed) { if (managed == null) return IntPtr.Zero; - GCHandle handle = NativeInterop.GetTypeGCHandle(managed); - return GCHandle.ToIntPtr(handle); + ManagedHandle handle = NativeInterop.GetTypeGCHandle(managed); + return ManagedHandle.ToIntPtr(handle); } public static void Free(IntPtr unmanaged) @@ -441,9 +638,9 @@ namespace FlaxEngine [CustomMarshaller(typeof(Exception), MarshalMode.Default, typeof(ExceptionMarshaller))] public static class ExceptionMarshaller { - public static Exception ConvertToManaged(IntPtr unmanaged) => Unsafe.As(GCHandleMarshaller.ConvertToManaged(unmanaged)); - public static IntPtr ConvertToUnmanaged(Exception managed) => GCHandleMarshaller.ConvertToUnmanaged(managed); - public static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged); + public static Exception ConvertToManaged(IntPtr unmanaged) => Unsafe.As(ManagedHandleMarshaller.ConvertToManaged(unmanaged)); + public static IntPtr ConvertToUnmanaged(Exception managed) => ManagedHandleMarshaller.ConvertToUnmanaged(managed); + public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.Free(unmanaged); } [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller.ManagedToNative))] @@ -456,20 +653,20 @@ namespace FlaxEngine { public static class NativeToManaged { - public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As(GCHandle.FromIntPtr(unmanaged).Target) : null; + public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(unmanaged).Target) : null; } public static class ManagedToNative { - public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero; + public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero; } } [CustomMarshaller(typeof(CultureInfo), MarshalMode.Default, typeof(CultureInfoMarshaller))] public static class CultureInfoMarshaller { - public static CultureInfo ConvertToManaged(IntPtr unmanaged) => Unsafe.As(GCHandleMarshaller.ConvertToManaged(unmanaged)); - public static IntPtr ConvertToUnmanaged(CultureInfo managed) => GCHandleMarshaller.ConvertToUnmanaged(managed); - public static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged); + public static CultureInfo ConvertToManaged(IntPtr unmanaged) => Unsafe.As(ManagedHandleMarshaller.ConvertToManaged(unmanaged)); + public static IntPtr ConvertToUnmanaged(CultureInfo managed) => ManagedHandleMarshaller.ConvertToUnmanaged(managed); + public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.Free(unmanaged); } [CustomMarshaller(typeof(Array), MarshalMode.ManagedToUnmanagedIn, typeof(SystemArrayMarshaller.ManagedToNative))] @@ -479,7 +676,7 @@ namespace FlaxEngine public struct ManagedToNative { ManagedArray managedArray; - GCHandle handle; + ManagedHandle handle; public void FromManaged(Array managed) { @@ -491,8 +688,8 @@ namespace FlaxEngine { if (managedArray == null) return IntPtr.Zero; - handle = GCHandle.Alloc(managedArray); - return GCHandle.ToIntPtr(handle); + handle = ManagedHandle.Alloc(managedArray); + return ManagedHandle.ToIntPtr(handle); } public void Free() @@ -553,15 +750,15 @@ namespace FlaxEngine public void Free() => DictionaryMarshaller.Free(unmanaged); } - public static Dictionary ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As>(GCHandle.FromIntPtr(unmanaged).Target) : null; - public static IntPtr ConvertToUnmanaged(Dictionary managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero; + public static Dictionary ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As>(ManagedHandle.FromIntPtr(unmanaged).Target) : null; + public static IntPtr ConvertToUnmanaged(Dictionary managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero; - public static Dictionary ToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As>(GCHandle.FromIntPtr(unmanaged).Target) : null; - public static IntPtr ToNative(Dictionary managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero; + public static Dictionary ToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As>(ManagedHandle.FromIntPtr(unmanaged).Target) : null; + public static IntPtr ToNative(Dictionary managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero; public static void Free(IntPtr unmanaged) { if (unmanaged != IntPtr.Zero) - GCHandle.FromIntPtr(unmanaged).Free(); + ManagedHandle.FromIntPtr(unmanaged).Free(); } } @@ -592,7 +789,7 @@ namespace FlaxEngine { if (unmanaged == null) return ReadOnlySpan.Empty; - ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target); + ManagedArray managedArray = Unsafe.As(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target); return managedArray.GetSpan(); } @@ -600,7 +797,7 @@ namespace FlaxEngine { if (unmanaged == null) return; - GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged)); + ManagedHandle handle = ManagedHandle.FromIntPtr(new IntPtr(unmanaged)); (Unsafe.As(handle.Target)).Free(); handle.Free(); } @@ -609,7 +806,7 @@ namespace FlaxEngine { if (unmanaged == null) return Span.Empty; - ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target); + ManagedArray managedArray = Unsafe.As(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target); return managedArray.GetSpan(); } } @@ -625,7 +822,7 @@ namespace FlaxEngine } numElements = managed.Length; ManagedArray managedArray = ManagedArray.AllocatePooledArray(managed.Length); - var ptr = GCHandle.ToIntPtr(GCHandle.Alloc(managedArray)); + var ptr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedArray)); return (TUnmanagedElement*)ptr; } @@ -635,7 +832,7 @@ namespace FlaxEngine { if (unmanaged == null) return Span.Empty; - ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target); + ManagedArray managedArray = Unsafe.As(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target); return managedArray.GetSpan(); } @@ -643,7 +840,7 @@ namespace FlaxEngine { if (unmanaged == null) return; - GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged)); + ManagedHandle handle = ManagedHandle.FromIntPtr(new IntPtr(unmanaged)); (Unsafe.As(handle.Target)).FreePooled(); handle.Free(); } @@ -653,7 +850,7 @@ namespace FlaxEngine { T[] managedArray; ManagedArray unmanagedArray; - GCHandle handle; + ManagedHandle handle; public void FromManaged(T[]? managed) { @@ -661,7 +858,7 @@ namespace FlaxEngine return; managedArray = managed; unmanagedArray = ManagedArray.AllocatePooledArray(managed.Length); - handle = GCHandle.Alloc(unmanagedArray); + handle = ManagedHandle.Alloc(unmanagedArray); } public ReadOnlySpan GetManagedValuesSource() => managedArray; @@ -673,11 +870,11 @@ namespace FlaxEngine return unmanagedArray.GetSpan(); } - public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)GCHandle.ToIntPtr(handle); + public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)ManagedHandle.ToIntPtr(handle); public void FromUnmanaged(TUnmanagedElement* unmanaged) { - ManagedArray arr = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target); + ManagedArray arr = Unsafe.As(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target); if (managedArray == null || managedArray.Length != arr.Length) managedArray = new T[arr.Length]; } @@ -709,7 +906,7 @@ namespace FlaxEngine } numElements = managed.Length; ManagedArray managedArray = ManagedArray.AllocatePooledArray(managed.Length); - IntPtr handle = GCHandle.ToIntPtr(GCHandle.Alloc(managedArray)); + IntPtr handle = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedArray)); return (TUnmanagedElement*)handle; } @@ -719,7 +916,7 @@ namespace FlaxEngine { if (unmanaged == null) return Span.Empty; - ManagedArray unmanagedArray = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target); + ManagedArray unmanagedArray = Unsafe.As(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target); return unmanagedArray.GetSpan(); } @@ -731,7 +928,7 @@ namespace FlaxEngine { if (unmanaged == null) return ReadOnlySpan.Empty; - ManagedArray array = Unsafe.As(GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target); + ManagedArray array = Unsafe.As(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target); return array.GetSpan(); } @@ -739,7 +936,7 @@ namespace FlaxEngine { if (unmanaged == null) return; - GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged)); + ManagedHandle handle = ManagedHandle.FromIntPtr(new IntPtr(unmanaged)); Unsafe.As(handle.Target).FreePooled(); handle.Free(); } @@ -768,7 +965,7 @@ namespace FlaxEngine { if (managed == null) return IntPtr.Zero; - return GCHandle.ToIntPtr(GCHandle.Alloc(managed, GCHandleType.Weak)); + return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed, GCHandleType.Weak)); } public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged); @@ -820,19 +1017,19 @@ namespace FlaxEngine private static Dictionary typeCache = new Dictionary(); - private static IntPtr boolTruePtr = GCHandle.ToIntPtr(GCHandle.Alloc((int)1, GCHandleType.Pinned)); - private static IntPtr boolFalsePtr = GCHandle.ToIntPtr(GCHandle.Alloc((int)0, GCHandleType.Pinned)); + private static IntPtr boolTruePtr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc((int)1, GCHandleType.Pinned)); + private static IntPtr boolFalsePtr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc((int)0, GCHandleType.Pinned)); - private static List methodHandles = new(); - private static List methodHandlesCollectible = new(); + private static List methodHandles = new(); + private static List methodHandlesCollectible = new(); private static ConcurrentDictionary cachedDelegates = new ConcurrentDictionary(); private static ConcurrentDictionary cachedDelegatesCollectible = new ConcurrentDictionary(); - private static Dictionary typeHandleCache = new Dictionary(); - private static Dictionary typeHandleCacheCollectible = new Dictionary(); - private static List fieldHandleCache = new(); - private static List fieldHandleCacheCollectible = new(); - private static Dictionary classAttributesCacheCollectible = new(); - private static Dictionary assemblyHandles = new Dictionary(); + private static Dictionary typeHandleCache = new Dictionary(); + private static Dictionary typeHandleCacheCollectible = new Dictionary(); + private static List fieldHandleCache = new(); + private static List fieldHandleCacheCollectible = new(); + private static Dictionary classAttributesCacheCollectible = new(); + private static Dictionary assemblyHandles = new Dictionary(); private static Dictionary loadedNativeLibraries = new Dictionary(); private static Dictionary nativeLibraryPaths = new Dictionary(); @@ -919,7 +1116,7 @@ namespace FlaxEngine Span span = ptrArray.GetSpan(); T[] managedArray = new T[ptrArray.Length]; for (int i = 0; i < managedArray.Length; i++) - managedArray[i] = span[i] != IntPtr.Zero ? (T)GCHandle.FromIntPtr(span[i]).Target : default; + managedArray[i] = span[i] != IntPtr.Zero ? (T)ManagedHandle.FromIntPtr(span[i]).Target : default; return managedArray; } @@ -930,7 +1127,7 @@ namespace FlaxEngine { var obj = array.GetValue(i); if (obj != null) - pointerArray.SetValue(GCHandle.ToIntPtr(GCHandle.Alloc(obj)), i); + pointerArray.SetValue(ManagedHandle.ToIntPtr(ManagedHandle.Alloc(obj)), i); } return pointerArray; } @@ -1032,7 +1229,7 @@ namespace FlaxEngine internal class ReferenceTypePlaceholder { } internal struct ValueTypePlaceholder { } - + internal delegate object MarshalToManagedDelegate(IntPtr nativePtr, bool byRef); internal delegate void MarshalToNativeDelegate(object managedObject, IntPtr nativePtr); internal delegate void MarshalToNativeFieldDelegate(FieldInfo field, object fieldOwner, IntPtr nativePtr, out int fieldOffset); @@ -1119,7 +1316,7 @@ namespace FlaxEngine static MarshalHelper() { Type type = typeof(T); - + // Setup marshallers for managed and native directions MethodInfo toManagedMethod; if (type.IsValueType) @@ -1407,7 +1604,7 @@ namespace FlaxEngine Type elementType = typeof(T); if (nativePtr != IntPtr.Zero) { - ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(nativePtr).Target); + ManagedArray managedArray = Unsafe.As(ManagedHandle.FromIntPtr(nativePtr).Target); if (ArrayFactory.GetMarshalledType(elementType) == elementType) managedValue = Unsafe.As(managedArray.GetArray()); else @@ -1460,9 +1657,9 @@ namespace FlaxEngine if (type == typeof(string)) managedValue = Unsafe.As(ManagedString.ToManaged(nativePtr)); else if (type.IsClass) - managedValue = nativePtr != IntPtr.Zero ? Unsafe.As(GCHandle.FromIntPtr(nativePtr).Target) : null; + managedValue = nativePtr != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(nativePtr).Target) : null; else if (type.IsInterface) // Dictionary - managedValue = nativePtr != IntPtr.Zero ? Unsafe.As(GCHandle.FromIntPtr(nativePtr).Target) : null; + managedValue = nativePtr != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(nativePtr).Target) : null; else throw new NotImplementedException(); } @@ -1474,7 +1671,7 @@ namespace FlaxEngine Type elementType = typeof(T); if (nativePtr != IntPtr.Zero) { - ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(nativePtr).Target); + ManagedArray managedArray = Unsafe.As(ManagedHandle.FromIntPtr(nativePtr).Target); managedValue = Unsafe.As(MarshalHelper.ToManagedArray(managedArray.GetSpan())); } else @@ -1495,10 +1692,10 @@ namespace FlaxEngine else if (managedValue is FlaxEngine.Object flaxObj) managedPtr = FlaxEngine.Object.GetUnmanagedPtr(flaxObj); else - managedPtr = GCHandle.ToIntPtr(GCHandle.Alloc(managedValue, GCHandleType.Weak)); + managedPtr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedValue, GCHandleType.Weak)); } else if (type == typeof(Type)) - managedPtr = managedValue != null ? GCHandle.ToIntPtr(GetTypeGCHandle((Type)(object)managedValue)) : IntPtr.Zero; + managedPtr = managedValue != null ? ManagedHandle.ToIntPtr(GetTypeGCHandle((Type)(object)managedValue)) : IntPtr.Zero; else if (type.IsArray) { if (managedValue == null) @@ -1507,13 +1704,13 @@ namespace FlaxEngine { var elementType = type.GetElementType(); if (ArrayFactory.GetMarshalledType(elementType) == elementType) - managedPtr = GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As(managedValue)), GCHandleType.Weak)); + managedPtr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As(managedValue)), GCHandleType.Weak)); else - managedPtr = GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(managedValue))), GCHandleType.Weak)); + managedPtr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(managedValue))), GCHandleType.Weak)); } } else - managedPtr = managedValue != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managedValue, GCHandleType.Weak)) : IntPtr.Zero; + managedPtr = managedValue != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedValue, GCHandleType.Weak)) : IntPtr.Zero; Unsafe.Write(nativePtr.ToPointer(), managedPtr); } @@ -1567,10 +1764,10 @@ namespace FlaxEngine } } - internal static GCHandle GetMethodGCHandle(MethodInfo method) + internal static ManagedHandle GetMethodGCHandle(MethodInfo method) { MethodHolder methodHolder = new MethodHolder(method); - GCHandle handle = GCHandle.Alloc(methodHolder); + ManagedHandle handle = ManagedHandle.Alloc(methodHolder); if (methodHolder.parameterTypes.Any(x => x.IsCollectible) || method.IsCollectible) methodHandlesCollectible.Add(handle); else @@ -1578,20 +1775,20 @@ namespace FlaxEngine return handle; } - internal static GCHandle GetAssemblyHandle(Assembly assembly) + internal static ManagedHandle GetAssemblyHandle(Assembly assembly) { - if (!assemblyHandles.TryGetValue(assembly, out GCHandle handle)) + if (!assemblyHandles.TryGetValue(assembly, out ManagedHandle handle)) { - handle = GCHandle.Alloc(assembly); + handle = ManagedHandle.Alloc(assembly); assemblyHandles.Add(assembly, handle); } return handle; } [UnmanagedCallersOnly] - internal static unsafe void GetManagedClasses(IntPtr assemblyHandle, NativeClassDefinitions** managedClasses, int* managedClassCount) + internal static unsafe void GetManagedClasses(ManagedHandle assemblyHandle, NativeClassDefinitions** managedClasses, int* managedClassCount) { - Assembly assembly = Unsafe.As(GCHandle.FromIntPtr(assemblyHandle).Target); + Assembly assembly = Unsafe.As(assemblyHandle.Target); var assemblyTypes = GetAssemblyTypes(assembly); NativeClassDefinitions* arr = (NativeClassDefinitions*)NativeAlloc(assemblyTypes.Length, Unsafe.SizeOf()); @@ -1604,11 +1801,11 @@ namespace FlaxEngine bool isInterface = type.IsInterface; bool isAbstract = type.IsAbstract; - GCHandle typeHandle = GetTypeGCHandle(type); + ManagedHandle typeHandle = GetTypeGCHandle(type); NativeClassDefinitions managedClass = new NativeClassDefinitions() { - typeHandle = GCHandle.ToIntPtr(typeHandle), + typeHandle = typeHandle, name = NativeAllocStringAnsi(type.Name), fullname = NativeAllocStringAnsi(type.FullName), @namespace = NativeAllocStringAnsi(type.Namespace ?? ""), @@ -1622,25 +1819,25 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static unsafe void GetManagedClassFromType(IntPtr typeHandle, NativeClassDefinitions* managedClass, IntPtr* assemblyHandle) + internal static unsafe void GetManagedClassFromType(ManagedHandle typeHandle, NativeClassDefinitions* managedClass, ManagedHandle* assemblyHandle) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); - GCHandle classTypeHandle = GetTypeGCHandle(type); + Type type = Unsafe.As(typeHandle.Target); + ManagedHandle classTypeHandle = GetTypeGCHandle(type); *managedClass = new NativeClassDefinitions() { - typeHandle = GCHandle.ToIntPtr(classTypeHandle), + typeHandle = classTypeHandle, name = NativeAllocStringAnsi(type.Name), fullname = NativeAllocStringAnsi(type.FullName), @namespace = NativeAllocStringAnsi(type.Namespace ?? ""), typeAttributes = (uint)type.Attributes, }; - *assemblyHandle = GCHandle.ToIntPtr(GetAssemblyHandle(type.Assembly)); + *assemblyHandle = GetAssemblyHandle(type.Assembly); } [UnmanagedCallersOnly] - internal static void GetClassMethods(IntPtr typeHandle, NativeMethodDefinitions** classMethods, int* classMethodsCount) + internal static void GetClassMethods(ManagedHandle typeHandle, NativeMethodDefinitions** classMethods, int* classMethodsCount) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); List methods = new List(); var staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); @@ -1660,7 +1857,7 @@ namespace FlaxEngine numParameters = methods[i].GetParameters().Length, methodAttributes = (uint)methods[i].Attributes, }; - classMethod.typeHandle = GCHandle.ToIntPtr(GetMethodGCHandle(methods[i])); + classMethod.typeHandle = GetMethodGCHandle(methods[i]); Unsafe.Write(ptr.ToPointer(), classMethod); } *classMethods = arr; @@ -1680,9 +1877,9 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static void GetClassFields(IntPtr typeHandle, NativeFieldDefinitions** classFields, int* classFieldsCount) + internal static void GetClassFields(ManagedHandle typeHandle, NativeFieldDefinitions** classFields, int* classFieldsCount) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); NativeFieldDefinitions* arr = (NativeFieldDefinitions*)NativeAlloc(fields.Length, Unsafe.SizeOf()); @@ -1690,7 +1887,7 @@ namespace FlaxEngine { FieldHolder fieldHolder = new FieldHolder(fields[i], type); - GCHandle fieldHandle = GCHandle.Alloc(fieldHolder); + ManagedHandle fieldHandle = ManagedHandle.Alloc(fieldHolder); if (type.IsCollectible) fieldHandleCacheCollectible.Add(fieldHandle); else @@ -1699,8 +1896,8 @@ namespace FlaxEngine NativeFieldDefinitions classField = new NativeFieldDefinitions() { name = NativeAllocStringAnsi(fieldHolder.field.Name), - fieldHandle = GCHandle.ToIntPtr(fieldHandle), - fieldTypeHandle = GCHandle.ToIntPtr(GetTypeGCHandle(fieldHolder.field.FieldType)), + fieldHandle = fieldHandle, + fieldTypeHandle = GetTypeGCHandle(fieldHolder.field.FieldType), fieldAttributes = (uint)fieldHolder.field.Attributes, }; Unsafe.Write(IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i).ToPointer(), classField); @@ -1710,9 +1907,9 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static void GetClassProperties(IntPtr typeHandle, NativePropertyDefinitions** classProperties, int* classPropertiesCount) + internal static void GetClassProperties(ManagedHandle typeHandle, NativePropertyDefinitions** classProperties, int* classPropertiesCount) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); NativePropertyDefinitions* arr = (NativePropertyDefinitions*)NativeAlloc(properties.Length, Unsafe.SizeOf()); @@ -1730,12 +1927,12 @@ namespace FlaxEngine if (getterMethod != null) { var getterHandle = GetMethodGCHandle(getterMethod); - classProperty.getterHandle = GCHandle.ToIntPtr(getterHandle); + classProperty.getterHandle = getterHandle; } if (setterMethod != null) { var setterHandle = GetMethodGCHandle(setterMethod); - classProperty.setterHandle = GCHandle.ToIntPtr(setterHandle); + classProperty.setterHandle = setterHandle; } Unsafe.Write(ptr.ToPointer(), classProperty); } @@ -1744,9 +1941,9 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static void GetClassAttributes(IntPtr typeHandle, NativeAttributeDefinitions** classAttributes, int* classAttributesCount) + internal static void GetClassAttributes(ManagedHandle typeHandle, NativeAttributeDefinitions** classAttributes, int* classAttributesCount) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); object[] attributeValues = type.GetCustomAttributes(false); Type[] attributeTypes = type.GetCustomAttributes(false).Select(x => x.GetType()).ToArray(); @@ -1755,18 +1952,18 @@ namespace FlaxEngine { IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); - if (!classAttributesCacheCollectible.TryGetValue(attributeValues[i], out GCHandle attributeHandle)) + if (!classAttributesCacheCollectible.TryGetValue(attributeValues[i], out ManagedHandle attributeHandle)) { - attributeHandle = GCHandle.Alloc(attributeValues[i]); + attributeHandle = ManagedHandle.Alloc(attributeValues[i]); classAttributesCacheCollectible.Add(attributeValues[i], attributeHandle); } - GCHandle attributeTypeHandle = GetTypeGCHandle(attributeTypes[i]); + ManagedHandle attributeTypeHandle = GetTypeGCHandle(attributeTypes[i]); NativeAttributeDefinitions classAttribute = new NativeAttributeDefinitions() { name = NativeAllocStringAnsi(attributeTypes[i].Name), - attributeTypeHandle = GCHandle.ToIntPtr(attributeTypeHandle), - attributeHandle = GCHandle.ToIntPtr(attributeHandle), + attributeTypeHandle = attributeTypeHandle, + attributeHandle = attributeHandle, }; Unsafe.Write(ptr.ToPointer(), classAttribute); } @@ -1775,20 +1972,20 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static IntPtr GetCustomAttribute(IntPtr typeHandle, IntPtr attribHandle) + internal static ManagedHandle GetCustomAttribute(ManagedHandle typeHandle, ManagedHandle attribHandle) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); - Type attribType = Unsafe.As(GCHandle.FromIntPtr(attribHandle).Target); + Type type = Unsafe.As(typeHandle.Target); + Type attribType = Unsafe.As(attribHandle.Target); object attrib = type.GetCustomAttributes(false).FirstOrDefault(x => x.GetType() == attribType); if (attrib != null) - return GCHandle.ToIntPtr(GCHandle.Alloc(attrib, GCHandleType.Weak)); - return IntPtr.Zero; + return ManagedHandle.Alloc(attrib, GCHandleType.Weak); + return new ManagedHandle(); } [UnmanagedCallersOnly] - internal static void GetClassInterfaces(IntPtr typeHandle, IntPtr* classInterfaces, int* classInterfacesCount) + internal static void GetClassInterfaces(ManagedHandle typeHandle, IntPtr* classInterfaces, int* classInterfacesCount) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); Type[] interfaces = type.GetInterfaces(); // mono doesn't seem to return any interfaces, or returns only "immediate" interfaces? // FIXME? @@ -1798,32 +1995,32 @@ namespace FlaxEngine IntPtr arr = (IntPtr)NativeAlloc(interfaces.Length, IntPtr.Size); for (int i = 0; i < interfaces.Length; i++) { - GCHandle handle = GetTypeGCHandle(interfaces[i]); - Unsafe.Write(IntPtr.Add(arr, IntPtr.Size * i).ToPointer(), GCHandle.ToIntPtr(handle)); + ManagedHandle handle = GetTypeGCHandle(interfaces[i]); + Unsafe.Write(IntPtr.Add(arr, IntPtr.Size * i).ToPointer(), handle); } *classInterfaces = arr; *classInterfacesCount = interfaces.Length; } [UnmanagedCallersOnly] - internal static IntPtr GetMethodReturnType(IntPtr methodHandle) + internal static ManagedHandle GetMethodReturnType(ManagedHandle methodHandle) { - MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + MethodHolder methodHolder = Unsafe.As(methodHandle.Target); Type returnType = methodHolder.method.ReturnType; - return GCHandle.ToIntPtr(GetTypeGCHandle(returnType)); + return GetTypeGCHandle(returnType); } [UnmanagedCallersOnly] - internal static void GetMethodParameterTypes(IntPtr methodHandle, IntPtr* typeHandles) + internal static void GetMethodParameterTypes(ManagedHandle methodHandle, IntPtr* typeHandles) { - MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + MethodHolder methodHolder = Unsafe.As(methodHandle.Target); Type returnType = methodHolder.method.ReturnType; IntPtr arr = (IntPtr)NativeAlloc(methodHolder.parameterTypes.Length, IntPtr.Size); for (int i = 0; i < methodHolder.parameterTypes.Length; i++) { - GCHandle typeHandle = GetTypeGCHandle(methodHolder.parameterTypes[i]); - Unsafe.Write(IntPtr.Add(new IntPtr(arr), IntPtr.Size * i).ToPointer(), GCHandle.ToIntPtr(typeHandle)); + ManagedHandle typeHandle = GetTypeGCHandle(methodHolder.parameterTypes[i]); + Unsafe.Write(IntPtr.Add(new IntPtr(arr), IntPtr.Size * i).ToPointer(), typeHandle); } *typeHandles = arr; } @@ -1832,9 +2029,9 @@ namespace FlaxEngine /// Returns pointer to the string's internal structure, containing the buffer and length of the string. /// [UnmanagedCallersOnly] - internal static IntPtr GetStringPointer(IntPtr stringHandle) + internal static IntPtr GetStringPointer(ManagedHandle stringHandle) { - string str = Unsafe.As(GCHandle.FromIntPtr(stringHandle).Target); + string str = Unsafe.As(stringHandle.Target); IntPtr ptr = (Unsafe.Read(Unsafe.AsPointer(ref str)) + sizeof(int) * 2); if (ptr < 0x1024) throw new Exception("null string ptr"); @@ -1842,16 +2039,16 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static IntPtr NewObject(IntPtr typeHandle) + internal static ManagedHandle NewObject(ManagedHandle typeHandle) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); if (type == typeof(Script)) { // FIXME: Script is an abstract type which can not be instantiated type = typeof(VisjectScript); } object value = RuntimeHelpers.GetUninitializedObject(type); - return GCHandle.ToIntPtr(GCHandle.Alloc(value)); + return ManagedHandle.Alloc(value); } internal static class ArrayFactory @@ -1901,29 +2098,29 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static IntPtr NewArray(IntPtr typeHandle, long size) + internal static ManagedHandle NewArray(ManagedHandle typeHandle, long size) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); Type marshalledType = ArrayFactory.GetMarshalledType(type); if (marshalledType.IsValueType) { ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, Marshal.SizeOf(marshalledType)); - return GCHandle.ToIntPtr(GCHandle.Alloc(managedArray/*, GCHandleType.Weak*/)); + return ManagedHandle.Alloc(managedArray/*, GCHandleType.Weak*/); } else { Array arr = ArrayFactory.CreateArray(type, size); ManagedArray managedArray = ManagedArray.WrapNewArray(arr); - return GCHandle.ToIntPtr(GCHandle.Alloc(managedArray/*, GCHandleType.Weak*/)); + return ManagedHandle.Alloc(managedArray/*, GCHandleType.Weak*/); } } [UnmanagedCallersOnly] - internal static unsafe IntPtr GetArrayPointerToElement(IntPtr arrayHandle, int size, int index) + internal static unsafe IntPtr GetArrayPointerToElement(ManagedHandle arrayHandle, int size, int index) { - if (arrayHandle == IntPtr.Zero) + if (!arrayHandle.IsAllocated) return IntPtr.Zero; - ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(arrayHandle).Target); + ManagedArray managedArray = Unsafe.As(arrayHandle.Target); if (managedArray.Length == 0) return IntPtr.Zero; Assert.IsTrue(index >= 0 && index < managedArray.Length); @@ -1931,18 +2128,18 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static int GetArrayLength(IntPtr arrayHandle) + internal static int GetArrayLength(ManagedHandle arrayHandle) { - if (arrayHandle == IntPtr.Zero) + if (!arrayHandle.IsAllocated) return 0; - ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(arrayHandle).Target); + ManagedArray managedArray = Unsafe.As(arrayHandle.Target); return managedArray.Length; } [UnmanagedCallersOnly] internal static IntPtr GetStringEmpty() { - return GCHandle.ToIntPtr(ManagedString.EmptyStringHandle); + return ManagedHandle.ToIntPtr(ManagedString.EmptyStringHandle); } [UnmanagedCallersOnly] @@ -1967,19 +2164,19 @@ namespace FlaxEngine /// Creates a managed copy of the value, and stores it in a boxed reference. /// [UnmanagedCallersOnly] - internal static IntPtr BoxValue(IntPtr typeHandle, IntPtr valuePtr) + internal static ManagedHandle BoxValue(ManagedHandle typeHandle, IntPtr valuePtr) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); object value = MarshalToManaged(valuePtr, type); - return GCHandle.ToIntPtr(GCHandle.Alloc(value, GCHandleType.Weak)); + return ManagedHandle.Alloc(value, GCHandleType.Weak); } [UnmanagedCallersOnly] - internal static IntPtr GetObjectType(IntPtr handle) + internal static ManagedHandle GetObjectType(ManagedHandle handle) { - var obj = GCHandle.FromIntPtr(handle).Target; + var obj = handle.Target; Type classType = obj.GetType(); - return GCHandle.ToIntPtr(GetTypeGCHandle(classType)); + return GetTypeGCHandle(classType); } internal static class ValueTypeUnboxer @@ -2011,29 +2208,28 @@ namespace FlaxEngine /// Returns the address of the boxed value type. /// [UnmanagedCallersOnly] - internal unsafe static IntPtr UnboxValue(IntPtr handlePtr) + internal unsafe static IntPtr UnboxValue(ManagedHandle handle) { - GCHandle handle = GCHandle.FromIntPtr(handlePtr); object value = handle.Target; Type type = value.GetType(); if (!type.IsValueType) - return handlePtr; + return ManagedHandle.ToIntPtr(handle); // HACK: Get the address of a non-pinned value return ValueTypeUnboxer.GetPointer(value); } [UnmanagedCallersOnly] - internal static void RaiseException(IntPtr exceptionHandle) + internal static void RaiseException(ManagedHandle exceptionHandle) { - Exception exception = Unsafe.As(GCHandle.FromIntPtr(exceptionHandle).Target); + Exception exception = Unsafe.As(exceptionHandle.Target); throw exception; } [UnmanagedCallersOnly] - internal static void ObjectInit(IntPtr objectHandle) + internal static void ObjectInit(ManagedHandle objectHandle) { - object obj = GCHandle.FromIntPtr(objectHandle).Target; + object obj = objectHandle.Target; Type type = obj.GetType(); ConstructorInfo ctor = type.GetMember(".ctor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).First() as ConstructorInfo; @@ -2041,21 +2237,21 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static IntPtr InvokeMethod(IntPtr instancePtr, IntPtr methodHandle, IntPtr paramPtr, IntPtr exceptionPtr) + internal static IntPtr InvokeMethod(ManagedHandle instanceHandle, ManagedHandle methodHandle, IntPtr paramPtr, IntPtr exceptionPtr) { - MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + MethodHolder methodHolder = Unsafe.As(methodHandle.Target); if (methodHolder.TryGetDelegate(out var methodDelegate, out var methodDelegateContext)) { // Fast path, invoke the method with minimal allocations IntPtr returnValue; try { - returnValue = methodDelegate(methodDelegateContext, instancePtr, paramPtr); + returnValue = methodDelegate(methodDelegateContext, instanceHandle, paramPtr); } catch (Exception exception) { if (exceptionPtr != IntPtr.Zero) - Marshal.WriteIntPtr(exceptionPtr, GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak))); + Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(ManagedHandle.Alloc(exception, GCHandleType.Weak))); return IntPtr.Zero; } return returnValue; @@ -2076,7 +2272,7 @@ namespace FlaxEngine try { - returnObject = methodHolder.method.Invoke(instancePtr != IntPtr.Zero ? GCHandle.FromIntPtr(instancePtr).Target : null, methodParameters); + returnObject = methodHolder.method.Invoke(instanceHandle.IsAllocated ? instanceHandle.Target : null, methodParameters); } catch (Exception exception) { @@ -2086,7 +2282,7 @@ namespace FlaxEngine realException = exception.InnerException; if (exceptionPtr != IntPtr.Zero) - Marshal.WriteIntPtr(exceptionPtr, GCHandle.ToIntPtr(GCHandle.Alloc(realException, GCHandleType.Weak))); + Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(ManagedHandle.Alloc(realException, GCHandleType.Weak))); else throw realException; return IntPtr.Zero; @@ -2109,24 +2305,24 @@ namespace FlaxEngine else if (methodHolder.method.ReturnType == typeof(bool)) return (bool)returnObject ? boolTruePtr : boolFalsePtr; else if (methodHolder.method.ReturnType == typeof(Type)) - return GCHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnObject))); + return ManagedHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnObject))); else if (methodHolder.method.ReturnType.IsArray && ArrayFactory.GetMarshalledType(methodHolder.method.ReturnType.GetElementType()) == methodHolder.method.ReturnType.GetElementType()) - return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As(returnObject)), GCHandleType.Weak)); + return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As(returnObject)), GCHandleType.Weak)); else if (methodHolder.method.ReturnType.IsArray) - return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); + return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); else - return GCHandle.ToIntPtr(GCHandle.Alloc(returnObject, GCHandleType.Weak)); + return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(returnObject, GCHandleType.Weak)); } return IntPtr.Zero; } } [UnmanagedCallersOnly] - internal static IntPtr GetMethodUnmanagedFunctionPointer(IntPtr methodHandle) + internal static IntPtr GetMethodUnmanagedFunctionPointer(ManagedHandle methodHandle) { - MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + MethodHolder methodHolder = Unsafe.As(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 + // Wrap the method call, this is needed to get the object instance from ManagedHandle 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()); @@ -2144,31 +2340,31 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static void FieldSetValue(IntPtr fieldOwnerHandle, IntPtr fieldHandle, IntPtr valuePtr) + internal static void FieldSetValue(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, IntPtr valuePtr) { - object fieldOwner = GCHandle.FromIntPtr(fieldOwnerHandle).Target; - FieldHolder field = Unsafe.As(GCHandle.FromIntPtr(fieldHandle).Target); + object fieldOwner = fieldOwnerHandle.Target; + FieldHolder field = Unsafe.As(fieldHandle.Target); field.field.SetValue(fieldOwner, Marshal.PtrToStructure(valuePtr, field.field.FieldType)); } [UnmanagedCallersOnly] - internal static void FieldGetValue(IntPtr fieldOwnerHandle, IntPtr fieldHandle, IntPtr valuePtr) + internal static void FieldGetValue(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, IntPtr valuePtr) { - object fieldOwner = GCHandle.FromIntPtr(fieldOwnerHandle).Target; - FieldHolder field = Unsafe.As(GCHandle.FromIntPtr(fieldHandle).Target); + object fieldOwner = fieldOwnerHandle.Target; + FieldHolder field = Unsafe.As(fieldHandle.Target); field.toNativeMarshaller(field.field, fieldOwner, valuePtr, out int fieldOffset); } [UnmanagedCallersOnly] - internal static void SetArrayValueReference(IntPtr arrayHandle, IntPtr elementPtr, IntPtr valueHandle) + internal static void SetArrayValueReference(ManagedHandle arrayHandle, IntPtr elementPtr, IntPtr valueHandle) { - ManagedArray managedArray = Unsafe.As(GCHandle.FromIntPtr(arrayHandle).Target); + ManagedArray managedArray = Unsafe.As(arrayHandle.Target); int index = (int)(elementPtr.ToInt64() - managedArray.GetPointer.ToInt64()) / managedArray.ElementSize; managedArray.GetSpan()[index] = valueHandle; } [UnmanagedCallersOnly] - internal static IntPtr LoadAssemblyFromPath(IntPtr assemblyPath_, IntPtr* assemblyName, IntPtr* assemblyFullName) + internal static ManagedHandle LoadAssemblyFromPath(IntPtr assemblyPath_, IntPtr* assemblyName, IntPtr* assemblyFullName) { if (!firstAssemblyLoaded) { @@ -2178,7 +2374,7 @@ namespace FlaxEngine Assembly flaxEngineAssembly = AppDomain.CurrentDomain.GetAssemblies().First(x => x.GetName().Name == "FlaxEngine.CSharp"); *assemblyName = NativeAllocStringAnsi(flaxEngineAssembly.GetName().Name); *assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName); - return GCHandle.ToIntPtr(GetAssemblyHandle(flaxEngineAssembly)); + return GetAssemblyHandle(flaxEngineAssembly); } string assemblyPath = Marshal.PtrToStringAnsi(assemblyPath_); @@ -2187,11 +2383,11 @@ namespace FlaxEngine *assemblyName = NativeAllocStringAnsi(assembly.GetName().Name); *assemblyFullName = NativeAllocStringAnsi(assembly.FullName); - return GCHandle.ToIntPtr(GetAssemblyHandle(assembly)); + return GetAssemblyHandle(assembly); } [UnmanagedCallersOnly] - internal static IntPtr LoadAssemblyImage(IntPtr data, int len, IntPtr assemblyPath_, IntPtr* assemblyName, IntPtr* assemblyFullName) + internal static ManagedHandle LoadAssemblyImage(IntPtr data, int len, IntPtr assemblyPath_, IntPtr* assemblyName, IntPtr* assemblyFullName) { if (!firstAssemblyLoaded) { @@ -2201,7 +2397,7 @@ namespace FlaxEngine Assembly flaxEngineAssembly = AppDomain.CurrentDomain.GetAssemblies().First(x => x.GetName().Name == "FlaxEngine.CSharp"); *assemblyName = NativeAllocStringAnsi(flaxEngineAssembly.GetName().Name); *assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName); - return GCHandle.ToIntPtr(GetAssemblyHandle(flaxEngineAssembly)); + return GetAssemblyHandle(flaxEngineAssembly); } string assemblyPath = Marshal.PtrToStringAnsi(assemblyPath_); @@ -2218,11 +2414,11 @@ namespace FlaxEngine *assemblyName = NativeAllocStringAnsi(assembly.GetName().Name); *assemblyFullName = NativeAllocStringAnsi(assembly.FullName); - return GCHandle.ToIntPtr(GetAssemblyHandle(assembly)); + return GetAssemblyHandle(assembly); } [UnmanagedCallersOnly] - internal static IntPtr GetAssemblyByName(IntPtr name_, IntPtr* assemblyName, IntPtr* assemblyFullName) + internal static ManagedHandle GetAssemblyByName(IntPtr name_, IntPtr* assemblyName, IntPtr* assemblyFullName) { string name = Marshal.PtrToStringAnsi(name_); Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.GetName().Name == name); @@ -2231,7 +2427,7 @@ namespace FlaxEngine *assemblyName = NativeAllocStringAnsi(assembly.GetName().Name); *assemblyFullName = NativeAllocStringAnsi(assembly.FullName); - return GCHandle.ToIntPtr(GetAssemblyHandle(assembly)); + return GetAssemblyHandle(assembly); } [UnmanagedCallersOnly] @@ -2241,10 +2437,10 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static void CloseAssembly(IntPtr assemblyHandle) + internal static void CloseAssembly(ManagedHandle assemblyHandle) { - Assembly assembly = Unsafe.As(GCHandle.FromIntPtr(assemblyHandle).Target); - GCHandle.FromIntPtr(assemblyHandle).Free(); + Assembly assembly = Unsafe.As(assemblyHandle.Target); + assemblyHandle.Free(); assemblyHandles.Remove(assembly); AssemblyLocations.Remove(assembly.FullName); @@ -2293,7 +2489,7 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static IntPtr GetAssemblyObject(IntPtr assemblyName_) + internal static ManagedHandle GetAssemblyObject(IntPtr assemblyName_) { string assemblyName = Marshal.PtrToStringAnsi(assemblyName_); Assembly assembly = null; @@ -2301,13 +2497,13 @@ namespace FlaxEngine if (assembly == null) assembly = System.AppDomain.CurrentDomain.GetAssemblies().First(x => x.FullName == assemblyName); - return GCHandle.ToIntPtr(GCHandle.Alloc(assembly)); + return ManagedHandle.Alloc(assembly); } [UnmanagedCallersOnly] - internal static unsafe int NativeSizeOf(IntPtr typeHandle, uint* align) + internal static unsafe int NativeSizeOf(ManagedHandle typeHandle, uint* align) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); Type nativeType = GetInternalType(type) ?? type; if (nativeType == typeof(Version)) nativeType = typeof(VersionNative); @@ -2318,13 +2514,13 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static byte TypeIsSubclassOf(IntPtr typeHandle, IntPtr othertypeHandle, byte checkInterfaces) + internal static byte TypeIsSubclassOf(ManagedHandle typeHandle, ManagedHandle othertypeHandle, byte checkInterfaces) { if (typeHandle == othertypeHandle) return 1; - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); - Type otherType = Unsafe.As(GCHandle.FromIntPtr(othertypeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); + Type otherType = Unsafe.As(othertypeHandle.Target); if (type == otherType) return 1; @@ -2339,90 +2535,89 @@ namespace FlaxEngine } [UnmanagedCallersOnly] - internal static byte TypeIsValueType(IntPtr typeHandle) + internal static byte TypeIsValueType(ManagedHandle typeHandle) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); return (byte)(type.IsValueType ? 1 : 0); } [UnmanagedCallersOnly] - internal static byte TypeIsEnum(IntPtr typeHandle) + internal static byte TypeIsEnum(ManagedHandle typeHandle) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); return (byte)(type.IsEnum ? 1 : 0); } [UnmanagedCallersOnly] - internal static IntPtr GetClassParent(IntPtr typeHandle) + internal static ManagedHandle GetClassParent(ManagedHandle typeHandle) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); - return GCHandle.ToIntPtr(GetTypeGCHandle(type.BaseType)); + Type type = Unsafe.As(typeHandle.Target); + return GetTypeGCHandle(type.BaseType); } [UnmanagedCallersOnly] - internal static byte GetMethodParameterIsOut(IntPtr methodHandle, int parameterNum) + internal static byte GetMethodParameterIsOut(ManagedHandle methodHandle, int parameterNum) { - MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); + MethodHolder methodHolder = Unsafe.As(methodHandle.Target); ParameterInfo parameterInfo = methodHolder.method.GetParameters()[parameterNum]; return (byte)(parameterInfo.IsOut ? 1 : 0); } [UnmanagedCallersOnly] - internal static IntPtr GetNullReferenceException() + internal static ManagedHandle GetNullReferenceException() { var exception = new NullReferenceException(); - return GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak)); + return ManagedHandle.Alloc(exception, GCHandleType.Weak); } [UnmanagedCallersOnly] - internal static IntPtr GetNotSupportedException() + internal static ManagedHandle GetNotSupportedException() { var exception = new NotSupportedException(); - return GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak)); + return ManagedHandle.Alloc(exception, GCHandleType.Weak); } [UnmanagedCallersOnly] - internal static IntPtr GetArgumentNullException() + internal static ManagedHandle GetArgumentNullException() { var exception = new ArgumentNullException(); - return GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak)); + return ManagedHandle.Alloc(exception, GCHandleType.Weak); } [UnmanagedCallersOnly] - internal static IntPtr GetArgumentException() + internal static ManagedHandle GetArgumentException() { var exception = new ArgumentException(); - return GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak)); + return ManagedHandle.Alloc(exception, GCHandleType.Weak); } [UnmanagedCallersOnly] - internal static IntPtr GetArgumentOutOfRangeException() + internal static ManagedHandle GetArgumentOutOfRangeException() { var exception = new ArgumentOutOfRangeException(); - return GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak)); + return ManagedHandle.Alloc(exception, GCHandleType.Weak); } [UnmanagedCallersOnly] - internal static IntPtr NewGCHandle(IntPtr ptr, byte pinned) + internal static ManagedHandle NewGCHandle(ManagedHandle valueHandle, byte pinned) { - object value = GCHandle.FromIntPtr(ptr).Target; - GCHandle handle = GCHandle.Alloc(value, pinned != 0 ? GCHandleType.Pinned : GCHandleType.Normal); - return GCHandle.ToIntPtr(handle); + object value = valueHandle.Target; + ManagedHandle handle = ManagedHandle.Alloc(value, pinned != 0 ? GCHandleType.Pinned : GCHandleType.Normal); + return handle; } [UnmanagedCallersOnly] - internal static IntPtr NewGCHandleWeakref(IntPtr ptr, byte track_resurrection) + internal static ManagedHandle NewGCHandleWeakref(ManagedHandle valueHandle, byte track_resurrection) { - object value = GCHandle.FromIntPtr(ptr).Target; - GCHandle handle = GCHandle.Alloc(value, track_resurrection != 0 ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak); - return GCHandle.ToIntPtr(handle); + object value = valueHandle.Target; + ManagedHandle handle = ManagedHandle.Alloc(value, track_resurrection != 0 ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak); + return handle; } [UnmanagedCallersOnly] - internal static void FreeGCHandle(IntPtr ptr) + internal static void FreeGCHandle(ManagedHandle valueHandle) { - GCHandle handle = GCHandle.FromIntPtr(ptr); - handle.Free(); + valueHandle.Free(); } internal enum MonoType @@ -2466,9 +2661,9 @@ namespace FlaxEngine }; [UnmanagedCallersOnly] - internal static int GetTypeMonoTypeEnum(IntPtr typeHandle) + internal static int GetTypeMonoTypeEnum(ManagedHandle typeHandle) { - Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); + Type type = Unsafe.As(typeHandle.Target); MonoType monoType; switch (type) @@ -2570,16 +2765,16 @@ namespace FlaxEngine } /// - /// Returns a static GCHandle for given Type, and caches it if needed. + /// Returns a static ManagedHandle for given Type, and caches it if needed. /// - internal static GCHandle GetTypeGCHandle(Type type) + internal static ManagedHandle GetTypeGCHandle(Type type) { - if (typeHandleCache.TryGetValue(type, out GCHandle handle)) + if (typeHandleCache.TryGetValue(type, out ManagedHandle handle)) return handle; if (typeHandleCacheCollectible.TryGetValue(type, out handle)) return handle; - handle = GCHandle.Alloc(type); + handle = ManagedHandle.Alloc(type); if (type.IsCollectible) // check if generic parameters are also collectible? typeHandleCacheCollectible.Add(type, handle); else @@ -2658,7 +2853,7 @@ namespace FlaxEngine Assert.IsTrue(methodDelegateContext != null); } - public IntPtr InvokeThunk(IntPtr instancePtr, IntPtr param1, IntPtr param2, IntPtr param3, IntPtr param4, IntPtr param5, IntPtr param6, IntPtr param7) + public IntPtr InvokeThunk(ManagedHandle instanceHandle, 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 }; @@ -2667,14 +2862,14 @@ namespace FlaxEngine IntPtr returnValue; try { - returnValue = methodDelegate(methodDelegateContext, instancePtr, nativePtrs); + returnValue = methodDelegate(methodDelegateContext, instanceHandle, nativePtrs); } catch (Exception exception) { // Returned exception is the last parameter IntPtr exceptionPtr = nativePtrs[parameterTypes.Length]; if (exceptionPtr != IntPtr.Zero) - Marshal.WriteIntPtr(exceptionPtr, GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak))); + Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(ManagedHandle.Alloc(exception, GCHandleType.Weak))); return IntPtr.Zero; } return returnValue; @@ -2686,18 +2881,18 @@ namespace FlaxEngine int numParams = parameterTypes.Length; object[] methodParameters = new object[numParams]; for (int i = 0; i < numParams; i++) - methodParameters[i] = nativePtrs[i] == IntPtr.Zero ? null : GCHandle.FromIntPtr(nativePtrs[i]).Target; + methodParameters[i] = nativePtrs[i] == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(nativePtrs[i]).Target; try { - returnObject = method.Invoke(instancePtr != IntPtr.Zero ? GCHandle.FromIntPtr(instancePtr).Target : null, methodParameters); + returnObject = method.Invoke(instanceHandle.IsAllocated ? instanceHandle.Target : null, methodParameters); } catch (Exception exception) { // Returned exception is the last parameter IntPtr exceptionPtr = nativePtrs[numParams]; if (exceptionPtr != IntPtr.Zero) - Marshal.WriteIntPtr(exceptionPtr, GCHandle.ToIntPtr(GCHandle.Alloc(exception, GCHandleType.Weak))); + Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(ManagedHandle.Alloc(exception, GCHandleType.Weak))); return IntPtr.Zero; } @@ -2710,11 +2905,11 @@ namespace FlaxEngine else if (method.ReturnType == typeof(bool)) return (bool)returnObject ? boolTruePtr : boolFalsePtr; else if (method.ReturnType == typeof(Type)) - return GCHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnObject))); + return ManagedHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnObject))); else if (method.ReturnType == typeof(object[])) - return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); + return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnObject))), GCHandleType.Weak)); else - return GCHandle.ToIntPtr(GCHandle.Alloc(returnObject, GCHandleType.Weak)); + return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(returnObject, GCHandleType.Weak)); } return IntPtr.Zero; } diff --git a/Source/Engine/Engine/NativeInterop_Invoker.cs b/Source/Engine/Engine/NativeInterop_Invoker.cs index ad9a2da2a..38386d31a 100644 --- a/Source/Engine/Engine/NativeInterop_Invoker.cs +++ b/Source/Engine/Engine/NativeInterop_Invoker.cs @@ -15,8 +15,8 @@ namespace FlaxEngine { internal static class Invoker { - internal delegate IntPtr MarshalAndInvokeDelegate(object delegateContext, IntPtr instancePtr, IntPtr paramPtr); - internal delegate IntPtr InvokeThunkDelegate(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs); + internal delegate IntPtr MarshalAndInvokeDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr); + internal delegate IntPtr InvokeThunkDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs); internal static T* ToPointer(IntPtr ptr) where T : unmanaged { @@ -58,19 +58,19 @@ namespace FlaxEngine else if (typeof(TRet) == typeof(bool)) return (bool)(object)returnValue ? boolTruePtr : boolFalsePtr; else if (typeof(TRet) == typeof(Type)) - return returnValue != null ? GCHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnValue))) : IntPtr.Zero; + return returnValue != null ? ManagedHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnValue))) : IntPtr.Zero; else if (typeof(TRet).IsArray) { if (returnValue == null) return IntPtr.Zero; var elementType = typeof(TRet).GetElementType(); if (ArrayFactory.GetMarshalledType(elementType) == elementType) - return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As(returnValue)), GCHandleType.Weak)); + return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As(returnValue)), GCHandleType.Weak)); else - return GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnValue))), GCHandleType.Weak)); + return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As(returnValue))), GCHandleType.Weak)); } else - return returnValue != null ? GCHandle.ToIntPtr(GCHandle.Alloc(returnValue, GCHandleType.Weak)) : IntPtr.Zero; + return returnValue != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(returnValue, GCHandleType.Weak)) : IntPtr.Zero; } @@ -90,21 +90,21 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); - deleg(GCHandle.FromIntPtr(instancePtr).Target); + deleg(instancePtr.Target); return IntPtr.Zero; } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - deleg(GCHandle.FromIntPtr(instancePtr).Target); + deleg(instancePtr.Target); return IntPtr.Zero; } @@ -126,7 +126,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -135,7 +135,7 @@ namespace FlaxEngine T1 param1 = default; if (param1Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param1, param1Ptr, types[0].IsByRef); - deleg(GCHandle.FromIntPtr(instancePtr).Target, ref param1); + deleg(instancePtr.Target, ref param1); // Marshal reference parameters back to original unmanaged references if (types[0].IsByRef) @@ -145,13 +145,13 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - deleg(GCHandle.FromIntPtr(instancePtr).Target, param1); + deleg(instancePtr.Target, param1); return IntPtr.Zero; } @@ -173,7 +173,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -185,7 +185,7 @@ namespace FlaxEngine if (param1Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param1, param1Ptr, types[0].IsByRef); if (param2Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param2, param2Ptr, types[1].IsByRef); - deleg(GCHandle.FromIntPtr(instancePtr).Target, ref param1, ref param2); + deleg(instancePtr.Target, ref param1, ref param2); // Marshal reference parameters back to original unmanaged references if (types[0].IsByRef) @@ -197,14 +197,14 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2); + deleg(instancePtr.Target, param1, param2); return IntPtr.Zero; } @@ -226,7 +226,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -241,7 +241,7 @@ namespace FlaxEngine if (param2Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param2, param2Ptr, types[1].IsByRef); if (param3Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param3, param3Ptr, types[2].IsByRef); - deleg(GCHandle.FromIntPtr(instancePtr).Target, ref param1, ref param2, ref param3); + deleg(instancePtr.Target, ref param1, ref param2, ref param3); // Marshal reference parameters back to original unmanaged references if (types[0].IsByRef) @@ -255,15 +255,15 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)GCHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)ManagedHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); - deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2, param3); + deleg(instancePtr.Target, param1, param2, param3); return IntPtr.Zero; } @@ -285,7 +285,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -303,7 +303,7 @@ namespace FlaxEngine if (param3Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param3, param3Ptr, types[2].IsByRef); if (param4Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param4, param4Ptr, types[3].IsByRef); - deleg(GCHandle.FromIntPtr(instancePtr).Target, ref param1, ref param2, ref param3, ref param4); + deleg(instancePtr.Target, ref param1, ref param2, ref param3, ref param4); // Marshal reference parameters back to original unmanaged references if (types[0].IsByRef) @@ -319,16 +319,16 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)GCHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); - T4 param4 = paramPtrs[3] != IntPtr.Zero ? (T4)GCHandle.FromIntPtr(paramPtrs[3]).Target : default(T4); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)ManagedHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); + T4 param4 = paramPtrs[3] != IntPtr.Zero ? (T4)ManagedHandle.FromIntPtr(paramPtrs[3]).Target : default(T4); - deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2, param3, param4); + deleg(instancePtr.Target, param1, param2, param3, param4); return IntPtr.Zero; } @@ -350,7 +350,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -360,7 +360,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -386,7 +386,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -405,11 +405,11 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); deleg(param1); @@ -433,7 +433,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -457,12 +457,12 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); deleg(param1, param2); @@ -486,7 +486,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -515,13 +515,13 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)GCHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)ManagedHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); deleg(param1, param2, param3); @@ -545,7 +545,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -579,14 +579,14 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)GCHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); - T4 param4 = paramPtrs[3] != IntPtr.Zero ? (T4)GCHandle.FromIntPtr(paramPtrs[3]).Target : default(T4); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)ManagedHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); + T4 param4 = paramPtrs[3] != IntPtr.Zero ? (T4)ManagedHandle.FromIntPtr(paramPtrs[3]).Target : default(T4); deleg(param1, param2, param3, param4); @@ -610,21 +610,21 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target); + TRet ret = deleg(instancePtr.Target); return MarshalReturnValue(ref ret); } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target); + TRet ret = deleg(instancePtr.Target); return MarshalReturnValue(ref ret); } @@ -646,7 +646,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -655,7 +655,7 @@ namespace FlaxEngine T1 param1 = default; if (param1Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param1, param1Ptr, types[0].IsByRef); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, ref param1); + TRet ret = deleg(instancePtr.Target, ref param1); // Marshal reference parameters back to original unmanaged references if (types[0].IsByRef) @@ -665,13 +665,13 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, param1); + TRet ret = deleg(instancePtr.Target, param1); return MarshalReturnValue(ref ret); } @@ -693,7 +693,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -705,7 +705,7 @@ namespace FlaxEngine if (param1Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param1, param1Ptr, types[0].IsByRef); if (param2Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param2, param2Ptr, types[1].IsByRef); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, ref param1, ref param2); + TRet ret = deleg(instancePtr.Target, ref param1, ref param2); // Marshal reference parameters back to original unmanaged references if (types[0].IsByRef) @@ -717,14 +717,14 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2); + TRet ret = deleg(instancePtr.Target, param1, param2); return MarshalReturnValue(ref ret); } @@ -746,7 +746,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -761,7 +761,7 @@ namespace FlaxEngine if (param2Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param2, param2Ptr, types[1].IsByRef); if (param3Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param3, param3Ptr, types[2].IsByRef); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, ref param1, ref param2, ref param3); + TRet ret = deleg(instancePtr.Target, ref param1, ref param2, ref param3); // Marshal reference parameters back to original unmanaged references if (types[0].IsByRef) @@ -775,15 +775,15 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)GCHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)ManagedHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2, param3); + TRet ret = deleg(instancePtr.Target, param1, param2, param3); return MarshalReturnValue(ref ret); } @@ -805,7 +805,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -823,7 +823,7 @@ namespace FlaxEngine if (param3Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param3, param3Ptr, types[2].IsByRef); if (param4Ptr != IntPtr.Zero) MarshalHelper.ToManaged(ref param4, param4Ptr, types[3].IsByRef); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, ref param1, ref param2, ref param3, ref param4); + TRet ret = deleg(instancePtr.Target, ref param1, ref param2, ref param3, ref param4); // Marshal reference parameters back to original unmanaged references if (types[0].IsByRef) @@ -839,16 +839,16 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)GCHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); - T4 param4 = paramPtrs[3] != IntPtr.Zero ? (T4)GCHandle.FromIntPtr(paramPtrs[3]).Target : default(T4); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)ManagedHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); + T4 param4 = paramPtrs[3] != IntPtr.Zero ? (T4)ManagedHandle.FromIntPtr(paramPtrs[3]).Target : default(T4); - TRet ret = deleg(GCHandle.FromIntPtr(instancePtr).Target, param1, param2, param3, param4); + TRet ret = deleg(instancePtr.Target, param1, param2, param3, param4); return MarshalReturnValue(ref ret); } @@ -870,7 +870,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -880,7 +880,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); @@ -906,7 +906,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -925,11 +925,11 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); TRet ret = deleg(param1); @@ -953,7 +953,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -977,12 +977,12 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); TRet ret = deleg(param1, param2); @@ -1006,7 +1006,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -1035,13 +1035,13 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)GCHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)ManagedHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); TRet ret = deleg(param1, param2, param3); @@ -1065,7 +1065,7 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static IntPtr MarshalAndInvoke(object delegateContext, IntPtr instancePtr, IntPtr paramPtr) + internal static IntPtr MarshalAndInvoke(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr) { (Type[] types, InvokerDelegate deleg) = (Tuple)(delegateContext); @@ -1099,14 +1099,14 @@ namespace FlaxEngine } [DebuggerStepThrough] - internal static unsafe IntPtr InvokeThunk(object delegateContext, IntPtr instancePtr, IntPtr* paramPtrs) + internal static unsafe IntPtr InvokeThunk(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) { ThunkInvokerDelegate deleg = Unsafe.As(delegateContext); - T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)GCHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); - T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)GCHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); - T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)GCHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); - T4 param4 = paramPtrs[3] != IntPtr.Zero ? (T4)GCHandle.FromIntPtr(paramPtrs[3]).Target : default(T4); + T1 param1 = paramPtrs[0] != IntPtr.Zero ? (T1)ManagedHandle.FromIntPtr(paramPtrs[0]).Target : default(T1); + T2 param2 = paramPtrs[1] != IntPtr.Zero ? (T2)ManagedHandle.FromIntPtr(paramPtrs[1]).Target : default(T2); + T3 param3 = paramPtrs[2] != IntPtr.Zero ? (T3)ManagedHandle.FromIntPtr(paramPtrs[2]).Target : default(T3); + T4 param4 = paramPtrs[3] != IntPtr.Zero ? (T4)ManagedHandle.FromIntPtr(paramPtrs[3]).Target : default(T4); TRet ret = deleg(param1, param2, param3, param4); diff --git a/Source/Engine/Scripting/Scripting.cs b/Source/Engine/Scripting/Scripting.cs index 80cdf3fa2..41925de6e 100644 --- a/Source/Engine/Scripting/Scripting.cs +++ b/Source/Engine/Scripting/Scripting.cs @@ -209,15 +209,15 @@ namespace FlaxEngine return result; } - internal static IntPtr VersionToManaged(int major, int minor, int build, int revision) + internal static ManagedHandle VersionToManaged(int major, int minor, int build, int revision) { Version version = new Version(major, minor, Math.Max(build, 0), Math.Max(revision, 0)); - return GCHandle.ToIntPtr(GCHandle.Alloc(version)); + return ManagedHandle.Alloc(version); } - internal static void VersionToNative(IntPtr versionHandle, IntPtr nativePtr) + internal static void VersionToNative(ManagedHandle versionHandle, IntPtr nativePtr) { - Version version = (Version)GCHandle.FromIntPtr(versionHandle).Target; + Version version = Unsafe.As(versionHandle.Target); if (version != null) { Marshal.WriteInt32(nativePtr, 0, version.Major); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index 7f55e3223..14c270ffa 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -486,7 +486,7 @@ namespace Flax.Build.Bindings else if (returnValueType == "CultureInfo") returnMarshalType = "MarshalUsing(typeof(FlaxEngine.CultureInfoMarshaller))"; else if (functionInfo.ReturnType.Type == "Variant") - returnMarshalType = "MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))"; + returnMarshalType = "MarshalUsing(typeof(FlaxEngine.ManagedHandleMarshaller))"; else if (FindApiTypeInfo(buildData, functionInfo.ReturnType, caller)?.IsInterface ?? false) { // Interfaces are not supported by NativeMarshallingAttribute, marshal the parameter @@ -538,7 +538,7 @@ namespace Flax.Build.Bindings else if (parameterInfo.Type.Type == "CultureInfo") parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.CultureInfoMarshaller))"; else if (parameterInfo.Type.Type == "Variant") // object - parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))"; + parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.ManagedHandleMarshaller))"; else if (parameterInfo.Type.Type == "MonoArray") parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.SystemArrayMarshaller))"; else if (parameterInfo.Type.Type == "Array" && parameterInfo.Type.GenericArgs.Count > 0 && parameterInfo.Type.GenericArgs[0].Type == "bool") @@ -1259,29 +1259,29 @@ namespace Flax.Build.Bindings #pragma warning disable 1591 public static class NativeToManaged { - public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => ({{classInfo.Name}})GCHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged); - public static void Free(IntPtr unmanaged) => GCHandleMarshaller.NativeToManaged.Free(unmanaged); + public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => ({{classInfo.Name}})ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged); + public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.NativeToManaged.Free(unmanaged); } public static class ManagedToNative { - public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => GCHandleMarshaller.ManagedToNative.ConvertToUnmanaged(managed); - public static void Free(IntPtr unmanaged) => GCHandleMarshaller.ManagedToNative.Free(unmanaged); + public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => ManagedHandleMarshaller.ManagedToNative.ConvertToUnmanaged(managed); + public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.ManagedToNative.Free(unmanaged); } public struct Bidirectional { - GCHandleMarshaller.Bidirectional marsh; + ManagedHandleMarshaller.Bidirectional marsh; public void FromManaged({{classInfo.Name}} managed) => marsh.FromManaged(managed); public IntPtr ToUnmanaged() => marsh.ToUnmanaged(); public void FromUnmanaged(IntPtr unmanaged) => marsh.FromUnmanaged(unmanaged); public {{classInfo.Name}} ToManaged() => ({{classInfo.Name}})marsh.ToManaged(); public void Free() => marsh.Free(); } - internal static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => ({{classInfo.Name}})GCHandleMarshaller.ConvertToManaged(unmanaged); - internal static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => GCHandleMarshaller.ConvertToUnmanaged(managed); - internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged); + internal static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => ({{classInfo.Name}})ManagedHandleMarshaller.ConvertToManaged(unmanaged); + internal static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => ManagedHandleMarshaller.ConvertToUnmanaged(managed); + internal static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.Free(unmanaged); - internal static {{classInfo.Name}} ToManaged(IntPtr managed) => ({{classInfo.Name}})GCHandleMarshaller.ToManaged(managed); - internal static IntPtr ToNative({{classInfo.Name}} managed) => GCHandleMarshaller.ToNative(managed); + internal static {{classInfo.Name}} ToManaged(IntPtr managed) => ({{classInfo.Name}})ManagedHandleMarshaller.ToManaged(managed); + internal static IntPtr ToNative({{classInfo.Name}} managed) => ManagedHandleMarshaller.ToNative(managed); #pragma warning restore 1591 } """).Split(new char[] { '\n' }))); @@ -1460,41 +1460,41 @@ namespace Flax.Build.Bindings if (fieldInfo.Type.IsObjectRef) { - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({fieldInfo.Type.GenericArgs[0].Type})GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); - toNativeContent.Append($"managed.{fieldInfo.Name} != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak)) : IntPtr.Zero"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({fieldInfo.Type.GenericArgs[0].Type})ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + toNativeContent.Append($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak)) : IntPtr.Zero"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); // Permanent ScriptingObject handle is passed from native side, do not release it - //freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + //freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); } else if (fieldInfo.Type.Type == "ScriptingObject") { - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? (FlaxEngine.Object)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); - toNativeContent.Append($"managed.{fieldInfo.Name} != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak)) : IntPtr.Zero"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? (FlaxEngine.Object)ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + toNativeContent.Append($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak)) : IntPtr.Zero"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); // Permanent ScriptingObject handle is passed from native side, do not release it - //freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + //freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); } else if (fieldInfo.Type.IsPtr && originalType != "IntPtr" && !originalType.EndsWith("*")) { - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); - toNativeContent.Append($"managed.{fieldInfo.Name} != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak)) : IntPtr.Zero"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + toNativeContent.Append($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak)) : IntPtr.Zero"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); // Permanent ScriptingObject handle is passed from native side, do not release it - //freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + //freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); } else if (fieldInfo.Type.Type == "Dictionary") { string dictionaryArgs = String.Join(", ", fieldInfo.Type.GenericArgs.Select(x => CSharpNativeToManagedBasicTypes.ContainsKey(x.Type) ? CSharpNativeToManagedBasicTypes[x.Type] : x.Type).ToArray()); toManagedContent.Append( - $"managed.{fieldInfo.Name} != IntPtr.Zero ? (System.Collections.Generic.{fieldInfo.Type.Type}<{dictionaryArgs}>)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + $"managed.{fieldInfo.Name} != IntPtr.Zero ? (System.Collections.Generic.{fieldInfo.Type.Type}<{dictionaryArgs}>)ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); toNativeContent.Append( - $"GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak))"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); - freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + $"ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak))"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); } else if (fieldInfo.Type.Type == "Array") { @@ -1504,34 +1504,34 @@ namespace Flax.Build.Bindings // Marshal blittable array elements back to original non-blittable elements 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.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(); }}"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.NativeArrayToManagedArray<{originalElementType}, {internalElementType}>(((ManagedArray)ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target).GetSpan<{internalElementType}>(), {originalElementTypeMarshaller}.ToManaged) : null"); + toNativeContent.Append($"ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak))"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.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) {{ ManagedHandle handle = ManagedHandle.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.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(); }}"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>((ManagedArray)ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null"); + toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.{fieldInfo.Name})), GCHandleType.Weak)) : IntPtr.Zero"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = ((ManagedArray)handle.Target).GetSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span ptrs = ((ManagedArray)handle.Target).GetSpan(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.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.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(); }}"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ((ManagedArray)ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target).GetArray<{originalElementType}>() : null"); + toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak)) : IntPtr.Zero"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); ((ManagedArray)handle.Target).Free(); handle.Free(); }}"); } } else if (fieldInfo.Type.Type == "Version") { - toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); - toNativeContent.Append($"GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak))"); - freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); - freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null"); + toNativeContent.Append($"ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak))"); + freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); + freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); } else if (originalType == "string") { @@ -1924,9 +1924,9 @@ namespace Flax.Build.Bindings contents.Append(indent).AppendLine($"public static class {marshallerName}"); contents.Append(indent).AppendLine("{"); contents.AppendLine("#pragma warning disable 1591"); - contents.Append(indent).Append(" ").AppendLine($"internal static {interfaceInfo.Name} ConvertToManaged(IntPtr unmanaged) => ({interfaceInfo.Name})GCHandleMarshaller.ConvertToManaged(unmanaged);"); - contents.Append(indent).Append(" ").AppendLine($"internal static IntPtr ConvertToUnmanaged({interfaceInfo.Name} managed) => GCHandleMarshaller.ConvertToUnmanaged(managed);"); - contents.Append(indent).Append(" ").AppendLine("internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged);"); + contents.Append(indent).Append(" ").AppendLine($"internal static {interfaceInfo.Name} ConvertToManaged(IntPtr unmanaged) => ({interfaceInfo.Name})ManagedHandleMarshaller.ConvertToManaged(unmanaged);"); + contents.Append(indent).Append(" ").AppendLine($"internal static IntPtr ConvertToUnmanaged({interfaceInfo.Name} managed) => ManagedHandleMarshaller.ConvertToUnmanaged(managed);"); + contents.Append(indent).Append(" ").AppendLine("internal static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.Free(unmanaged);"); contents.AppendLine("#pragma warning restore 1591"); contents.Append(indent).AppendLine("}"); } From 2f507091b270c15aecef52e96e23ac30fb5d1fdf Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sat, 31 Dec 2022 15:30:58 +0200 Subject: [PATCH 2/4] Fix ManagedHandle marshalling --- Source/Engine/Engine/NativeInterop.cs | 10 ++++++++++ Source/Engine/Engine/NativeInterop_Invoker.cs | 2 ++ 2 files changed, 12 insertions(+) diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 9efbcaabe..4f84cff2e 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -400,12 +400,16 @@ namespace FlaxEngine public bool IsAllocated => handle != IntPtr.Zero; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ManagedHandle(IntPtr value) => FromIntPtr(value); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedHandle FromIntPtr(IntPtr value) => new ManagedHandle(value); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator IntPtr(ManagedHandle value) => ToIntPtr(value); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IntPtr ToIntPtr(ManagedHandle value) => value.handle; public override int GetHashCode() => handle.GetHashCode(); @@ -1583,6 +1587,8 @@ namespace FlaxEngine if (type == typeof(IntPtr)) managedValue = (T)(object)nativePtr; + else if (type == typeof(ManagedHandle)) + managedValue = (T)(object)ManagedHandle.FromIntPtr(nativePtr); else if (MarshalHelper.marshallableFields != null) { IntPtr fieldPtr = nativePtr; @@ -2302,6 +2308,8 @@ namespace FlaxEngine return ManagedString.ToNative(Unsafe.As(returnObject)); else if (methodHolder.method.ReturnType == typeof(IntPtr)) return (IntPtr)returnObject; + else if (methodHolder.method.ReturnType == typeof(ManagedHandle)) + return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject); else if (methodHolder.method.ReturnType == typeof(bool)) return (bool)returnObject ? boolTruePtr : boolFalsePtr; else if (methodHolder.method.ReturnType == typeof(Type)) @@ -2902,6 +2910,8 @@ namespace FlaxEngine return ManagedString.ToNative(Unsafe.As(returnObject)); else if (method.ReturnType == typeof(IntPtr)) return (IntPtr)returnObject; + else if (method.ReturnType == typeof(ManagedHandle)) + return ManagedHandle.ToIntPtr((ManagedHandle)returnObject); else if (method.ReturnType == typeof(bool)) return (bool)returnObject ? boolTruePtr : boolFalsePtr; else if (method.ReturnType == typeof(Type)) diff --git a/Source/Engine/Engine/NativeInterop_Invoker.cs b/Source/Engine/Engine/NativeInterop_Invoker.cs index 38386d31a..21f9770e9 100644 --- a/Source/Engine/Engine/NativeInterop_Invoker.cs +++ b/Source/Engine/Engine/NativeInterop_Invoker.cs @@ -55,6 +55,8 @@ namespace FlaxEngine return ManagedString.ToNative(Unsafe.As(returnValue)); else if (typeof(TRet) == typeof(IntPtr)) return (IntPtr)(object)returnValue; + else if (typeof(TRet) == typeof(ManagedHandle)) + return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnValue); else if (typeof(TRet) == typeof(bool)) return (bool)(object)returnValue ? boolTruePtr : boolFalsePtr; else if (typeof(TRet) == typeof(Type)) From 21c67b4777484729c5ef1ac8c41fa5c35673e73c Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sat, 31 Dec 2022 15:34:16 +0200 Subject: [PATCH 3/4] Fix weak ManagedHandles collection --- Source/Engine/Engine/NativeInterop.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 4f84cff2e..2be91651e 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -437,7 +437,7 @@ namespace FlaxEngine private static Dictionary weakPool = weakPool1; private static Dictionary weakPoolOther = weakPool2; - private static int nextCollection = GC.CollectionCount(0) + 2; + private static int nextCollection = GC.CollectionCount(0) + 1; /// /// Tries to free all references to old weak handles so GC can collect them. @@ -449,15 +449,13 @@ namespace FlaxEngine lock (poolLock) { - // During initialization we might want to skip - // few generations between collections due to high GC pressure. - nextCollection = GC.CollectionCount(0) + 2; + nextCollection = GC.CollectionCount(0) + 1; var swap = weakPoolOther; weakPoolOther = weakPool; weakPool = swap; - weakPoolOther.Clear(); + weakPool.Clear(); } } From 5b4e20981671ced36cff653ba5930e7910d9b646 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 1 Jan 2023 22:06:00 +0200 Subject: [PATCH 4/4] Fix creating delegates to scripting methods after script reload --- Source/Engine/Engine/NativeInterop.cs | 49 ++++++++------- Source/Engine/Engine/NativeInterop_Invoker.cs | 61 +++++++++++++------ 2 files changed, 69 insertions(+), 41 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 2be91651e..a9df6c96c 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -1067,8 +1067,7 @@ namespace FlaxEngine var isCollectible = false; #endif scriptingAssemblyLoadContext = new AssemblyLoadContext("Flax", isCollectible); - - DelegateHelpers.Init(); + DelegateHelpers.InitMethods(); } [UnmanagedCallersOnly] @@ -2323,17 +2322,16 @@ namespace FlaxEngine } } + private delegate IntPtr InvokeThunkDelegate(ManagedHandle instanceHandle, IntPtr param1, IntPtr param2, IntPtr param3, IntPtr param4, IntPtr param5, IntPtr param6, IntPtr param7); + [UnmanagedCallersOnly] internal static IntPtr GetMethodUnmanagedFunctionPointer(ManagedHandle methodHandle) { MethodHolder methodHolder = Unsafe.As(methodHandle.Target); // Wrap the method call, this is needed to get the object instance from ManagedHandle 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(methodHolder.method); - Delegate methodDelegate = invokeThunk.CreateDelegate(delegateType, context); + Delegate methodDelegate = typeof(ThunkContext).GetMethod(nameof(ThunkContext.InvokeThunk)).CreateDelegate(context); IntPtr functionPtr = Marshal.GetFunctionPointerForDelegate(methodDelegate); // Keep a reference to the delegate to prevent it from being garbage collected @@ -2491,7 +2489,8 @@ namespace FlaxEngine System.Threading.Thread.Sleep(1); // TODO: benchmark collectible setting performance, maybe enable it only in editor builds? - scriptingAssemblyLoadContext = new AssemblyLoadContext(null, true); + scriptingAssemblyLoadContext = new AssemblyLoadContext("Flax", true); + DelegateHelpers.InitMethods(); } [UnmanagedCallersOnly] @@ -2791,28 +2790,36 @@ namespace FlaxEngine private static class DelegateHelpers { - private static readonly Func MakeNewCustomDelegateFunc = - typeof(Expression).Assembly.GetType("System.Linq.Expressions.Compiler.DelegateHelpers") - .GetMethod("MakeNewCustomDelegate", BindingFlags.NonPublic | BindingFlags.Static) - .CreateDelegate>(); + private static Func MakeNewCustomDelegateFunc; + private static Func MakeNewCustomDelegateFuncCollectible; - internal static void Init() + internal static void InitMethods() { - // Ensures the MakeNewCustomDelegate is put in the collectible ALC? - using var ctx = scriptingAssemblyLoadContext.EnterContextualReflection(); + MakeNewCustomDelegateFunc = + typeof(Expression).Assembly.GetType("System.Linq.Expressions.Compiler.DelegateHelpers") + .GetMethod("MakeNewCustomDelegate", BindingFlags.NonPublic | BindingFlags.Static).CreateDelegate>(); + // Load System.Linq.Expressions assembly to collectible ALC. + // The dynamic assembly where delegates are stored is cached in the DelegateHelpers class, so we should + // use the DelegateHelpers in collectible ALC to make sure the delegates are also stored in the same ALC. + Assembly assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(typeof(Expression).Assembly.Location); + MakeNewCustomDelegateFuncCollectible = + assembly.GetType("System.Linq.Expressions.Compiler.DelegateHelpers") + .GetMethod("MakeNewCustomDelegate", BindingFlags.NonPublic | BindingFlags.Static).CreateDelegate>(); + + // Create dummy delegates to force the dynamic Snippets assembly to be loaded in correcet ALCs MakeNewCustomDelegateFunc(new[] { typeof(void) }); + { + // Ensure the new delegate is placed in the collectible ALC + using var ctx = scriptingAssemblyLoadContext.EnterContextualReflection(); + MakeNewCustomDelegateFuncCollectible(new[] { typeof(void) }); + } } internal static Type MakeNewCustomDelegate(Type[] parameters) { - if (parameters.Any(x => scriptingAssemblyLoadContext.Assemblies.Contains(x.Module.Assembly))) - { - // Ensure the new delegate is placed in the collectible ALC - //using var ctx = scriptingAssemblyLoadContext.EnterContextualReflection(); - return MakeNewCustomDelegateFunc(parameters); - } - + if (parameters.Any(x => x.IsCollectible)) + return MakeNewCustomDelegateFuncCollectible(parameters); return MakeNewCustomDelegateFunc(parameters); } } diff --git a/Source/Engine/Engine/NativeInterop_Invoker.cs b/Source/Engine/Engine/NativeInterop_Invoker.cs index 21f9770e9..2098c653c 100644 --- a/Source/Engine/Engine/NativeInterop_Invoker.cs +++ b/Source/Engine/Engine/NativeInterop_Invoker.cs @@ -1,7 +1,5 @@ #if USE_NETCORE - using System; -using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -13,40 +11,64 @@ namespace FlaxEngine { internal unsafe static partial class NativeInterop { + /// + /// Helper class for invoking managed methods from delegates. + /// internal static class Invoker { internal delegate IntPtr MarshalAndInvokeDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr); internal delegate IntPtr InvokeThunkDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs); + /// + /// Casts managed pointer to unmanaged pointer. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T* ToPointer(IntPtr ptr) where T : unmanaged { return (T*)ptr.ToPointer(); } + internal static MethodInfo ToPointerMethod = typeof(Invoker).GetMethod(nameof(Invoker.ToPointer), BindingFlags.Static | BindingFlags.NonPublic); /// /// Creates a delegate for invoker to pass parameters as references. /// - internal static Delegate CreateDelegateFromMethod(MethodInfo method, bool byRefParameters = true) + internal static Delegate CreateDelegateFromMethod(MethodInfo method, bool passParametersByRef = true) { - Type[] methodParameters = method.GetParameters().Select(x => x.ParameterType).ToArray(); - Type[] delegateParameters = method.GetParameters().Select(x => x.ParameterType.IsPointer ? typeof(IntPtr) : x.ParameterType).ToArray(); - if (byRefParameters) - delegateParameters = delegateParameters.Select(x => x.IsByRef ? x : x.MakeByRefType()).ToArray(); + Type[] methodParameters; + if (method.IsStatic) + methodParameters = method.GetParameters().Select(x => x.ParameterType).ToArray(); + else + methodParameters = method.GetParameters().Select(x => x.ParameterType).Prepend(method.DeclaringType).ToArray(); - List parameterExpressions = new List(delegateParameters.Select(x => Expression.Parameter(x))); - List callExpressions = new List(parameterExpressions); - for (int i = 0; i < callExpressions.Count; i++) - if (methodParameters[i].IsPointer) - callExpressions[i] = Expression.Call(null, typeof(Invoker).GetMethod(nameof(Invoker.ToPointer), BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(methodParameters[i].GetElementType()), parameterExpressions[i]); + // Pass delegate parameters by reference + Type[] delegateParameters = methodParameters.Select(x => x.IsPointer ? typeof(IntPtr) : x) + .Select(x => passParametersByRef && !x.IsByRef ? x.MakeByRefType() : x).ToArray(); + if (!method.IsStatic && passParametersByRef) + delegateParameters[0] = method.DeclaringType; - var firstParamExp = Expression.Parameter(method.DeclaringType); - var callDelegExp = Expression.Call(!method.IsStatic ? firstParamExp : null, method, callExpressions.ToArray()); + // Convert unmanaged pointer parameters to IntPtr + ParameterExpression[] parameterExpressions = delegateParameters.Select(x => Expression.Parameter(x)).ToArray(); + Expression[] callExpressions = new Expression[methodParameters.Length]; + for (int i = 0; i < methodParameters.Length; i++) + { + Type parameterType = methodParameters[i]; + if (parameterType.IsPointer) + { + callExpressions[i] = + Expression.Call(null, ToPointerMethod.MakeGenericMethod(parameterType.GetElementType()), parameterExpressions[i]); + } + else + callExpressions[i] = parameterExpressions[i]; + } - if (!method.IsStatic) - parameterExpressions.Insert(0, firstParamExp); - var lambda = Expression.Lambda(callDelegExp, parameterExpressions.ToArray()); - - return lambda.Compile(); + // Create and compile the delegate + MethodCallExpression callDelegExp; + if (method.IsStatic) + callDelegExp = Expression.Call(null, method, callExpressions.ToArray()); + else + callDelegExp = Expression.Call(parameterExpressions[0], method, callExpressions.Skip(1).ToArray()); + Type delegateType = DelegateHelpers.MakeNewCustomDelegate(delegateParameters.Append(method.ReturnType).ToArray()); + return Expression.Lambda(delegateType, callDelegExp, parameterExpressions.ToArray()).Compile(); } internal static IntPtr MarshalReturnValue(ref TRet returnValue) @@ -75,7 +97,6 @@ namespace FlaxEngine return returnValue != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(returnValue, GCHandleType.Weak)) : IntPtr.Zero; } - internal static class InvokerNoRet0 { internal delegate void InvokerDelegate(object instance);