summaryrefslogtreecommitdiff
path: root/modules/mono/glue
diff options
context:
space:
mode:
authorIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2021-12-28 23:25:16 +0100
committerIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2022-08-22 03:36:51 +0200
commit4d710bf659c0bea5b8f3d6ec65eda047bada0e02 (patch)
tree72868f86b8507eddf706004175865dbefa81972a /modules/mono/glue
parente5e7a795b14487e7eb0cfb011a8e0518769ce533 (diff)
C#: Add initial implementation of source generator for script members
This replaces the way we invoke methods and set/get properties. This first iteration rids us of runtime type checking in those cases, as it's now done at compile time. Later it will also stop needing the use of reflection. After that, we will only depend on reflection for generic Godot Array and Dictionary. We're stuck with reflection in generic collections for now as C# doesn't support generic/template specialization. This is only the initial implementation. Further iterations are coming, specially once we switch to the native extension system which completely changes the way members are accessed/invoked. For example, with the native extension system we will likely need to create `UnmanagedCallersOnly` invoke wrapper methods and return function pointers to the engine. Other kind of members, like event signals will be receiving the same treatment in the future.
Diffstat (limited to 'modules/mono/glue')
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs23
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs25
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs126
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs46
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj1
-rw-r--r--modules/mono/glue/runtime_interop.cpp4
8 files changed, 92 insertions, 145 deletions
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
deleted file mode 100644
index 0b00878e8c..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace Godot
-{
- /// <summary>
- /// An attribute that disables Godot Generators.
- /// </summary>
- [AttributeUsage(AttributeTargets.Class)]
- public class DisableGodotGeneratorsAttribute : Attribute { }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
index 6bb1ba27e9..f28d7b1c51 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
@@ -12,7 +12,6 @@ namespace Godot.Bridge
{
try
{
- // Performance is not critical here as this will be replaced with source generators.
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (godotObject == null)
@@ -27,7 +26,7 @@ namespace Godot.Bridge
using (dest)
methodStr = Marshaling.ConvertStringToManaged(dest);
- bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, new NativeVariantPtrArgs(args),
+ bool methodInvoked = godotObject.InvokeGodotClassMethod(CustomUnsafe.AsRef(method), new NativeVariantPtrArgs(args),
argCount, out godot_variant retValue);
if (!methodInvoked)
@@ -55,21 +54,19 @@ namespace Godot.Bridge
{
try
{
- // Performance is not critical here as this will be replaced with source generators.
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (godotObject == null)
throw new InvalidOperationException();
- var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
-
- if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(
- nameManaged.ToString(), CustomUnsafe.AsRef(value)))
+ if (godotObject.SetGodotClassPropertyValue(CustomUnsafe.AsRef(name), CustomUnsafe.AsRef(value)))
{
return true.ToGodotBool();
}
+ var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
+
object valueManaged = Marshaling.ConvertVariantToManagedObject(CustomUnsafe.AsRef(value));
return godotObject._Set(nameManaged, valueManaged).ToGodotBool();
@@ -87,22 +84,20 @@ namespace Godot.Bridge
{
try
{
- // Performance is not critical here as this will be replaced with source generators.
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (godotObject == null)
throw new InvalidOperationException();
- var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
-
- if (godotObject.InternalGodotScriptGetFieldOrPropViaReflection(nameManaged.ToString(),
- out godot_variant outRetValue))
+ if (godotObject.GetGodotClassPropertyValue(CustomUnsafe.AsRef(name), out godot_variant outRetValue))
{
*outRet = outRetValue;
return true.ToGodotBool();
}
+ var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
+
object ret = godotObject._Get(nameManaged);
if (ret == null)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
index ef20819d62..f15dc941c9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
@@ -487,6 +487,31 @@ namespace Godot.NativeInterop
get => _data == IntPtr.Zero;
}
+ public static bool operator ==(godot_string_name left, godot_string_name right)
+ {
+ return left._data == right._data;
+ }
+
+ public static bool operator !=(godot_string_name left, godot_string_name right)
+ {
+ return !(left == right);
+ }
+
+ public bool Equals(godot_string_name other)
+ {
+ return _data == other._data;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is StringName s && s.Equals(this);
+ }
+
+ public override int GetHashCode()
+ {
+ return _data.GetHashCode();
+ }
+
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
internal struct movable
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index f1cccfed0a..c2812b8919 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -26,7 +26,7 @@ namespace Godot.NativeInterop
[DllImport(GodotDllName)]
public static extern IntPtr godotsharp_method_bind_get_method(in godot_string_name p_classname,
- char* p_methodname);
+ in godot_string_name p_methodname);
[DllImport(GodotDllName)]
public static extern delegate* unmanaged<IntPtr> godotsharp_get_class_constructor(
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 5f4dc50c72..dbffd1d5d1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -185,125 +185,20 @@ namespace Godot
return assemblyName.Name == "GodotSharp" || assemblyName.Name == "GodotSharpEditor";
}
- internal bool InternalGodotScriptCallViaReflection(string method, NativeVariantPtrArgs args, int argCount,
- out godot_variant ret)
+ // ReSharper disable once VirtualMemberNeverOverridden.Global
+ protected internal virtual bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
{
- // Performance is not critical here as this will be replaced with source generators.
- Type top = GetType();
- Type native = InternalGetClassNativeBase(top);
-
- while (top != null && top != native)
- {
- var methodInfo = top.GetMethod(method,
- BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public);
-
- if (methodInfo != null)
- {
- var parameters = methodInfo.GetParameters();
- int paramCount = parameters.Length;
-
- if (argCount == paramCount)
- {
- object[] invokeParams = new object[paramCount];
-
- for (int i = 0; i < paramCount; i++)
- {
- invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType(
- args[i], parameters[i].ParameterType);
- }
-
- object retObj = methodInfo.Invoke(this, invokeParams);
-
- ret = Marshaling.ConvertManagedObjectToVariant(retObj);
- return true;
- }
- }
-
- top = top.BaseType;
- }
-
- ret = default;
- return false;
- }
-
- internal bool InternalGodotScriptSetFieldOrPropViaReflection(string name, in godot_variant value)
- {
- // Performance is not critical here as this will be replaced with source generators.
- Type top = GetType();
- Type native = InternalGetClassNativeBase(top);
-
- while (top != null && top != native)
- {
- var fieldInfo = top.GetField(name,
- BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public);
-
- if (fieldInfo != null)
- {
- object valueManaged = Marshaling.ConvertVariantToManagedObjectOfType(value, fieldInfo.FieldType);
- fieldInfo.SetValue(this, valueManaged);
-
- return true;
- }
-
- var propertyInfo = top.GetProperty(name,
- BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public);
-
- if (propertyInfo != null)
- {
- object valueManaged =
- Marshaling.ConvertVariantToManagedObjectOfType(value, propertyInfo.PropertyType);
- propertyInfo.SetValue(this, valueManaged);
-
- return true;
- }
-
- top = top.BaseType;
- }
-
return false;
}
- internal bool InternalGodotScriptGetFieldOrPropViaReflection(string name, out godot_variant value)
+ // ReSharper disable once VirtualMemberNeverOverridden.Global
+ protected internal virtual bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
{
- // Performance is not critical here as this will be replaced with source generators.
- Type top = GetType();
- Type native = InternalGetClassNativeBase(top);
-
- while (top != null && top != native)
- {
- var fieldInfo = top.GetField(name,
- BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public);
-
- if (fieldInfo != null)
- {
- object valueManaged = fieldInfo.GetValue(this);
- value = Marshaling.ConvertManagedObjectToVariant(valueManaged);
- return true;
- }
-
- var propertyInfo = top.GetProperty(name,
- BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public);
-
- if (propertyInfo != null)
- {
- object valueManaged = propertyInfo.GetValue(this);
- value = Marshaling.ConvertManagedObjectToVariant(valueManaged);
- return true;
- }
-
- top = top.BaseType;
- }
-
value = default;
return false;
}
- internal unsafe void InternalRaiseEventSignal(in godot_string_name eventSignalName, NativeVariantPtrArgs args,
+ internal void InternalRaiseEventSignal(in godot_string_name eventSignalName, NativeVariantPtrArgs args,
int argc)
{
// Performance is not critical here as this will be replaced with source generators.
@@ -371,14 +266,11 @@ namespace Godot
}
}
- internal static unsafe IntPtr ClassDB_get_method(StringName type, string method)
+ internal static IntPtr ClassDB_get_method(StringName type, StringName method)
{
- IntPtr methodBind;
- fixed (char* methodChars = method)
- {
- var typeSelf = (godot_string_name)type.NativeValue;
- methodBind = NativeFuncs.godotsharp_method_bind_get_method(typeSelf, methodChars);
- }
+ var typeSelf = (godot_string_name)type.NativeValue;
+ var methodSelf = (godot_string_name)method.NativeValue;
+ IntPtr methodBind = NativeFuncs.godotsharp_method_bind_get_method(typeSelf, methodSelf);
if (methodBind == IntPtr.Zero)
throw new NativeMethodBindNotFoundException(type + "." + method);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
index e8bda9b219..3a415d3deb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
@@ -92,5 +92,51 @@ namespace Godot
/// </summary>
/// <returns>If the <see cref="StringName"/> is empty.</returns>
public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty;
+
+ public static bool operator ==(StringName left, StringName right)
+ {
+ if (left is null)
+ return right is null;
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(StringName left, StringName right)
+ {
+ return !(left == right);
+ }
+
+ public bool Equals(StringName other)
+ {
+ if (other is null)
+ return false;
+ return NativeValue.DangerousSelfRef == other.NativeValue.DangerousSelfRef;
+ }
+
+ public static bool operator ==(StringName left, in godot_string_name right)
+ {
+ if (left is null)
+ return right.IsEmpty;
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(StringName left, in godot_string_name right)
+ {
+ return !(left == right);
+ }
+
+ public static bool operator ==(in godot_string_name left, StringName right)
+ {
+ return right == left;
+ }
+
+ public static bool operator !=(in godot_string_name left, StringName right)
+ {
+ return !(right == left);
+ }
+
+ public bool Equals(in godot_string_name other)
+ {
+ return NativeValue.DangerousSelfRef == other;
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index a06b448136..d5bbbfb7ca 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -32,7 +32,6 @@
<Compile Include="Core\AABB.cs" />
<Compile Include="Core\Array.cs" />
<Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />
- <Compile Include="Core\Attributes\DisableGodotGeneratorsAttribute.cs" />
<Compile Include="Core\Attributes\ExportAttribute.cs" />
<Compile Include="Core\Attributes\GodotMethodAttribute.cs" />
<Compile Include="Core\Attributes\RPCAttribute.cs" />
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
index c5db869a05..c3d4f53048 100644
--- a/modules/mono/glue/runtime_interop.cpp
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -65,8 +65,8 @@ static_assert(sizeof(SafeRefCount) == sizeof(uint32_t));
typedef Object *(*godotsharp_class_creation_func)();
-GD_PINVOKE_EXPORT MethodBind *godotsharp_method_bind_get_method(const StringName *p_classname, const char16_t *p_methodname) {
- return ClassDB::get_method(*p_classname, StringName(String::utf16(p_methodname)));
+GD_PINVOKE_EXPORT MethodBind *godotsharp_method_bind_get_method(const StringName *p_classname, const StringName *p_methodname) {
+ return ClassDB::get_method(*p_classname, *p_methodname);
}
GD_PINVOKE_EXPORT godotsharp_class_creation_func godotsharp_get_class_constructor(const StringName *p_classname) {