summaryrefslogtreecommitdiff
path: root/modules/mono/glue
diff options
context:
space:
mode:
authorIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2022-02-27 21:57:30 +0100
committerIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2022-08-22 03:36:51 +0200
commit92503ae8dbdf8f0f543dd785b79d3ec13b19092f (patch)
tree18e276bd75919eb701b625338b58af653821687e /modules/mono/glue
parent88e367a4066773a6fbfe2ea25dc2e81d2035d791 (diff)
C#: Add source generator for properties and exports default values
The editor no longer needs to create temporary instances to get the default values. The initializer values of the exported properties are still evaluated at runtime. For example, in the following example, `GetInitialValue()` will be called when first looks for default values: ``` [Export] int MyValue = GetInitialValue(); ``` Exporting fields with a non-supported type now results in a compiler error rather than a runtime error when the script is used.
Diffstat (limited to 'modules/mono/glue')
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs26
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs255
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs13
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj2
-rw-r--r--modules/mono/glue/runtime_interop.cpp74
9 files changed, 358 insertions, 46 deletions
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
index 46eb128d37..3d204bdf9f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
@@ -6,7 +6,7 @@ namespace Godot
/// An attribute used to export objects.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
- public class ExportAttribute : Attribute
+ public sealed class ExportAttribute : Attribute
{
private PropertyHint hint;
private string hintString;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
index fb1efa0ac8..7a6748b4eb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
@@ -24,6 +24,8 @@ namespace Godot.Bridge
public delegate* unmanaged<IntPtr, void> ScriptManagerBridge_RemoveScriptBridge;
public delegate* unmanaged<IntPtr, godot_bool*, godot_dictionary*, void> ScriptManagerBridge_UpdateScriptClassInfo;
public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
+ public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, godot_string*, void*, int, void>, void> ScriptManagerBridge_GetPropertyInfoList;
+ public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, void*, int, void>, void> ScriptManagerBridge_GetPropertyDefaultValues;
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_variant_call_error*, godot_variant*, godot_bool> CSharpInstanceBridge_Call;
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Set;
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Get;
@@ -57,6 +59,8 @@ namespace Godot.Bridge
ScriptManagerBridge_RemoveScriptBridge = &ScriptManagerBridge.RemoveScriptBridge,
ScriptManagerBridge_UpdateScriptClassInfo = &ScriptManagerBridge.UpdateScriptClassInfo,
ScriptManagerBridge_SwapGCHandleForType = &ScriptManagerBridge.SwapGCHandleForType,
+ ScriptManagerBridge_GetPropertyInfoList = &ScriptManagerBridge.GetPropertyInfoList,
+ ScriptManagerBridge_GetPropertyDefaultValues = &ScriptManagerBridge.GetPropertyDefaultValues,
CSharpInstanceBridge_Call = &CSharpInstanceBridge.Call,
CSharpInstanceBridge_Set = &CSharpInstanceBridge.Set,
CSharpInstanceBridge_Get = &CSharpInstanceBridge.Get,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
new file mode 100644
index 0000000000..cfdfe2dab3
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
@@ -0,0 +1,26 @@
+using System;
+using Godot.NativeInterop;
+
+namespace Godot.Bridge
+{
+ public struct PropertyInfo
+ {
+ public Variant.Type Type { get; init; }
+ public StringName Name { get; init; }
+ public PropertyHint Hint { get; init; }
+ public string HintString { get; init; }
+ public PropertyUsageFlags Usage { get; init; }
+ public bool Exported { get; init; }
+
+ public PropertyInfo(Variant.Type type, StringName name, PropertyHint hint, string hintString,
+ PropertyUsageFlags usage, bool exported)
+ {
+ Type = type;
+ Name = name;
+ Hint = hint;
+ HintString = hintString;
+ Usage = usage;
+ Exported = exported;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index b86ced55cb..8348598b65 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -1,6 +1,8 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using Godot.Collections;
@@ -523,7 +525,7 @@ namespace Godot.Bridge
Dictionary<string, Dictionary> rpcFunctions = new();
- Type top = _scriptBridgeMap[scriptPtr];
+ Type top = scriptType;
Type native = Object.InternalGetClassNativeBase(top);
while (top != null && top != native)
@@ -602,5 +604,256 @@ namespace Godot.Bridge
return false.ToGodotBool();
}
}
+
+ // ReSharper disable once InconsistentNaming
+ [SuppressMessage("ReSharper", "NotAccessedField.Local")]
+ [StructLayout(LayoutKind.Sequential)]
+ private ref struct godotsharp_property_info
+ {
+ // Careful with padding...
+ public godot_string_name Name; // Not owned
+ public godot_string HintString;
+ public int Type;
+ public int Hint;
+ public int Usage;
+ public godot_bool Exported;
+
+ public void Dispose()
+ {
+ HintString.Dispose();
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void GetPropertyInfoList(IntPtr scriptPtr,
+ delegate* unmanaged<IntPtr, godot_string*, void*, int, void> addPropInfoFunc)
+ {
+ try
+ {
+ Type scriptType = _scriptBridgeMap[scriptPtr];
+ GetPropertyInfoListForType(scriptType, scriptPtr, addPropInfoFunc);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ }
+ }
+
+ private static unsafe void GetPropertyInfoListForType(Type type, IntPtr scriptPtr,
+ delegate* unmanaged<IntPtr, godot_string*, void*, int, void> addPropInfoFunc)
+ {
+ try
+ {
+ var getGodotPropertiesMetadataMethod = type.GetMethod(
+ "GetGodotPropertiesMetadata",
+ BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (getGodotPropertiesMetadataMethod == null)
+ return;
+
+ var properties = (System.Collections.Generic.List<PropertyInfo>)
+ getGodotPropertiesMetadataMethod.Invoke(null, null);
+
+ if (properties == null || properties.Count <= 0)
+ return;
+
+ int length = properties.Count;
+
+ // There's no recursion here, so it's ok to go with a big enough number for most cases
+ // stackMaxSize = stackMaxLength * sizeof(godotsharp_property_info)
+ const int stackMaxLength = 32;
+ bool useStack = length < stackMaxLength;
+
+ godotsharp_property_info* interopProperties;
+
+ if (useStack)
+ {
+ // Weird limitation, hence the need for aux:
+ // "In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to initialize the variable."
+ var aux = stackalloc godotsharp_property_info[length];
+ interopProperties = aux;
+ }
+ else
+ {
+#if NET6_0_OR_GREATER
+ interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc(length))!;
+#else
+ interopProperties = ((godotsharp_property_info*)Marshal.AllocHGlobal(length))!;
+#endif
+ }
+
+ try
+ {
+ for (int i = 0; i < length; i++)
+ {
+ var property = properties[i];
+
+ godotsharp_property_info interopProperty = new()
+ {
+ Type = (int)property.Type,
+ Name = (godot_string_name)property.Name.NativeValue, // Not owned
+ Hint = (int)property.Hint,
+ HintString = Marshaling.ConvertStringToNative(property.HintString),
+ Usage = (int)property.Usage,
+ Exported = property.Exported.ToGodotBool()
+ };
+
+ interopProperties[i] = interopProperty;
+ }
+
+ using godot_string currentClassName = Marshaling.ConvertStringToNative(type.Name);
+
+ addPropInfoFunc(scriptPtr, &currentClassName, interopProperties, length);
+
+ // We're borrowing the StringName's without making an owning copy, so the
+ // managed collection needs to be kept alive until `addPropInfoFunc` returns.
+ GC.KeepAlive(properties);
+ }
+ finally
+ {
+ for (int i = 0; i < length; i++)
+ interopProperties[i].Dispose();
+
+ if (!useStack)
+ {
+#if NET6_0_OR_GREATER
+ NativeMemory.Free(interopProperties);
+#else
+ Marshal.FreeHGlobal((IntPtr)interopProperties);
+#endif
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ }
+ }
+
+ // ReSharper disable once InconsistentNaming
+ [SuppressMessage("ReSharper", "NotAccessedField.Local")]
+ [StructLayout(LayoutKind.Sequential)]
+ private ref struct godotsharp_property_def_val_pair
+ {
+ // Careful with padding...
+ public godot_string_name Name; // Not owned
+ public godot_variant Value;
+
+ public void Dispose()
+ {
+ Value.Dispose();
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void GetPropertyDefaultValues(IntPtr scriptPtr,
+ delegate* unmanaged<IntPtr, void*, int, void> addDefValFunc)
+ {
+ try
+ {
+ Type top = _scriptBridgeMap[scriptPtr];
+ Type native = Object.InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ GetPropertyDefaultValuesForType(top, scriptPtr, addDefValFunc);
+
+ top = top.BaseType;
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ }
+ }
+
+ [SkipLocalsInit]
+ private static unsafe void GetPropertyDefaultValuesForType(Type type, IntPtr scriptPtr,
+ delegate* unmanaged<IntPtr, void*, int, void> addDefValFunc)
+ {
+ try
+ {
+ var getGodotPropertyDefaultValuesMethod = type.GetMethod(
+ "GetGodotPropertyDefaultValues",
+ BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (getGodotPropertyDefaultValuesMethod == null)
+ return;
+
+ var defaultValues = (System.Collections.Generic.Dictionary<StringName, object>)
+ getGodotPropertyDefaultValuesMethod.Invoke(null, null);
+
+ if (defaultValues == null || defaultValues.Count <= 0)
+ return;
+
+ int length = defaultValues.Count;
+
+ // There's no recursion here, so it's ok to go with a big enough number for most cases
+ // stackMaxSize = stackMaxLength * sizeof(godotsharp_property_def_val_pair)
+ const int stackMaxLength = 32;
+ bool useStack = length < stackMaxLength;
+
+ godotsharp_property_def_val_pair* interopDefaultValues;
+
+ if (useStack)
+ {
+ // Weird limitation, hence the need for aux:
+ // "In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to initialize the variable."
+ var aux = stackalloc godotsharp_property_def_val_pair[length];
+ interopDefaultValues = aux;
+ }
+ else
+ {
+#if NET6_0_OR_GREATER
+ interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc(length))!;
+#else
+ interopDefaultValues = ((godotsharp_property_def_val_pair*)Marshal.AllocHGlobal(length))!;
+#endif
+ }
+
+ try
+ {
+ int i = 0;
+ foreach (var defaultValuePair in defaultValues)
+ {
+ godotsharp_property_def_val_pair interopProperty = new()
+ {
+ Name = (godot_string_name)defaultValuePair.Key.NativeValue, // Not owned
+ Value = Marshaling.ConvertManagedObjectToVariant(defaultValuePair.Value)
+ };
+
+ interopDefaultValues[i] = interopProperty;
+
+ i++;
+ }
+
+ addDefValFunc(scriptPtr, interopDefaultValues, length);
+
+ // We're borrowing the StringName's without making an owning copy, so the
+ // managed collection needs to be kept alive until `addDefValFunc` returns.
+ GC.KeepAlive(defaultValues);
+ }
+ finally
+ {
+ for (int i = 0; i < length; i++)
+ interopDefaultValues[i].Dispose();
+
+ if (!useStack)
+ {
+#if NET6_0_OR_GREATER
+ NativeMemory.Free(interopDefaultValues);
+#else
+ Marshal.FreeHGlobal((IntPtr)interopDefaultValues);
+#endif
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ }
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
deleted file mode 100644
index 733a8ac114..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Godot
-{
- internal static class MarshalUtils
- {
- /// <summary>
- /// Returns <see langword="true"/> if the <see cref="FlagsAttribute"/> is applied to the given type.
- /// </summary>
- private static bool TypeHasFlagsAttribute(Type type) => type.IsDefined(typeof(FlagsAttribute), false);
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index c2812b8919..01add1bf45 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -36,10 +36,13 @@ namespace Godot.NativeInterop
public static extern IntPtr godotsharp_engine_get_singleton(in godot_string p_name);
[DllImport(GodotDllName)]
- internal static extern void godotsharp_internal_object_disposed(IntPtr ptr);
+ internal static extern IntPtr godotsharp_internal_object_get_associated_gchandle(IntPtr ptr);
[DllImport(GodotDllName)]
- internal static extern void godotsharp_internal_refcounted_disposed(IntPtr ptr, godot_bool isFinalizer);
+ internal static extern void godotsharp_internal_object_disposed(IntPtr ptr, IntPtr gcHandleToFree);
+
+ [DllImport(GodotDllName)]
+ internal static extern void godotsharp_internal_refcounted_disposed(IntPtr ptr, IntPtr gcHandleToFree, godot_bool isFinalizer);
[DllImport(GodotDllName)]
internal static extern void godotsharp_internal_object_connect_event_signal(IntPtr obj,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 6255ffbbc7..71a620716f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Reflection;
+using System.Runtime.InteropServices;
using Godot.NativeInterop;
namespace Godot
@@ -121,23 +122,35 @@ namespace Godot
if (_disposed)
return;
+ _disposed = true;
+
if (NativePtr != IntPtr.Zero)
{
+ IntPtr gcHandleToFree = NativeFuncs.godotsharp_internal_object_get_associated_gchandle(NativePtr);
+
+ if (gcHandleToFree != IntPtr.Zero)
+ {
+ object target = GCHandle.FromIntPtr(gcHandleToFree).Target;
+ // The GC handle may have been replaced in another thread. Release it only if
+ // it's associated to this managed instance, or if the target is no longer alive.
+ if (target != this && target != null)
+ gcHandleToFree = IntPtr.Zero;
+ }
+
if (_memoryOwn)
{
- NativeFuncs.godotsharp_internal_refcounted_disposed(NativePtr, (!disposing).ToGodotBool());
+ NativeFuncs.godotsharp_internal_refcounted_disposed(NativePtr, gcHandleToFree,
+ (!disposing).ToGodotBool());
}
else
{
- NativeFuncs.godotsharp_internal_object_disposed(NativePtr);
+ NativeFuncs.godotsharp_internal_object_disposed(NativePtr, gcHandleToFree);
}
NativePtr = IntPtr.Zero;
}
DisposablesTracker.UnregisterGodotObject(_weakReferenceToSelf);
-
- _disposed = true;
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index b7fbb81f9c..8b0c421829 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -41,6 +41,7 @@
<Compile Include="Core\Bridge\CSharpInstanceBridge.cs" />
<Compile Include="Core\Bridge\GCHandleBridge.cs" />
<Compile Include="Core\Bridge\ManagedCallbacks.cs" />
+ <Compile Include="Core\Bridge\PropertyInfo.cs" />
<Compile Include="Core\Bridge\ScriptManagerBridge.cs" />
<Compile Include="Core\Callable.cs" />
<Compile Include="Core\Color.cs" />
@@ -63,7 +64,6 @@
<Compile Include="Core\Interfaces\IAwaitable.cs" />
<Compile Include="Core\Interfaces\IAwaiter.cs" />
<Compile Include="Core\Interfaces\ISerializationListener.cs" />
- <Compile Include="Core\MarshalUtils.cs" />
<Compile Include="Core\Mathf.cs" />
<Compile Include="Core\MathfEx.cs" />
<Compile Include="Core\NativeInterop\ExceptionUtils.cs" />
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
index c3d4f53048..7150e2e35b 100644
--- a/modules/mono/glue/runtime_interop.cpp
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -81,7 +81,7 @@ GD_PINVOKE_EXPORT Object *godotsharp_engine_get_singleton(const String *p_name)
return Engine::get_singleton()->get_singleton_object(*p_name);
}
-GD_PINVOKE_EXPORT void godotsharp_internal_object_disposed(Object *p_ptr) {
+GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_object_get_associated_gchandle(Object *p_ptr) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_ptr == nullptr);
#endif
@@ -90,7 +90,35 @@ GD_PINVOKE_EXPORT void godotsharp_internal_object_disposed(Object *p_ptr) {
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
if (cs_instance) {
if (!cs_instance->is_destructing_script_instance()) {
- cs_instance->mono_object_disposed();
+ return cs_instance->get_gchandle_intptr();
+ }
+ return { nullptr };
+ }
+ }
+
+ void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
+
+ if (data) {
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
+ if (script_binding.inited) {
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+ return !gchandle.is_released() ? gchandle.get_intptr() : GCHandleIntPtr{ nullptr };
+ }
+ }
+
+ return { nullptr };
+}
+
+GD_PINVOKE_EXPORT void godotsharp_internal_object_disposed(Object *p_ptr, GCHandleIntPtr p_gchandle_to_free) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(p_ptr == nullptr);
+#endif
+
+ if (p_ptr->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
+ if (cs_instance) {
+ if (!cs_instance->is_destructing_script_instance()) {
+ cs_instance->mono_object_disposed(p_gchandle_to_free);
p_ptr->set_script_instance(nullptr);
}
return;
@@ -102,16 +130,14 @@ GD_PINVOKE_EXPORT void godotsharp_internal_object_disposed(Object *p_ptr) {
if (data) {
CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited) {
- MonoGCHandleData &gchandle = script_binding.gchandle;
- if (!gchandle.is_released()) {
- CSharpLanguage::release_script_gchandle(nullptr, gchandle);
- script_binding.inited = false;
+ if (!script_binding.gchandle.is_released()) {
+ CSharpLanguage::release_binding_gchandle_thread_safe(p_gchandle_to_free, script_binding);
}
}
}
}
-GD_PINVOKE_EXPORT void godotsharp_internal_refcounted_disposed(Object *p_ptr, bool p_is_finalizer) {
+GD_PINVOKE_EXPORT void godotsharp_internal_refcounted_disposed(Object *p_ptr, GCHandleIntPtr p_gchandle_to_free, bool p_is_finalizer) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_ptr == nullptr);
// This is only called with RefCounted derived classes
@@ -127,7 +153,8 @@ GD_PINVOKE_EXPORT void godotsharp_internal_refcounted_disposed(Object *p_ptr, bo
bool delete_owner;
bool remove_script_instance;
- cs_instance->mono_object_disposed_baseref(p_is_finalizer, delete_owner, remove_script_instance);
+ cs_instance->mono_object_disposed_baseref(p_gchandle_to_free, p_is_finalizer,
+ delete_owner, remove_script_instance);
if (delete_owner) {
memdelete(rc);
@@ -150,10 +177,8 @@ GD_PINVOKE_EXPORT void godotsharp_internal_refcounted_disposed(Object *p_ptr, bo
if (data) {
CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited) {
- MonoGCHandleData &gchandle = script_binding.gchandle;
- if (!gchandle.is_released()) {
- CSharpLanguage::release_script_gchandle(nullptr, gchandle);
- script_binding.inited = false;
+ if (!script_binding.gchandle.is_released()) {
+ CSharpLanguage::release_binding_gchandle_thread_safe(p_gchandle_to_free, script_binding);
}
}
}
@@ -188,7 +213,7 @@ GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_unmanaged_get_script_instan
}
*r_has_cs_script_instance = false;
- return GCHandleIntPtr();
+ return { nullptr };
}
GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(Object *p_unmanaged) {
@@ -197,9 +222,9 @@ GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_unmanaged_get_instance_bind
#endif
void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
- ERR_FAIL_NULL_V(data, GCHandleIntPtr());
+ ERR_FAIL_NULL_V(data, { nullptr });
CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
- ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
+ ERR_FAIL_COND_V(!script_binding.inited, { nullptr });
return script_binding.gchandle.get_intptr();
}
@@ -210,9 +235,9 @@ GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_unmanaged_instance_binding_
#endif
void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
- ERR_FAIL_NULL_V(data, GCHandleIntPtr());
+ ERR_FAIL_NULL_V(data, { nullptr });
CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
- ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
+ ERR_FAIL_COND_V(!script_binding.inited, { nullptr });
MonoGCHandleData &gchandle = script_binding.gchandle;
@@ -229,14 +254,14 @@ GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_unmanaged_instance_binding_
#endif
bool parent_is_object_class = ClassDB::is_parent_class(p_unmanaged->get_class_name(), script_binding.type_name);
- ERR_FAIL_COND_V_MSG(!parent_is_object_class, GCHandleIntPtr(),
+ ERR_FAIL_COND_V_MSG(!parent_is_object_class, { nullptr },
"Type inherits from native type '" + script_binding.type_name + "', so it can't be instantiated in object of type: '" + p_unmanaged->get_class() + "'.");
GCHandleIntPtr strong_gchandle =
GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectBinding(
&script_binding.type_name, p_unmanaged);
- ERR_FAIL_NULL_V(strong_gchandle.value, GCHandleIntPtr());
+ ERR_FAIL_NULL_V(strong_gchandle.value, { nullptr });
gchandle = MonoGCHandleData(strong_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
script_binding.inited = true;
@@ -420,25 +445,25 @@ GD_PINVOKE_EXPORT bool godotsharp_callable_get_data_for_marshalling(const Callab
return true;
} else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) {
SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom);
- *r_delegate_handle = GCHandleIntPtr();
+ *r_delegate_handle = { nullptr };
*r_object = ObjectDB::get_instance(signal_awaiter_callable->get_object());
memnew_placement(r_name, StringName(signal_awaiter_callable->get_signal()));
return true;
} else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) {
EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom);
- *r_delegate_handle = GCHandleIntPtr();
+ *r_delegate_handle = { nullptr };
*r_object = ObjectDB::get_instance(event_signal_callable->get_object());
memnew_placement(r_name, StringName(event_signal_callable->get_signal()));
return true;
}
// Some other CallableCustom. We only support ManagedCallable.
- *r_delegate_handle = GCHandleIntPtr();
+ *r_delegate_handle = { nullptr };
*r_object = nullptr;
memnew_placement(r_name, StringName());
return false;
} else {
- *r_delegate_handle = GCHandleIntPtr();
+ *r_delegate_handle = { nullptr };
*r_object = ObjectDB::get_instance(p_callable->get_object_id());
memnew_placement(r_name, StringName(p_callable->get_method()));
return true;
@@ -1256,10 +1281,11 @@ GD_PINVOKE_EXPORT void godotsharp_object_to_string(Object *p_ptr, godot_string *
#endif
// We need this to prevent the functions from being stripped.
-void *godotsharp_pinvoke_funcs[178] = {
+void *godotsharp_pinvoke_funcs[179] = {
(void *)godotsharp_method_bind_get_method,
(void *)godotsharp_get_class_constructor,
(void *)godotsharp_engine_get_singleton,
+ (void *)godotsharp_internal_object_get_associated_gchandle,
(void *)godotsharp_internal_object_disposed,
(void *)godotsharp_internal_refcounted_disposed,
(void *)godotsharp_internal_object_connect_event_signal,