diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index f17822e2c..9e871e2fb 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -48,7 +48,7 @@ namespace FlaxEngine.Interop #endif private static Dictionary classAttributesCacheCollectible = new(); private static Dictionary assemblyHandles = new(); - private static Dictionary _typeSizeCache = new(); + private static ConcurrentDictionary _typeSizeCache = new(); private static Dictionary loadedNativeLibraries = new(); internal static Dictionary libraryPaths = new(); @@ -1594,7 +1594,7 @@ namespace FlaxEngine.Interop private static IntPtr PinValue(T value) where T : struct { // Store the converted value in unmanaged memory so it will not be relocated by the garbage collector. - int size = GetTypeSize(typeof(T)); + int size = TypeHelpers.MarshalSize; uint index = Interlocked.Increment(ref pinnedAllocationsPointer) % (uint)pinnedAllocations.Length; ref (IntPtr ptr, int size) alloc = ref pinnedAllocations[index]; if (alloc.size < size) @@ -1727,25 +1727,36 @@ namespace FlaxEngine.Interop return tuple; } - internal static int GetTypeSize(Type type) + internal static class TypeHelpers { - if (!_typeSizeCache.TryGetValue(type, out var size)) + public static readonly int MarshalSize; + static TypeHelpers() { + Type type = typeof(T); try { var marshalType = type; if (type.IsEnum) marshalType = type.GetEnumUnderlyingType(); - size = Marshal.SizeOf(marshalType); + MarshalSize = Marshal.SizeOf(marshalType); } catch { // Workaround the issue where structure defined within generic type instance (eg. MyType.MyStruct) fails to get size // https://github.com/dotnet/runtime/issues/46426 - var obj = Activator.CreateInstance(type); - size = Marshal.SizeOf(obj); + var obj = RuntimeHelpers.GetUninitializedObject(type); + MarshalSize = Marshal.SizeOf(obj); } - _typeSizeCache.Add(type, size); + } + } + + internal static int GetTypeSize(Type type) + { + if (!_typeSizeCache.TryGetValue(type, out int size)) + { + var marshalSizeField = typeof(TypeHelpers<>).MakeGenericType(type).GetField(nameof(TypeHelpers.MarshalSize), BindingFlags.Static | BindingFlags.Public); + size = (int)marshalSizeField.GetValue(null); + _typeSizeCache.AddOrUpdate(type, size, (t, v) => size); } return size; }