diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 43d6ea91c..0c1f93864 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -15,6 +15,7 @@ using System.Runtime.InteropServices.Marshalling; using FlaxEngine.Visject; using System.Buffers; using System.Collections.Concurrent; +using System.Text; #pragma warning disable 1591 @@ -181,9 +182,11 @@ namespace FlaxEngine return managedArray; } - internal static ManagedArray AllocateNewArray(T* ptr, int length) where T : unmanaged => new ManagedArray(ptr, length, Unsafe.SizeOf()); + internal static ManagedArray AllocateNewArray(int length, int elementSize) + => new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, elementSize), length, elementSize); - internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, int elementSize) => new ManagedArray(ptr.ToPointer(), length, elementSize); + internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, int elementSize) + => new ManagedArray(ptr, length, elementSize); /// /// Returns an instance of ManagedArray from shared pool. @@ -198,6 +201,19 @@ namespace FlaxEngine return managedArray; } + /// + /// Returns an instance of ManagedArray from shared pool. + /// + /// + /// The resources must be released by calling FreePooled() instead of Free()-method. + /// + internal static ManagedArray AllocatePooledArray(int length) where T : unmanaged + { + ManagedArray managedArray = ManagedArrayPool.Get(); + managedArray.Allocate((IntPtr)NativeInterop.NativeAlloc(length, Unsafe.SizeOf()), length, Unsafe.SizeOf()); + return managedArray; + } + internal ManagedArray(Array arr) => WrapArray(arr); internal void WrapArray(Array arr) @@ -224,7 +240,7 @@ namespace FlaxEngine private ManagedArray() { } - private ManagedArray(void* ptr, int length, int elementSize) => Allocate(new IntPtr(ptr), length, elementSize); + private ManagedArray(IntPtr ptr, int length, int elementSize) => Allocate(ptr, length, elementSize); ~ManagedArray() { @@ -242,7 +258,7 @@ namespace FlaxEngine } if (unmanagedData != IntPtr.Zero) { - Marshal.FreeHGlobal(unmanagedData); + NativeInterop.NativeFree(unmanagedData.ToPointer()); unmanagedData = IntPtr.Zero; } } @@ -608,7 +624,7 @@ namespace FlaxEngine return null; } numElements = managed.Length; - ManagedArray managedArray = ManagedArray.AllocatePooledArray((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length); + ManagedArray managedArray = ManagedArray.AllocatePooledArray(managed.Length); var ptr = GCHandle.ToIntPtr(GCHandle.Alloc(managedArray)); return (TUnmanagedElement*)ptr; } @@ -644,7 +660,7 @@ namespace FlaxEngine if (managed == null) return; managedArray = managed; - unmanagedArray = ManagedArray.AllocatePooledArray((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length); + unmanagedArray = ManagedArray.AllocatePooledArray(managed.Length); handle = GCHandle.Alloc(unmanagedArray); } @@ -692,7 +708,7 @@ namespace FlaxEngine return null; } numElements = managed.Length; - ManagedArray managedArray = ManagedArray.AllocatePooledArray((TUnmanagedElement*)Marshal.AllocHGlobal(sizeof(TUnmanagedElement) * managed.Length), managed.Length); + ManagedArray managedArray = ManagedArray.AllocatePooledArray(managed.Length); IntPtr handle = GCHandle.ToIntPtr(GCHandle.Alloc(managedArray)); return (TUnmanagedElement*)handle; } @@ -869,6 +885,35 @@ namespace FlaxEngine nativeLibraryPaths[moduleName] = modulePath; } + internal static void* NativeAlloc(int byteCount) + { + return NativeMemory.AlignedAlloc((UIntPtr)byteCount, 16); + } + + internal static void* NativeAlloc(int elementCount, int elementSize) + { + return NativeMemory.AlignedAlloc((UIntPtr)(elementCount * elementSize), 16); + } + + internal static IntPtr NativeAllocStringAnsi(string str) + { + if (str is null) + return IntPtr.Zero; + + int length = str.Length + 1; + void* ptr = NativeMemory.AlignedAlloc((UIntPtr)length, 16); + Span byteSpan = new Span(ptr, length); + Encoding.ASCII.GetBytes(str, byteSpan); + byteSpan[length - 1] = 0; + + return (IntPtr)ptr; + } + + internal static void NativeFree(void* ptr) + { + NativeMemory.AlignedFree(ptr); + } + internal static T[] GCHandleArrayToManagedArray(ManagedArray ptrArray) { Span span = ptrArray.GetSpan(); @@ -1530,7 +1575,7 @@ namespace FlaxEngine Assembly assembly = Unsafe.As(GCHandle.FromIntPtr(assemblyHandle).Target); var assemblyTypes = GetAssemblyTypes(assembly); - NativeClassDefinitions* arr = (NativeClassDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * assemblyTypes.Length).ToPointer(); + NativeClassDefinitions* arr = (NativeClassDefinitions*)NativeAlloc(assemblyTypes.Length, Unsafe.SizeOf()); for (int i = 0; i < assemblyTypes.Length; i++) { @@ -1545,9 +1590,9 @@ namespace FlaxEngine NativeClassDefinitions managedClass = new NativeClassDefinitions() { typeHandle = GCHandle.ToIntPtr(typeHandle), - name = Marshal.StringToCoTaskMemAnsi(type.Name), - fullname = Marshal.StringToCoTaskMemAnsi(type.FullName), - @namespace = Marshal.StringToCoTaskMemAnsi(type.Namespace ?? ""), + name = NativeAllocStringAnsi(type.Name), + fullname = NativeAllocStringAnsi(type.FullName), + @namespace = NativeAllocStringAnsi(type.Namespace ?? ""), typeAttributes = (uint)type.Attributes, }; Unsafe.Write(ptr.ToPointer(), managedClass); @@ -1565,9 +1610,9 @@ namespace FlaxEngine *managedClass = new NativeClassDefinitions() { typeHandle = GCHandle.ToIntPtr(classTypeHandle), - name = Marshal.StringToCoTaskMemAnsi(type.Name), - fullname = Marshal.StringToCoTaskMemAnsi(type.FullName), - @namespace = Marshal.StringToCoTaskMemAnsi(type.Namespace ?? ""), + name = NativeAllocStringAnsi(type.Name), + fullname = NativeAllocStringAnsi(type.FullName), + @namespace = NativeAllocStringAnsi(type.Namespace ?? ""), typeAttributes = (uint)type.Attributes, }; *assemblyHandle = GCHandle.ToIntPtr(GetAssemblyHandle(type.Assembly)); @@ -1586,13 +1631,13 @@ namespace FlaxEngine foreach (MethodInfo method in instanceMethods) methods.Add(method); - NativeMethodDefinitions* arr = (NativeMethodDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * methods.Count).ToPointer(); + NativeMethodDefinitions* arr = (NativeMethodDefinitions*)NativeAlloc(methods.Count, Unsafe.SizeOf()); for (int i = 0; i < methods.Count; i++) { IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); NativeMethodDefinitions classMethod = new NativeMethodDefinitions() { - name = Marshal.StringToCoTaskMemAnsi(methods[i].Name), + name = NativeAllocStringAnsi(methods[i].Name), numParameters = methods[i].GetParameters().Length, methodAttributes = (uint)methods[i].Attributes, }; @@ -1621,11 +1666,9 @@ namespace FlaxEngine Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - NativeFieldDefinitions* arr = (NativeFieldDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * fields.Length).ToPointer(); + NativeFieldDefinitions* arr = (NativeFieldDefinitions*)NativeAlloc(fields.Length, Unsafe.SizeOf()); for (int i = 0; i < fields.Length; i++) { - IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); - FieldHolder fieldHolder = new FieldHolder(fields[i], type); GCHandle fieldHandle = GCHandle.Alloc(fieldHolder); @@ -1636,12 +1679,12 @@ namespace FlaxEngine NativeFieldDefinitions classField = new NativeFieldDefinitions() { - name = Marshal.StringToCoTaskMemAnsi(fieldHolder.field.Name), + name = NativeAllocStringAnsi(fieldHolder.field.Name), fieldHandle = GCHandle.ToIntPtr(fieldHandle), fieldTypeHandle = GCHandle.ToIntPtr(GetTypeGCHandle(fieldHolder.field.FieldType)), fieldAttributes = (uint)fieldHolder.field.Attributes, }; - Unsafe.Write(ptr.ToPointer(), classField); + Unsafe.Write(IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i).ToPointer(), classField); } *classFields = arr; *classFieldsCount = fields.Length; @@ -1653,7 +1696,7 @@ namespace FlaxEngine Type type = Unsafe.As(GCHandle.FromIntPtr(typeHandle).Target); var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - NativePropertyDefinitions* arr = (NativePropertyDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * properties.Length).ToPointer(); + NativePropertyDefinitions* arr = (NativePropertyDefinitions*)NativeAlloc(properties.Length, Unsafe.SizeOf()); for (int i = 0; i < properties.Length; i++) { IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); @@ -1663,7 +1706,7 @@ namespace FlaxEngine NativePropertyDefinitions classProperty = new NativePropertyDefinitions() { - name = Marshal.StringToCoTaskMemAnsi(properties[i].Name), + name = NativeAllocStringAnsi(properties[i].Name), }; if (getterMethod != null) { @@ -1688,7 +1731,7 @@ namespace FlaxEngine object[] attributeValues = type.GetCustomAttributes(false); Type[] attributeTypes = type.GetCustomAttributes(false).Select(x => x.GetType()).ToArray(); - NativeAttributeDefinitions* arr = (NativeAttributeDefinitions*)Marshal.AllocCoTaskMem(Unsafe.SizeOf() * attributeTypes.Length).ToPointer(); + NativeAttributeDefinitions* arr = (NativeAttributeDefinitions*)NativeAlloc(attributeTypes.Length, Unsafe.SizeOf()); for (int i = 0; i < attributeTypes.Length; i++) { IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); @@ -1702,7 +1745,7 @@ namespace FlaxEngine NativeAttributeDefinitions classAttribute = new NativeAttributeDefinitions() { - name = Marshal.StringToCoTaskMemAnsi(attributeTypes[i].Name), + name = NativeAllocStringAnsi(attributeTypes[i].Name), attributeTypeHandle = GCHandle.ToIntPtr(attributeTypeHandle), attributeHandle = GCHandle.ToIntPtr(attributeHandle), }; @@ -1733,13 +1776,11 @@ namespace FlaxEngine //foreach (Type interfaceType in type.BaseType.GetInterfaces()) // interfaces.Remove(interfaceType.FullName); - IntPtr arr = Marshal.AllocCoTaskMem(IntPtr.Size * interfaces.Length); + IntPtr arr = (IntPtr)NativeAlloc(interfaces.Length, IntPtr.Size); for (int i = 0; i < interfaces.Length; i++) { - IntPtr ptr = IntPtr.Add(arr, IntPtr.Size * i); - GCHandle handle = GetTypeGCHandle(interfaces[i]); - Marshal.WriteIntPtr(ptr, GCHandle.ToIntPtr(handle)); + Unsafe.Write(IntPtr.Add(arr, IntPtr.Size * i).ToPointer(), GCHandle.ToIntPtr(handle)); } *classInterfaces = arr; *classInterfacesCount = interfaces.Length; @@ -1759,11 +1800,11 @@ namespace FlaxEngine { MethodHolder methodHolder = Unsafe.As(GCHandle.FromIntPtr(methodHandle).Target); Type returnType = methodHolder.method.ReturnType; - IntPtr arr = Marshal.AllocCoTaskMem(IntPtr.Size * methodHolder.parameterTypes.Length); + IntPtr arr = (IntPtr)NativeAlloc(methodHolder.parameterTypes.Length, IntPtr.Size); for (int i = 0; i < methodHolder.parameterTypes.Length; i++) { GCHandle typeHandle = GetTypeGCHandle(methodHolder.parameterTypes[i]); - Marshal.WriteIntPtr(IntPtr.Add(new IntPtr(arr), IntPtr.Size * i), GCHandle.ToIntPtr(typeHandle)); + Unsafe.Write(IntPtr.Add(new IntPtr(arr), IntPtr.Size * i).ToPointer(), GCHandle.ToIntPtr(typeHandle)); } *typeHandles = arr; } @@ -1847,7 +1888,7 @@ namespace FlaxEngine Type marshalledType = ArrayFactory.GetMarshalledType(type); if (marshalledType.IsValueType) { - ManagedArray managedArray = ManagedArray.AllocateNewArray(Marshal.AllocHGlobal(Marshal.SizeOf(marshalledType) * (int)size), (int)size, Marshal.SizeOf(marshalledType)); + ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, Marshal.SizeOf(marshalledType)); return GCHandle.ToIntPtr(GCHandle.Alloc(managedArray/*, GCHandleType.Weak*/)); } else @@ -2111,8 +2152,8 @@ namespace FlaxEngine firstAssemblyLoaded = true; Assembly flaxEngineAssembly = AppDomain.CurrentDomain.GetAssemblies().First(x => x.GetName().Name == "FlaxEngine.CSharp"); - *assemblyName = Marshal.StringToCoTaskMemAnsi(flaxEngineAssembly.GetName().Name); - *assemblyFullName = Marshal.StringToCoTaskMemAnsi(flaxEngineAssembly.FullName); + *assemblyName = NativeAllocStringAnsi(flaxEngineAssembly.GetName().Name); + *assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName); return GCHandle.ToIntPtr(GetAssemblyHandle(flaxEngineAssembly)); } string assemblyPath = Marshal.PtrToStringAnsi(assemblyPath_); @@ -2120,8 +2161,8 @@ namespace FlaxEngine Assembly assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(assemblyPath); NativeLibrary.SetDllImportResolver(assembly, NativeLibraryImportResolver); - *assemblyName = Marshal.StringToCoTaskMemAnsi(assembly.GetName().Name); - *assemblyFullName = Marshal.StringToCoTaskMemAnsi(assembly.FullName); + *assemblyName = NativeAllocStringAnsi(assembly.GetName().Name); + *assemblyFullName = NativeAllocStringAnsi(assembly.FullName); return GCHandle.ToIntPtr(GetAssemblyHandle(assembly)); } @@ -2134,8 +2175,8 @@ namespace FlaxEngine firstAssemblyLoaded = true; Assembly flaxEngineAssembly = AppDomain.CurrentDomain.GetAssemblies().First(x => x.GetName().Name == "FlaxEngine.CSharp"); - *assemblyName = Marshal.StringToCoTaskMemAnsi(flaxEngineAssembly.GetName().Name); - *assemblyFullName = Marshal.StringToCoTaskMemAnsi(flaxEngineAssembly.FullName); + *assemblyName = NativeAllocStringAnsi(flaxEngineAssembly.GetName().Name); + *assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName); return GCHandle.ToIntPtr(GetAssemblyHandle(flaxEngineAssembly)); } @@ -2151,8 +2192,8 @@ namespace FlaxEngine // Assemblies loaded via streams have no Location: https://github.com/dotnet/runtime/issues/12822 AssemblyLocations.Add(assembly.FullName, assemblyPath); - *assemblyName = Marshal.StringToCoTaskMemAnsi(assembly.GetName().Name); - *assemblyFullName = Marshal.StringToCoTaskMemAnsi(assembly.FullName); + *assemblyName = NativeAllocStringAnsi(assembly.GetName().Name); + *assemblyFullName = NativeAllocStringAnsi(assembly.FullName); return GCHandle.ToIntPtr(GetAssemblyHandle(assembly)); } @@ -2164,15 +2205,15 @@ namespace FlaxEngine if (assembly == null) assembly = scriptingAssemblyLoadContext.Assemblies.FirstOrDefault(x => x.GetName().Name == name); - *assemblyName = Marshal.StringToCoTaskMemAnsi(assembly.GetName().Name); - *assemblyFullName = Marshal.StringToCoTaskMemAnsi(assembly.FullName); + *assemblyName = NativeAllocStringAnsi(assembly.GetName().Name); + *assemblyFullName = NativeAllocStringAnsi(assembly.FullName); return GCHandle.ToIntPtr(GetAssemblyHandle(assembly)); } [UnmanagedCallersOnly] internal static IntPtr GetRuntimeInformation() { - return Marshal.StringToCoTaskMemAnsi(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription); + return NativeAllocStringAnsi(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription); } [UnmanagedCallersOnly] diff --git a/Source/Engine/Scripting/DotNet/CoreCLR.cpp b/Source/Engine/Scripting/DotNet/CoreCLR.cpp index 5026dc805..0c9c9f7c6 100644 --- a/Source/Engine/Scripting/DotNet/CoreCLR.cpp +++ b/Source/Engine/Scripting/DotNet/CoreCLR.cpp @@ -129,12 +129,7 @@ void CoreCLR::RegisterNativeLibrary(const char* moduleName, const char* modulePa void* CoreCLR::Allocate(int size) { -#if PLATFORM_WINDOWS - void* ptr = CoTaskMemAlloc(size); -#else - void* ptr = malloc(size); -#endif - + void* ptr = Platform::Allocate(size, 16); #if COMPILE_WITH_PROFILER Platform::OnMemoryAlloc(ptr, size); #endif @@ -146,9 +141,5 @@ void CoreCLR::Free(void* ptr) #if COMPILE_WITH_PROFILER Platform::OnMemoryFree(ptr); #endif -#if PLATFORM_WINDOWS - CoTaskMemFree(ptr); -#else - free(ptr); -#endif + Platform::Free(ptr); }