From 1cfc382fe89ba9df3d9edc2de07fbc28e594193a Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Thu, 18 May 2023 13:44:36 +0200 Subject: [PATCH] C#: Mostly fix hash of ManagedCallable The hash can still change when reloading assemblies but in all other cases the result should be correct. --- .../GodotSharp/Core/Bridge/ManagedCallbacks.cs | 2 ++ .../GodotSharp/GodotSharp/Core/DelegateUtils.cs | 15 +++++++++++++++ modules/mono/managed_callable.cpp | 8 ++++---- modules/mono/mono_gd/gd_mono_cache.cpp | 1 + modules/mono/mono_gd/gd_mono_cache.h | 2 ++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs index 44ea8fc83df..03744fc4e34 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs @@ -11,6 +11,7 @@ namespace Godot.Bridge public delegate* unmanaged SignalAwaiter_SignalCallback; public delegate* unmanaged DelegateUtils_InvokeWithVariantArgs; public delegate* unmanaged DelegateUtils_DelegateEquals; + public delegate* unmanaged DelegateUtils_DelegateHash; public delegate* unmanaged DelegateUtils_TrySerializeDelegateWithGCHandle; public delegate* unmanaged DelegateUtils_TryDeserializeDelegateWithGCHandle; public delegate* unmanaged ScriptManagerBridge_FrameCallback; @@ -50,6 +51,7 @@ namespace Godot.Bridge SignalAwaiter_SignalCallback = &SignalAwaiter.SignalCallback, DelegateUtils_InvokeWithVariantArgs = &DelegateUtils.InvokeWithVariantArgs, DelegateUtils_DelegateEquals = &DelegateUtils.DelegateEquals, + DelegateUtils_DelegateHash = &DelegateUtils.DelegateHash, DelegateUtils_TrySerializeDelegateWithGCHandle = &DelegateUtils.TrySerializeDelegateWithGCHandle, DelegateUtils_TryDeserializeDelegateWithGCHandle = &DelegateUtils.TryDeserializeDelegateWithGCHandle, ScriptManagerBridge_FrameCallback = &ScriptManagerBridge.FrameCallback, diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs index 4a54f67cc9c..279dadf425f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs @@ -29,6 +29,21 @@ namespace Godot } } + [UnmanagedCallersOnly] + internal static int DelegateHash(IntPtr delegateGCHandle) + { + try + { + var @delegate = (Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target; + return @delegate?.GetHashCode() ?? 0; + } + catch (Exception e) + { + ExceptionUtils.LogException(e); + return 0; + } + } + [UnmanagedCallersOnly] internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, void* trampoline, godot_variant** args, int argc, godot_variant* outRet) diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp index 3e4eb5a9664..faf3ae7b045 100644 --- a/modules/mono/managed_callable.cpp +++ b/modules/mono/managed_callable.cpp @@ -43,10 +43,10 @@ bool ManagedCallable::compare_equal(const CallableCustom *p_a, const CallableCus const ManagedCallable *a = static_cast(p_a); const ManagedCallable *b = static_cast(p_b); + if (a->delegate_handle.value == b->delegate_handle.value) { + return true; + } if (!a->delegate_handle.value || !b->delegate_handle.value) { - if (!a->delegate_handle.value && !b->delegate_handle.value) { - return true; - } return false; } @@ -63,7 +63,7 @@ bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCust } uint32_t ManagedCallable::hash() const { - return hash_murmur3_one_64((uint64_t)delegate_handle.value); + return GDMonoCache::managed_callbacks.DelegateUtils_DelegateHash(delegate_handle); } String ManagedCallable::get_as_text() const { diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index 3ef7554a3fc..e254484df9d 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -52,6 +52,7 @@ void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) { CHECK_CALLBACK_NOT_NULL(SignalAwaiter, SignalCallback); CHECK_CALLBACK_NOT_NULL(DelegateUtils, InvokeWithVariantArgs); CHECK_CALLBACK_NOT_NULL(DelegateUtils, DelegateEquals); + CHECK_CALLBACK_NOT_NULL(DelegateUtils, DelegateHash); CHECK_CALLBACK_NOT_NULL(DelegateUtils, TrySerializeDelegateWithGCHandle); CHECK_CALLBACK_NOT_NULL(DelegateUtils, TryDeserializeDelegateWithGCHandle); CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, FrameCallback); diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index 2554dfff97b..b180d8133aa 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -76,6 +76,7 @@ struct ManagedCallbacks { using FuncSignalAwaiter_SignalCallback = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, int32_t, bool *); using FuncDelegateUtils_InvokeWithVariantArgs = void(GD_CLR_STDCALL *)(GCHandleIntPtr, void *, const Variant **, int32_t, const Variant *); using FuncDelegateUtils_DelegateEquals = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr); + using FuncDelegateUtils_DelegateHash = int32_t(GD_CLR_STDCALL *)(GCHandleIntPtr); using FuncDelegateUtils_TrySerializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const Array *); using FuncDelegateUtils_TryDeserializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(const Array *, GCHandleIntPtr *); using FuncScriptManagerBridge_FrameCallback = void(GD_CLR_STDCALL *)(); @@ -109,6 +110,7 @@ struct ManagedCallbacks { FuncSignalAwaiter_SignalCallback SignalAwaiter_SignalCallback; FuncDelegateUtils_InvokeWithVariantArgs DelegateUtils_InvokeWithVariantArgs; FuncDelegateUtils_DelegateEquals DelegateUtils_DelegateEquals; + FuncDelegateUtils_DelegateHash DelegateUtils_DelegateHash; FuncDelegateUtils_TrySerializeDelegateWithGCHandle DelegateUtils_TrySerializeDelegateWithGCHandle; FuncDelegateUtils_TryDeserializeDelegateWithGCHandle DelegateUtils_TryDeserializeDelegateWithGCHandle; FuncScriptManagerBridge_FrameCallback ScriptManagerBridge_FrameCallback;