From 8bd66495101e40bd6626a30d0c36227dd8b2d33f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 20 Sep 2023 14:17:11 +0200 Subject: [PATCH] Refactor managed array unboxing to handle case of C# array passes as object #1415 --- Source/Engine/Engine/NativeInterop.Unmanaged.cs | 13 +++++++++++++ Source/Engine/Scripting/ManagedCLR/MCore.h | 1 + Source/Engine/Scripting/ManagedCLR/MUtils.h | 5 +++-- Source/Engine/Scripting/Runtime/DotNet.cpp | 6 ++++++ Source/Engine/Scripting/Runtime/Mono.cpp | 5 +++++ Source/Engine/Scripting/Runtime/None.cpp | 5 +++++ 6 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index 670b7fff5..423aae6a5 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -559,6 +559,19 @@ namespace FlaxEngine.Interop return managedArray.Pointer; } + [UnmanagedCallersOnly] + internal static IntPtr GetArray(ManagedHandle handle) + { + if (!handle.IsAllocated) + return IntPtr.Zero; + object value = handle.Target; + if (value is ManagedArray) + return (IntPtr)handle; + if (value is Array) + return Invoker.MarshalReturnValueGeneric(value.GetType(), value); + return IntPtr.Zero; + } + [UnmanagedCallersOnly] internal static int GetArrayLength(ManagedHandle arrayHandle) { diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.h b/Source/Engine/Scripting/ManagedCLR/MCore.h index e1de3c207..7c61031c7 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.h +++ b/Source/Engine/Scripting/ManagedCLR/MCore.h @@ -85,6 +85,7 @@ public: static MClass* GetClass(MClass* elementKlass); static int32 GetLength(const MArray* obj); static void* GetAddress(const MArray* obj); + static MArray* Unbox(MObject* obj); template FORCE_INLINE static T* GetAddress(const MArray* obj) diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.h b/Source/Engine/Scripting/ManagedCLR/MUtils.h index 7b340e5c6..a9b2d8414 100644 --- a/Source/Engine/Scripting/ManagedCLR/MUtils.h +++ b/Source/Engine/Scripting/ManagedCLR/MUtils.h @@ -363,11 +363,12 @@ struct MConverter> void Unbox(Array& result, MObject* data) { - const int32 length = data ? MCore::Array::GetLength((MArray*)data) : 0; + MArray* array = MCore::Array::Unbox(data); + const int32 length = array ? MCore::Array::GetLength(array) : 0; result.Resize(length); MConverter converter; Span resultSpan(result.Get(), length); - converter.ToNativeArray(resultSpan, (MArray*)data); + converter.ToNativeArray(resultSpan, array); } }; diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 2157e8dff..c859fa961 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -408,6 +408,12 @@ void* MCore::Array::GetAddress(const MArray* obj) return CallStaticMethod(GetArrayPointerPtr, (void*)obj); } +MArray* MCore::Array::Unbox(MObject* obj) +{ + static void* GetArrayPtr = GetStaticMethodPointer(TEXT("GetArray")); + return (MArray*)CallStaticMethod(GetArrayPtr, (void*)obj); +} + MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned) { ASSERT(obj); diff --git a/Source/Engine/Scripting/Runtime/Mono.cpp b/Source/Engine/Scripting/Runtime/Mono.cpp index 0a60db42f..da21e90d0 100644 --- a/Source/Engine/Scripting/Runtime/Mono.cpp +++ b/Source/Engine/Scripting/Runtime/Mono.cpp @@ -804,6 +804,11 @@ void* MCore::Array::GetAddress(const MArray* obj) return mono_array_addr_with_size((MonoArray*)obj, 0, 0); } +MArray* MCore::Array::Unbox(MObject* obj) +{ + return (MArray*)obj; +} + MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned) { return mono_gchandle_new(obj, pinned); diff --git a/Source/Engine/Scripting/Runtime/None.cpp b/Source/Engine/Scripting/Runtime/None.cpp index ef9c118cf..39d85ad84 100644 --- a/Source/Engine/Scripting/Runtime/None.cpp +++ b/Source/Engine/Scripting/Runtime/None.cpp @@ -141,6 +141,11 @@ void* MCore::Array::GetAddress(const MArray* obj) return nullptr; } +MArray* MCore::Array::Unbox(MObject* obj) +{ + return nullptr; +} + MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned) { return (MGCHandle)(uintptr)obj;