diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index e002e460abd..8a5be781026 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1465,7 +1465,7 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { GDMonoProperty *property = top->get_property(p_name); if (property) { - property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value, property->get_type())); + property->set_value_from_variant(mono_object, p_value); return true; } @@ -2479,7 +2479,7 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) { // Arguments are accessibles as arguments of .Invoke method - GDMonoMethod *invoke = p_delegate->get_method("Invoke", -1); + GDMonoMethod *invoke = p_delegate->get_method(mono_get_delegate_invoke(p_delegate->get_mono_ptr())); Vector names; Vector types; diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index b144bb5a93c..d0cb7162ee0 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -278,7 +278,7 @@ bool GDMonoClass::has_public_parameterless_ctor() { return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC; } -GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) { +GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_params_count) { MethodKey key = MethodKey(p_name, p_params_count); GDMonoMethod **match = methods.getptr(key); @@ -316,7 +316,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName return get_method(p_raw_method, p_name, params_count); } -GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count) { +GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count) { ERR_FAIL_NULL_V(p_raw_method, NULL); MethodKey key = MethodKey(p_name, p_params_count); diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index 898c55a0a3c..3b09338016b 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -59,13 +59,13 @@ class GDMonoClass { MethodKey() {} - MethodKey(const StringName &p_name, int p_params_count) { + MethodKey(const StringName &p_name, uint16_t p_params_count) { name = p_name; params_count = p_params_count; } StringName name; - int params_count; + uint16_t params_count; }; StringName namespace_name; @@ -139,10 +139,10 @@ public: bool implements_interface(GDMonoClass *p_interface); bool has_public_parameterless_ctor(); - GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0); + GDMonoMethod *get_method(const StringName &p_name, uint16_t p_params_count = 0); GDMonoMethod *get_method(MonoMethod *p_raw_method); GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name); - GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count); + GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count); GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace); GDMonoField *get_field(const StringName &p_name); diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 4617068c954..b237ac24177 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -42,29 +42,15 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) { } void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) { -#define SET_FROM_STRUCT(m_type) \ - { \ - GDMonoMarshal::M_##m_type from = MARSHALLED_OUT(m_type, p_value.operator ::m_type()); \ - mono_field_set_value(p_object, mono_field, &from); \ - } - -#define SET_FROM_ARRAY(m_type) \ - { \ - MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \ - mono_field_set_value(p_object, mono_field, managed); \ - } - switch (type.type_encoding) { case MONO_TYPE_BOOLEAN: { MonoBoolean val = p_value.operator bool(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_CHAR: { int16_t val = p_value.operator unsigned short(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_I1: { int8_t val = p_value.operator signed char(); mono_field_set_value(p_object, mono_field, &val); @@ -81,7 +67,6 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ int64_t val = p_value.operator int64_t(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_U1: { uint8_t val = p_value.operator unsigned char(); mono_field_set_value(p_object, mono_field, &val); @@ -98,78 +83,74 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ uint64_t val = p_value.operator uint64_t(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_R4: { float val = p_value.operator float(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_R8: { double val = p_value.operator double(); mono_field_set_value(p_object, mono_field, &val); } break; - - case MONO_TYPE_STRING: { - if (p_value.get_type() == Variant::NIL) { - // Otherwise, Variant -> String would return the string "Null" - MonoString *mono_string = NULL; - mono_field_set_value(p_object, mono_field, mono_string); - } else { - MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value); - mono_field_set_value(p_object, mono_field, mono_string); - } - } break; - case MONO_TYPE_VALUETYPE: { GDMonoClass *tclass = type.type_class; if (tclass == CACHED_CLASS(Vector2)) { - SET_FROM_STRUCT(Vector2); + GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Rect2)) { - SET_FROM_STRUCT(Rect2); + GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Transform2D)) { - SET_FROM_STRUCT(Transform2D); + GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Vector3)) { - SET_FROM_STRUCT(Vector3); + GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Basis)) { - SET_FROM_STRUCT(Basis); + GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Quat)) { - SET_FROM_STRUCT(Quat); + GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Transform)) { - SET_FROM_STRUCT(Transform); + GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(AABB)) { - SET_FROM_STRUCT(AABB); + GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Color)) { - SET_FROM_STRUCT(Color); + GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Plane)) { - SET_FROM_STRUCT(Plane); + GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); + mono_field_set_value(p_object, mono_field, &from); break; } @@ -236,112 +217,35 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + tclass->get_name() + "'."); } break; - + case MONO_TYPE_STRING: { + if (p_value.get_type() == Variant::NIL) { + // Otherwise, Variant -> String would return the string "Null" + MonoString *mono_string = NULL; + mono_field_set_value(p_object, mono_field, mono_string); + } else { + MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value); + mono_field_set_value(p_object, mono_field, mono_string); + } + } break; case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type()); - - if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { - SET_FROM_ARRAY(Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { - SET_FROM_ARRAY(PoolByteArray); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { - SET_FROM_ARRAY(PoolIntArray); - break; - } - - if (array_type->eklass == REAL_T_MONOCLASS) { - SET_FROM_ARRAY(PoolRealArray); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(String)) { - SET_FROM_ARRAY(PoolStringArray); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { - SET_FROM_ARRAY(PoolVector2Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { - SET_FROM_ARRAY(PoolVector3Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(Color)) { - SET_FROM_ARRAY(PoolColorArray); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) { - SET_FROM_ARRAY(Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(RID)) { - SET_FROM_ARRAY(Array); - break; - } - - GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); - if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) { - MonoArray *managed = GDMonoMarshal::Array_to_mono_array(p_value.operator ::Array(), array_type_class); + MonoArray *managed = GDMonoMarshal::variant_to_mono_array(p_value, type.type_class); + if (likely(managed != nullptr)) { mono_field_set_value(p_object, mono_field, managed); - break; } - - ERR_FAIL_MSG("Attempted to convert Variant to a managed array of unmarshallable element type."); } break; - case MONO_TYPE_CLASS: { - GDMonoClass *type_class = type.type_class; - - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *()); + MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_class(p_value, type.type_class); + if (likely(managed != nullptr)) { + mono_field_set_value(p_object, mono_field, managed); + } + } break; + case MONO_TYPE_GENERICINST: { + MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_genericinst(p_value, type.type_class); + if (likely(managed != nullptr)) { mono_field_set_value(p_object, mono_field, managed); - break; } - - if (CACHED_CLASS(NodePath) == type_class) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath()); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - if (CACHED_CLASS(RID) == type_class) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator RID()); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // Godot.Collections.Dictionary or IDictionary - if (CACHED_CLASS(Dictionary) == type_class || type_class == CACHED_CLASS(System_Collections_IDictionary)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary)); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // Godot.Collections.Array or ICollection or IEnumerable - if (CACHED_CLASS(Array) == type_class || - type_class == CACHED_CLASS(System_Collections_ICollection) || - type_class == CACHED_CLASS(System_Collections_IEnumerable)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + type_class->get_name() + "'."); } break; - case MONO_TYPE_OBJECT: { // Variant switch (p_value.get_type()) { @@ -367,34 +271,44 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ mono_field_set_value(p_object, mono_field, mono_string); } break; case Variant::VECTOR2: { - SET_FROM_STRUCT(Vector2); + GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::RECT2: { - SET_FROM_STRUCT(Rect2); + GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::VECTOR3: { - SET_FROM_STRUCT(Vector3); + GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::TRANSFORM2D: { - SET_FROM_STRUCT(Transform2D); + GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::PLANE: { - SET_FROM_STRUCT(Plane); + GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::QUAT: { - SET_FROM_STRUCT(Quat); + GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::AABB: { - SET_FROM_STRUCT(AABB); + GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::BASIS: { - SET_FROM_STRUCT(Basis); + GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::TRANSFORM: { - SET_FROM_STRUCT(Transform); + GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::COLOR: { - SET_FROM_STRUCT(Color); + GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::NODE_PATH: { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath()); @@ -418,107 +332,41 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ mono_field_set_value(p_object, mono_field, managed); } break; case Variant::POOL_BYTE_ARRAY: { - SET_FROM_ARRAY(PoolByteArray); + MonoArray *managed = GDMonoMarshal::PoolByteArray_to_mono_array(p_value.operator ::PoolByteArray()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::POOL_INT_ARRAY: { - SET_FROM_ARRAY(PoolIntArray); + MonoArray *managed = GDMonoMarshal::PoolIntArray_to_mono_array(p_value.operator ::PoolIntArray()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::POOL_REAL_ARRAY: { - SET_FROM_ARRAY(PoolRealArray); + MonoArray *managed = GDMonoMarshal::PoolRealArray_to_mono_array(p_value.operator ::PoolRealArray()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::POOL_STRING_ARRAY: { - SET_FROM_ARRAY(PoolStringArray); + MonoArray *managed = GDMonoMarshal::PoolStringArray_to_mono_array(p_value.operator ::PoolStringArray()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::POOL_VECTOR2_ARRAY: { - SET_FROM_ARRAY(PoolVector2Array); + MonoArray *managed = GDMonoMarshal::PoolVector2Array_to_mono_array(p_value.operator ::PoolVector2Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::POOL_VECTOR3_ARRAY: { - SET_FROM_ARRAY(PoolVector3Array); + MonoArray *managed = GDMonoMarshal::PoolVector3Array_to_mono_array(p_value.operator ::PoolVector3Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::POOL_COLOR_ARRAY: { - SET_FROM_ARRAY(PoolColorArray); + MonoArray *managed = GDMonoMarshal::PoolColorArray_to_mono_array(p_value.operator ::PoolColorArray()); + mono_field_set_value(p_object, mono_field, managed); } break; default: break; } } break; - - case MONO_TYPE_GENERICINST: { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type()); - - // Godot.Collections.Dictionary - if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // Godot.Collections.Array - if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // System.Collections.Generic.Dictionary - if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { - MonoReflectionType *key_reftype = nullptr; - MonoReflectionType *value_reftype = nullptr; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - MonoObject *managed = GDMonoMarshal::Dictionary_to_system_generic_dict(p_value.operator Dictionary(), - type.type_class, key_reftype, value_reftype); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // System.Collections.Generic.List - if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { - MonoReflectionType *elem_reftype = nullptr; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - MonoObject *managed = GDMonoMarshal::Array_to_system_generic_list(p_value.operator Array(), - type.type_class, elem_reftype); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // IDictionary - if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { - MonoReflectionType *key_reftype; - MonoReflectionType *value_reftype; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); - - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), godot_dict_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // ICollection or IEnumerable - if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { - MonoReflectionType *elem_reftype; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); - - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), godot_array_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // GodotObject - GDMonoClass *type_class = type.type_class; - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *()); - mono_field_set_value(p_object, mono_field, managed); - } - } break; - default: { ERR_PRINT("Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding) + "."); } break; } - -#undef SET_FROM_ARRAY_AND_BREAK -#undef SET_FROM_STRUCT_AND_BREAK } MonoObject *GDMonoField::get_value(MonoObject *p_object) { diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 434b24c55e9..b651b04f88e 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -323,408 +323,611 @@ String mono_to_utf16_string(MonoString *p_mono_string) { return ret; } -MonoObject *variant_to_mono_object(const Variant *p_var) { - ManagedType type; - - type.type_encoding = MONO_TYPE_OBJECT; - // type.type_class is not needed when we specify the MONO_TYPE_OBJECT encoding - - return variant_to_mono_object(p_var, type); +MonoString *variant_to_mono_string(const Variant &p_var) { + if (p_var.get_type() == Variant::NIL) { + return NULL; // Otherwise, Variant -> String would return the string "Null" + } + return mono_string_from_godot(p_var.operator String()); } -MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) { - switch (p_type.type_encoding) { - case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_var->operator bool(); +MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class) { + MonoArrayType *array_type = mono_type_get_array_type(p_type_class->get_mono_type()); + + if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { + return Array_to_mono_array(p_var.operator Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { + return PoolByteArray_to_mono_array(p_var.operator PoolByteArray()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { + return PoolIntArray_to_mono_array(p_var.operator PoolIntArray()); + } + + if (array_type->eklass == REAL_T_MONOCLASS) { + return PoolRealArray_to_mono_array(p_var.operator PoolRealArray()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(String)) { + return PoolStringArray_to_mono_array(p_var.operator PoolStringArray()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { + return PoolVector2Array_to_mono_array(p_var.operator PoolVector2Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { + return PoolVector3Array_to_mono_array(p_var.operator PoolVector3Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(Color)) { + return PoolColorArray_to_mono_array(p_var.operator PoolColorArray()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) { + return Array_to_mono_array(p_var.operator Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(RID)) { + return Array_to_mono_array(p_var.operator Array()); + } + + if (mono_class_is_assignable_from(CACHED_CLASS(GodotObject)->get_mono_ptr(), array_type->eklass)) { + return Array_to_mono_array(p_var.operator ::Array(), array_type->eklass); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to array of unsupported element type:" + GDMonoClass::get_full_name(array_type->eklass) + "'."); +} + +MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class) { + // GodotObject + if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) { + return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); + } + + if (CACHED_CLASS(NodePath) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator NodePath()); + } + + if (CACHED_CLASS(RID) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator ::RID()); + } + + // Godot.Collections.Dictionary or IDictionary + if (CACHED_CLASS(Dictionary) == p_type_class || CACHED_CLASS(System_Collections_IDictionary) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary)); + } + + // Godot.Collections.Array or ICollection or IEnumerable + if (CACHED_CLASS(Array) == p_type_class || + CACHED_CLASS(System_Collections_ICollection) == p_type_class || + CACHED_CLASS(System_Collections_IEnumerable) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array)); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type: '" + p_type_class->get_full_name() + "'."); +} + +MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class) { + MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type_class->get_mono_type()); + + // Godot.Collections.Dictionary + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), p_type_class); + } + + // Godot.Collections.Array + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { + return GDMonoUtils::create_managed_from(p_var.operator Array(), p_type_class); + } + + // System.Collections.Generic.Dictionary + if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { + MonoReflectionType *key_reftype = nullptr; + MonoReflectionType *value_reftype = nullptr; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + return Dictionary_to_system_generic_dict(p_var.operator Dictionary(), p_type_class, key_reftype, value_reftype); + } + + // System.Collections.Generic.List + if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { + MonoReflectionType *elem_reftype = nullptr; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + return Array_to_system_generic_list(p_var.operator Array(), p_type_class, elem_reftype); + } + + // IDictionary + if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { + MonoReflectionType *key_reftype; + MonoReflectionType *value_reftype; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); + + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), godot_dict_class); + } + + // ICollection or IEnumerable + if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { + MonoReflectionType *elem_reftype; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); + + return GDMonoUtils::create_managed_from(p_var.operator Array(), godot_array_class); + } + + // GodotObject + if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) { + return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported generic type: '" + p_type_class->get_full_name() + "'."); +} + +MonoObject *variant_to_mono_object(const Variant &p_var) { + // Variant + switch (p_var.get_type()) { + case Variant::BOOL: { + MonoBoolean val = p_var.operator bool(); return BOX_BOOLEAN(val); } - - case MONO_TYPE_CHAR: { - uint16_t val = p_var->operator unsigned short(); - return BOX_UINT16(val); - } - - case MONO_TYPE_I1: { - int8_t val = p_var->operator signed char(); - return BOX_INT8(val); - } - case MONO_TYPE_I2: { - int16_t val = p_var->operator signed short(); - return BOX_INT16(val); - } - case MONO_TYPE_I4: { - int32_t val = p_var->operator signed int(); + case Variant::INT: { + int32_t val = p_var.operator signed int(); return BOX_INT32(val); } - case MONO_TYPE_I8: { - int64_t val = p_var->operator int64_t(); - return BOX_INT64(val); - } - - case MONO_TYPE_U1: { - uint8_t val = p_var->operator unsigned char(); - return BOX_UINT8(val); - } - case MONO_TYPE_U2: { - uint16_t val = p_var->operator unsigned short(); - return BOX_UINT16(val); - } - case MONO_TYPE_U4: { - uint32_t val = p_var->operator unsigned int(); - return BOX_UINT32(val); - } - case MONO_TYPE_U8: { - uint64_t val = p_var->operator uint64_t(); - return BOX_UINT64(val); - } - - case MONO_TYPE_R4: { - float val = p_var->operator float(); - return BOX_FLOAT(val); - } - case MONO_TYPE_R8: { - double val = p_var->operator double(); + case Variant::REAL: { +#ifdef REAL_T_IS_DOUBLE + double val = p_var.operator double(); return BOX_DOUBLE(val); +#else + float val = p_var.operator float(); + return BOX_FLOAT(val); +#endif } + case Variant::STRING: + return (MonoObject *)mono_string_from_godot(p_var.operator String()); + case Variant::VECTOR2: { + GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var.operator ::Vector2()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); + } + case Variant::RECT2: { + GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var.operator ::Rect2()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); + } + case Variant::VECTOR3: { + GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var.operator ::Vector3()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); + } + case Variant::TRANSFORM2D: { + GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var.operator ::Transform2D()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); + } + case Variant::PLANE: { + GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); + } + case Variant::QUAT: { + GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var.operator ::Quat()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); + } + case Variant::AABB: { + GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); + } + case Variant::BASIS: { + GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); + } + case Variant::TRANSFORM: { + GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var.operator ::Transform()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); + } + case Variant::COLOR: { + GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); + } + case Variant::NODE_PATH: + return GDMonoUtils::create_managed_from(p_var.operator NodePath()); + case Variant::_RID: + return GDMonoUtils::create_managed_from(p_var.operator ::RID()); + case Variant::OBJECT: + return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); + case Variant::DICTIONARY: + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary)); + case Variant::ARRAY: + return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array)); + case Variant::POOL_BYTE_ARRAY: + return (MonoObject *)PoolByteArray_to_mono_array(p_var.operator PoolByteArray()); + case Variant::POOL_INT_ARRAY: + return (MonoObject *)PoolIntArray_to_mono_array(p_var.operator PoolIntArray()); + case Variant::POOL_REAL_ARRAY: + return (MonoObject *)PoolRealArray_to_mono_array(p_var.operator PoolRealArray()); + case Variant::POOL_STRING_ARRAY: + return (MonoObject *)PoolStringArray_to_mono_array(p_var.operator PoolStringArray()); + case Variant::POOL_VECTOR2_ARRAY: + return (MonoObject *)PoolVector2Array_to_mono_array(p_var.operator PoolVector2Array()); + case Variant::POOL_VECTOR3_ARRAY: + return (MonoObject *)PoolVector3Array_to_mono_array(p_var.operator PoolVector3Array()); + case Variant::POOL_COLOR_ARRAY: + return (MonoObject *)PoolColorArray_to_mono_array(p_var.operator PoolColorArray()); + default: + return nullptr; + } +} - case MONO_TYPE_STRING: { - if (p_var->get_type() == Variant::NIL) - return NULL; // Otherwise, Variant -> String would return the string "Null" - return (MonoObject *)mono_string_from_godot(p_var->operator String()); - } break; +size_t variant_get_managed_unboxed_size(const ManagedType &p_type) { + // This method prints no errors for unsupported types. It's called on all methods, not only + // those that end up being invoked with Variant parameters. + // For MonoObject* we return 0, as it doesn't need to be stored. + constexpr size_t zero_for_mono_object = 0; + + switch (p_type.type_encoding) { + case MONO_TYPE_BOOLEAN: + return sizeof(MonoBoolean); + case MONO_TYPE_CHAR: + return sizeof(uint16_t); + case MONO_TYPE_I1: + return sizeof(int8_t); + case MONO_TYPE_I2: + return sizeof(int16_t); + case MONO_TYPE_I4: + return sizeof(int32_t); + case MONO_TYPE_I8: + return sizeof(int64_t); + case MONO_TYPE_U1: + return sizeof(uint8_t); + case MONO_TYPE_U2: + return sizeof(uint16_t); + case MONO_TYPE_U4: + return sizeof(uint32_t); + case MONO_TYPE_U8: + return sizeof(uint64_t); + case MONO_TYPE_R4: + return sizeof(float); + case MONO_TYPE_R8: + return sizeof(double); case MONO_TYPE_VALUETYPE: { GDMonoClass *vtclass = p_type.type_class; - if (vtclass == CACHED_CLASS(Vector2)) { - GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); +#define RETURN_CHECK_FOR_STRUCT(m_struct) \ + if (vtclass == CACHED_CLASS(m_struct)) { \ + return sizeof(M_##m_struct); \ + } + + RETURN_CHECK_FOR_STRUCT(Vector2); + RETURN_CHECK_FOR_STRUCT(Rect2); + RETURN_CHECK_FOR_STRUCT(Transform2D); + RETURN_CHECK_FOR_STRUCT(Vector3); + RETURN_CHECK_FOR_STRUCT(Basis); + RETURN_CHECK_FOR_STRUCT(Quat); + RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(AABB); + RETURN_CHECK_FOR_STRUCT(Color); + RETURN_CHECK_FOR_STRUCT(Plane); + +#undef RETURN_CHECK_FOR_STRUCT + + if (mono_class_is_enum(vtclass->get_mono_ptr())) { + MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); + switch (mono_type_get_type(enum_basetype)) { + case MONO_TYPE_BOOLEAN: + return sizeof(MonoBoolean); + case MONO_TYPE_CHAR: + return sizeof(uint16_t); + case MONO_TYPE_I1: + return sizeof(int8_t); + case MONO_TYPE_I2: + return sizeof(int16_t); + case MONO_TYPE_I4: + return sizeof(int32_t); + case MONO_TYPE_I8: + return sizeof(int64_t); + case MONO_TYPE_U1: + return sizeof(uint8_t); + case MONO_TYPE_U2: + return sizeof(uint16_t); + case MONO_TYPE_U4: + return sizeof(uint32_t); + case MONO_TYPE_U8: + return sizeof(uint64_t); + default: { + // Enum with unsupported base type. We return nullptr MonoObject* on error. + return zero_for_mono_object; + } + } } - if (vtclass == CACHED_CLASS(Rect2)) { - GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); + // Enum with unsupported value type. We return nullptr MonoObject* on error. + } break; + case MONO_TYPE_STRING: + return zero_for_mono_object; + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_GENERICINST: + return zero_for_mono_object; + case MONO_TYPE_OBJECT: + return zero_for_mono_object; + } + + // Unsupported type encoding. We return nullptr MonoObject* on error. + return zero_for_mono_object; +} + +void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) { +#define RETURN_TYPE_VAL(m_type, m_val) \ + *reinterpret_cast(r_buffer) = m_val; \ + r_offset += sizeof(m_type); \ + return r_buffer; + + switch (p_type.type_encoding) { + case MONO_TYPE_BOOLEAN: + RETURN_TYPE_VAL(MonoBoolean, (MonoBoolean)p_var.operator bool()); + case MONO_TYPE_CHAR: + RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short()); + case MONO_TYPE_I1: + RETURN_TYPE_VAL(int8_t, p_var.operator signed char()); + case MONO_TYPE_I2: + RETURN_TYPE_VAL(int16_t, p_var.operator signed short()); + case MONO_TYPE_I4: + RETURN_TYPE_VAL(int32_t, p_var.operator signed int()); + case MONO_TYPE_I8: + RETURN_TYPE_VAL(int64_t, p_var.operator int64_t()); + case MONO_TYPE_U1: + RETURN_TYPE_VAL(uint8_t, p_var.operator unsigned char()); + case MONO_TYPE_U2: + RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short()); + case MONO_TYPE_U4: + RETURN_TYPE_VAL(uint32_t, p_var.operator unsigned int()); + case MONO_TYPE_U8: + RETURN_TYPE_VAL(uint64_t, p_var.operator uint64_t()); + case MONO_TYPE_R4: + RETURN_TYPE_VAL(float, p_var.operator float()); + case MONO_TYPE_R8: + RETURN_TYPE_VAL(double, p_var.operator double()); + case MONO_TYPE_VALUETYPE: { + GDMonoClass *vtclass = p_type.type_class; + +#define RETURN_CHECK_FOR_STRUCT(m_struct) \ + if (vtclass == CACHED_CLASS(m_struct)) { \ + GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \ + RETURN_TYPE_VAL(M_##m_struct, from); \ + } + + RETURN_CHECK_FOR_STRUCT(Vector2); + RETURN_CHECK_FOR_STRUCT(Rect2); + RETURN_CHECK_FOR_STRUCT(Transform2D); + RETURN_CHECK_FOR_STRUCT(Vector3); + RETURN_CHECK_FOR_STRUCT(Basis); + RETURN_CHECK_FOR_STRUCT(Quat); + RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(AABB); + RETURN_CHECK_FOR_STRUCT(Color); + RETURN_CHECK_FOR_STRUCT(Plane); + +#undef RETURN_CHECK_FOR_STRUCT + + if (mono_class_is_enum(vtclass->get_mono_ptr())) { + MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); + switch (mono_type_get_type(enum_basetype)) { + case MONO_TYPE_BOOLEAN: { + MonoBoolean val = p_var.operator bool(); + RETURN_TYPE_VAL(MonoBoolean, val); + } + case MONO_TYPE_CHAR: { + uint16_t val = p_var.operator unsigned short(); + RETURN_TYPE_VAL(uint16_t, val); + } + case MONO_TYPE_I1: { + int8_t val = p_var.operator signed char(); + RETURN_TYPE_VAL(int8_t, val); + } + case MONO_TYPE_I2: { + int16_t val = p_var.operator signed short(); + RETURN_TYPE_VAL(int16_t, val); + } + case MONO_TYPE_I4: { + int32_t val = p_var.operator signed int(); + RETURN_TYPE_VAL(int32_t, val); + } + case MONO_TYPE_I8: { + int64_t val = p_var.operator int64_t(); + RETURN_TYPE_VAL(int64_t, val); + } + case MONO_TYPE_U1: { + uint8_t val = p_var.operator unsigned char(); + RETURN_TYPE_VAL(uint8_t, val); + } + case MONO_TYPE_U2: { + uint16_t val = p_var.operator unsigned short(); + RETURN_TYPE_VAL(uint16_t, val); + } + case MONO_TYPE_U4: { + uint32_t val = p_var.operator unsigned int(); + RETURN_TYPE_VAL(uint32_t, val); + } + case MONO_TYPE_U8: { + uint64_t val = p_var.operator uint64_t(); + RETURN_TYPE_VAL(uint64_t, val); + } + default: { + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + GDMonoClass::get_full_name(mono_class_from_mono_type(enum_basetype)) + "'."); + } + } } - if (vtclass == CACHED_CLASS(Transform2D)) { - GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); - } + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + p_type.type_class->get_full_name() + "'."); + } break; +#undef RETURN_TYPE_VAL + case MONO_TYPE_STRING: + return variant_to_mono_string(p_var); + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + return variant_to_mono_array(p_var, p_type.type_class); + case MONO_TYPE_CLASS: + return variant_to_mono_object_of_class(p_var, p_type.type_class); + case MONO_TYPE_GENERICINST: + return variant_to_mono_object_of_genericinst(p_var, p_type.type_class); + case MONO_TYPE_OBJECT: + return variant_to_mono_object(p_var); + } - if (vtclass == CACHED_CLASS(Vector3)) { - GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); - } + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + itos(p_type.type_encoding) + "."); +} - if (vtclass == CACHED_CLASS(Basis)) { - GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); - } +MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) { + switch (p_type.type_encoding) { + case MONO_TYPE_BOOLEAN: { + MonoBoolean val = p_var.operator bool(); + return BOX_BOOLEAN(val); + } + case MONO_TYPE_CHAR: { + uint16_t val = p_var.operator unsigned short(); + return BOX_UINT16(val); + } + case MONO_TYPE_I1: { + int8_t val = p_var.operator signed char(); + return BOX_INT8(val); + } + case MONO_TYPE_I2: { + int16_t val = p_var.operator signed short(); + return BOX_INT16(val); + } + case MONO_TYPE_I4: { + int32_t val = p_var.operator signed int(); + return BOX_INT32(val); + } + case MONO_TYPE_I8: { + int64_t val = p_var.operator int64_t(); + return BOX_INT64(val); + } + case MONO_TYPE_U1: { + uint8_t val = p_var.operator unsigned char(); + return BOX_UINT8(val); + } + case MONO_TYPE_U2: { + uint16_t val = p_var.operator unsigned short(); + return BOX_UINT16(val); + } + case MONO_TYPE_U4: { + uint32_t val = p_var.operator unsigned int(); + return BOX_UINT32(val); + } + case MONO_TYPE_U8: { + uint64_t val = p_var.operator uint64_t(); + return BOX_UINT64(val); + } + case MONO_TYPE_R4: { + float val = p_var.operator float(); + return BOX_FLOAT(val); + } + case MONO_TYPE_R8: { + double val = p_var.operator double(); + return BOX_DOUBLE(val); + } + case MONO_TYPE_VALUETYPE: { + GDMonoClass *vtclass = p_type.type_class; - if (vtclass == CACHED_CLASS(Quat)) { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); - } +#define RETURN_CHECK_FOR_STRUCT(m_struct) \ + if (vtclass == CACHED_CLASS(m_struct)) { \ + GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \ + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_struct), &from); \ + } - if (vtclass == CACHED_CLASS(Transform)) { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); - } + RETURN_CHECK_FOR_STRUCT(Vector2); + RETURN_CHECK_FOR_STRUCT(Rect2); + RETURN_CHECK_FOR_STRUCT(Transform2D); + RETURN_CHECK_FOR_STRUCT(Vector3); + RETURN_CHECK_FOR_STRUCT(Basis); + RETURN_CHECK_FOR_STRUCT(Quat); + RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(AABB); + RETURN_CHECK_FOR_STRUCT(Color); + RETURN_CHECK_FOR_STRUCT(Plane); - if (vtclass == CACHED_CLASS(AABB)) { - GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); - } - - if (vtclass == CACHED_CLASS(Color)) { - GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); - } - - if (vtclass == CACHED_CLASS(Plane)) { - GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); - } +#undef RETURN_CHECK_FOR_STRUCT if (mono_class_is_enum(vtclass->get_mono_ptr())) { MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype); switch (mono_type_get_type(enum_basetype)) { case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_var->operator bool(); + MonoBoolean val = p_var.operator bool(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_CHAR: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I1: { - int8_t val = p_var->operator signed char(); + int8_t val = p_var.operator signed char(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I2: { - int16_t val = p_var->operator signed short(); + int16_t val = p_var.operator signed short(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I4: { - int32_t val = p_var->operator signed int(); + int32_t val = p_var.operator signed int(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I8: { - int64_t val = p_var->operator int64_t(); + int64_t val = p_var.operator int64_t(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U1: { - uint8_t val = p_var->operator unsigned char(); + uint8_t val = p_var.operator unsigned char(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U2: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U4: { - uint32_t val = p_var->operator unsigned int(); + uint32_t val = p_var.operator unsigned int(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U8: { - uint64_t val = p_var->operator uint64_t(); + uint64_t val = p_var.operator uint64_t(); return BOX_ENUM(enum_baseclass, val); } default: { - ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to a managed enum value of unmarshallable base type."); + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + GDMonoClass::get_full_name(enum_baseclass) + "'."); } } } - } break; + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + p_type.type_class->get_full_name() + "'."); + } break; + case MONO_TYPE_STRING: + return (MonoObject *)variant_to_mono_string(p_var); case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type()); - - if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) - return (MonoObject *)Array_to_mono_array(p_var->operator Array()); - - if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) - return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray()); - - if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) - return (MonoObject *)PoolIntArray_to_mono_array(p_var->operator PoolIntArray()); - - if (array_type->eklass == REAL_T_MONOCLASS) - return (MonoObject *)PoolRealArray_to_mono_array(p_var->operator PoolRealArray()); - - if (array_type->eklass == CACHED_CLASS_RAW(String)) - return (MonoObject *)PoolStringArray_to_mono_array(p_var->operator PoolStringArray()); - - if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) - return (MonoObject *)PoolVector2Array_to_mono_array(p_var->operator PoolVector2Array()); - - if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) - return (MonoObject *)PoolVector3Array_to_mono_array(p_var->operator PoolVector3Array()); - - if (array_type->eklass == CACHED_CLASS_RAW(Color)) - return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray()); - - if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) - return (MonoObject *)Array_to_mono_array(p_var->operator Array()); - - if (array_type->eklass == CACHED_CLASS_RAW(RID)) - return (MonoObject *)Array_to_mono_array(p_var->operator Array()); - - GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); - if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) - return (MonoObject *)Array_to_mono_array(p_var->operator Array(), array_type_class); - - ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to a managed array of unmarshallable element type."); - } break; - - case MONO_TYPE_CLASS: { - GDMonoClass *type_class = p_type.type_class; - - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); - } - - if (CACHED_CLASS(NodePath) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator NodePath()); - } - - if (CACHED_CLASS(RID) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator RID()); - } - - // Godot.Collections.Dictionary or IDictionary - if (CACHED_CLASS(Dictionary) == type_class || CACHED_CLASS(System_Collections_IDictionary) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); - } - - // Godot.Collections.Array or ICollection or IEnumerable - if (CACHED_CLASS(Array) == type_class || - CACHED_CLASS(System_Collections_ICollection) == type_class || - CACHED_CLASS(System_Collections_IEnumerable) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); - } - } break; - case MONO_TYPE_OBJECT: { - // Variant - switch (p_var->get_type()) { - case Variant::BOOL: { - MonoBoolean val = p_var->operator bool(); - return BOX_BOOLEAN(val); - } - case Variant::INT: { - int32_t val = p_var->operator signed int(); - return BOX_INT32(val); - } - case Variant::REAL: { -#ifdef REAL_T_IS_DOUBLE - double val = p_var->operator double(); - return BOX_DOUBLE(val); -#else - float val = p_var->operator float(); - return BOX_FLOAT(val); -#endif - } - case Variant::STRING: - return (MonoObject *)mono_string_from_godot(p_var->operator String()); - case Variant::VECTOR2: { - GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); - } - case Variant::RECT2: { - GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); - } - case Variant::VECTOR3: { - GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); - } - case Variant::TRANSFORM2D: { - GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); - } - case Variant::PLANE: { - GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); - } - case Variant::QUAT: { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); - } - case Variant::AABB: { - GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); - } - case Variant::BASIS: { - GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); - } - case Variant::TRANSFORM: { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); - } - case Variant::COLOR: { - GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); - } - case Variant::NODE_PATH: - return GDMonoUtils::create_managed_from(p_var->operator NodePath()); - case Variant::_RID: - return GDMonoUtils::create_managed_from(p_var->operator RID()); - case Variant::OBJECT: - return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); - case Variant::DICTIONARY: - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); - case Variant::ARRAY: - return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); - case Variant::POOL_BYTE_ARRAY: - return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray()); - case Variant::POOL_INT_ARRAY: - return (MonoObject *)PoolIntArray_to_mono_array(p_var->operator PoolIntArray()); - case Variant::POOL_REAL_ARRAY: - return (MonoObject *)PoolRealArray_to_mono_array(p_var->operator PoolRealArray()); - case Variant::POOL_STRING_ARRAY: - return (MonoObject *)PoolStringArray_to_mono_array(p_var->operator PoolStringArray()); - case Variant::POOL_VECTOR2_ARRAY: - return (MonoObject *)PoolVector2Array_to_mono_array(p_var->operator PoolVector2Array()); - case Variant::POOL_VECTOR3_ARRAY: - return (MonoObject *)PoolVector3Array_to_mono_array(p_var->operator PoolVector3Array()); - case Variant::POOL_COLOR_ARRAY: - return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray()); - default: - return NULL; - } - break; - case MONO_TYPE_GENERICINST: { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); - - // Godot.Collections.Dictionary - if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class); - } - - // Godot.Collections.Array - if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class); - } - - // System.Collections.Generic.Dictionary - if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { - MonoReflectionType *key_reftype = nullptr; - MonoReflectionType *value_reftype = nullptr; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - return Dictionary_to_system_generic_dict(p_var->operator Dictionary(), p_type.type_class, key_reftype, value_reftype); - } - - // System.Collections.Generic.List - if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { - MonoReflectionType *elem_reftype = nullptr; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - return Array_to_system_generic_list(p_var->operator Array(), p_type.type_class, elem_reftype); - } - - // IDictionary - if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { - MonoReflectionType *key_reftype; - MonoReflectionType *value_reftype; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); - - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), godot_dict_class); - } - - // ICollection or IEnumerable - if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { - MonoReflectionType *elem_reftype; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); - - return GDMonoUtils::create_managed_from(p_var->operator Array(), godot_array_class); - } - - // GodotObject - GDMonoClass *type_class = p_type.type_class; - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); - } - } break; - } break; + case MONO_TYPE_SZARRAY: + return (MonoObject *)variant_to_mono_array(p_var, p_type.type_class); + case MONO_TYPE_CLASS: + return variant_to_mono_object_of_class(p_var, p_type.type_class); + case MONO_TYPE_GENERICINST: + return variant_to_mono_object_of_genericinst(p_var, p_type.type_class); + case MONO_TYPE_OBJECT: + return variant_to_mono_object(p_var); } - ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to an unmarshallable managed type. Name: '" + p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + "."); + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + itos(p_type.type_encoding) + "."); } Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) { ERR_FAIL_COND_V(!p_type.type_class, Variant()); +#ifdef DEBUG_ENABLED + CRASH_COND_MSG(p_type.type_encoding == MONO_TYPE_OBJECT, "Type of object should be known."); +#endif + switch (p_type.type_encoding) { case MONO_TYPE_BOOLEAN: return (bool)unbox(p_obj); - case MONO_TYPE_CHAR: return unbox(p_obj); - case MONO_TYPE_I1: return unbox(p_obj); case MONO_TYPE_I2: @@ -733,7 +936,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return unbox(p_obj); case MONO_TYPE_I8: return unbox(p_obj); - case MONO_TYPE_U1: return unbox(p_obj); case MONO_TYPE_U2: @@ -742,55 +944,52 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return unbox(p_obj); case MONO_TYPE_U8: return unbox(p_obj); - case MONO_TYPE_R4: return unbox(p_obj); case MONO_TYPE_R8: return unbox(p_obj); - - case MONO_TYPE_STRING: { - if (p_obj == NULL) - return Variant(); // NIL - return mono_string_to_godot_not_null((MonoString *)p_obj); - } break; - case MONO_TYPE_VALUETYPE: { GDMonoClass *vtclass = p_type.type_class; if (vtclass == CACHED_CLASS(Vector2)) - return MARSHALLED_IN(Vector2, (GDMonoMarshal::M_Vector2 *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(Vector2, unbox_addr(p_obj)); if (vtclass == CACHED_CLASS(Rect2)) - return MARSHALLED_IN(Rect2, (GDMonoMarshal::M_Rect2 *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(Rect2, unbox_addr(p_obj)); if (vtclass == CACHED_CLASS(Transform2D)) - return MARSHALLED_IN(Transform2D, (GDMonoMarshal::M_Transform2D *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(Transform2D, unbox_addr(p_obj)); if (vtclass == CACHED_CLASS(Vector3)) - return MARSHALLED_IN(Vector3, (GDMonoMarshal::M_Vector3 *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(Vector3, unbox_addr(p_obj)); if (vtclass == CACHED_CLASS(Basis)) - return MARSHALLED_IN(Basis, (GDMonoMarshal::M_Basis *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(Basis, unbox_addr(p_obj)); if (vtclass == CACHED_CLASS(Quat)) - return MARSHALLED_IN(Quat, (GDMonoMarshal::M_Quat *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(Quat, unbox_addr(p_obj)); if (vtclass == CACHED_CLASS(Transform)) - return MARSHALLED_IN(Transform, (GDMonoMarshal::M_Transform *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(Transform, unbox_addr(p_obj)); if (vtclass == CACHED_CLASS(AABB)) - return MARSHALLED_IN(AABB, (GDMonoMarshal::M_AABB *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(AABB, unbox_addr(p_obj)); if (vtclass == CACHED_CLASS(Color)) - return MARSHALLED_IN(Color, (GDMonoMarshal::M_Color *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(Color, unbox_addr(p_obj)); if (vtclass == CACHED_CLASS(Plane)) - return MARSHALLED_IN(Plane, (GDMonoMarshal::M_Plane *)mono_object_unbox(p_obj)); + return MARSHALLED_IN(Plane, unbox_addr(p_obj)); if (mono_class_is_enum(vtclass->get_mono_ptr())) return unbox(p_obj); } break; - + case MONO_TYPE_STRING: { + if (p_obj == NULL) { + return Variant(); // NIL + } + return mono_string_to_godot_not_null((MonoString *)p_obj); + } break; case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type()); @@ -835,7 +1034,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return Variant(); } } break; - case MONO_TYPE_CLASS: { GDMonoClass *type_class = p_type.type_class; @@ -875,7 +1073,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return ptr ? Variant(*ptr) : Variant(); } } break; - case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); @@ -961,7 +1158,7 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) { ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj)); Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type); - if (var.get_type() == Variant::NIL && p_obj != NULL) { + if (var.get_type() == Variant::NIL) { // `&& p_obj != NULL` but omitted because always true // Cannot convert MonoObject* to Variant; fallback to 'ToString()'. MonoException *exc = NULL; MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc); @@ -1063,9 +1260,10 @@ Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_c } MonoArray *Array_to_mono_array(const Array &p_array) { - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_array.size()); + int length = p_array.size(); + MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), length); - for (int i = 0; i < p_array.size(); i++) { + for (int i = 0; i < length; i++) { MonoObject *boxed = variant_to_mono_object(p_array[i]); mono_array_setref(ret, i, boxed); } @@ -1073,9 +1271,9 @@ MonoArray *Array_to_mono_array(const Array &p_array) { return ret; } -MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class) { +MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class) { int length = p_array.size(); - MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class->get_mono_ptr(), length); + MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class, length); for (int i = 0; i < length; i++) { MonoObject *boxed = variant_to_mono_object(p_array[i]); diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 255e06a7e01..32fdf0e7b9e 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -103,15 +103,40 @@ _FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) { // Variant -MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type); -MonoObject *variant_to_mono_object(const Variant *p_var); +size_t variant_get_managed_unboxed_size(const ManagedType &p_type); +void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset); +MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type); -_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var) { - return variant_to_mono_object(&p_var); +MonoObject *variant_to_mono_object(const Variant &p_var); +MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class); +MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class); +MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class); +MonoString *variant_to_mono_string(const Variant &p_var); + +// These overloads were added to avoid passing a `const Variant *` to the `const Variant &` +// parameter. That would result in the `Variant(bool)` copy constructor being called as +// pointers are implicitly converted to bool. Implicit conversions are f-ing evil. + +_FORCE_INLINE_ void *variant_to_managed_unboxed(const Variant *p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) { + return variant_to_managed_unboxed(*p_var, p_type, r_buffer, r_offset); } - -_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) { - return variant_to_mono_object(&p_var, p_type); +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) { + return variant_to_mono_object(*p_var, p_type); +} +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) { + return variant_to_mono_object(*p_var); +} +_FORCE_INLINE_ MonoArray *variant_to_mono_array(const Variant *p_var, GDMonoClass *p_type_class) { + return variant_to_mono_array(*p_var, p_type_class); +} +_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_class(const Variant *p_var, GDMonoClass *p_type_class) { + return variant_to_mono_object_of_class(*p_var, p_type_class); +} +_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_genericinst(const Variant *p_var, GDMonoClass *p_type_class) { + return variant_to_mono_object_of_genericinst(*p_var, p_type_class); +} +_FORCE_INLINE_ MonoString *variant_to_mono_string(const Variant *p_var) { + return variant_to_mono_string(*p_var); } Variant mono_object_to_variant(MonoObject *p_obj); @@ -133,7 +158,7 @@ Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_c // Array MonoArray *Array_to_mono_array(const Array &p_array); -MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class); +MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class); Array mono_array_to_Array(MonoArray *p_array); // PoolIntArray diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 7cf90c9835a..2c81d41d804 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -75,6 +75,10 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) { // clear the cache method_info_fetched = false; method_info = MethodInfo(); + + for (int i = 0; i < params_count; i++) { + params_buffer_size += GDMonoMarshal::variant_get_managed_unboxed_size(param_types[i]); + } } GDMonoClass *GDMonoMethod::get_enclosing_class() const { @@ -102,50 +106,42 @@ IMonoClassMember::Visibility GDMonoMethod::get_visibility() { } } -MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) { - if (get_return_type().type_encoding != MONO_TYPE_VOID || get_parameters_count() > 0) { - MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count()); +MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) const { + MonoException *exc = NULL; + MonoObject *ret; + + if (params_count > 0) { + void **params = (void **)alloca(params_count * sizeof(void *)); + uint8_t *buffer = (uint8_t *)alloca(params_buffer_size); + unsigned int offset = 0; for (int i = 0; i < params_count; i++) { - MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]); - mono_array_setref(params, i, boxed_param); + params[i] = GDMonoMarshal::variant_to_managed_unboxed(p_params[i], param_types[i], buffer + offset, offset); } - MonoException *exc = NULL; - MonoObject *ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc); - - if (exc) { - ret = NULL; - if (r_exc) { - *r_exc = exc; - } else { - GDMonoUtils::set_pending_exception(exc); - } - } - - return ret; + ret = GDMonoUtils::runtime_invoke(mono_method, p_object, params, &exc); } else { - MonoException *exc = NULL; - GDMonoUtils::runtime_invoke(mono_method, p_object, NULL, &exc); - - if (exc) { - if (r_exc) { - *r_exc = exc; - } else { - GDMonoUtils::set_pending_exception(exc); - } - } - - return NULL; + ret = GDMonoUtils::runtime_invoke(mono_method, p_object, NULL, &exc); } + + if (exc) { + ret = NULL; + if (r_exc) { + *r_exc = exc; + } else { + GDMonoUtils::set_pending_exception(exc); + } + } + + return ret; } -MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoException **r_exc) { +MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoException **r_exc) const { ERR_FAIL_COND_V(get_parameters_count() > 0, NULL); return invoke_raw(p_object, NULL, r_exc); } -MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) { +MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) const { MonoException *exc = NULL; MonoObject *ret = GDMonoUtils::runtime_invoke(mono_method, p_object, p_params, &exc); diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index 053254e4d6a..c89e41906e6 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -38,7 +38,8 @@ class GDMonoMethod : public IMonoClassMember { StringName name; - int params_count; + uint16_t params_count; + unsigned int params_buffer_size; ManagedType return_type; Vector param_types; @@ -70,14 +71,14 @@ public: virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL; void fetch_attributes(); - _FORCE_INLINE_ MonoMethod *get_mono_ptr() { return mono_method; } + _FORCE_INLINE_ MonoMethod *get_mono_ptr() const { return mono_method; } - _FORCE_INLINE_ int get_parameters_count() { return params_count; } - _FORCE_INLINE_ ManagedType get_return_type() { return return_type; } + _FORCE_INLINE_ uint16_t get_parameters_count() const { return params_count; } + _FORCE_INLINE_ ManagedType get_return_type() const { return return_type; } - MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = NULL); - MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = NULL); - MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL); + MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = NULL) const; + MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = NULL) const; + MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL) const; String get_full_name(bool p_signature = false) const; String get_full_name_no_class() const; diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index 6bb08bf78ab..878546f2664 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -65,6 +65,8 @@ GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_own type.type_class = GDMono::get_singleton()->get_class(param_type_class); } + param_buffer_size = GDMonoMarshal::variant_get_managed_unboxed_size(type); + attrs_fetched = false; attributes = NULL; } @@ -141,25 +143,20 @@ bool GDMonoProperty::has_setter() { return mono_property_get_set_method(mono_property) != NULL; } -void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) { - MonoMethod *prop_method = mono_property_get_set_method(mono_property); - MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1); - mono_array_setref(params, 0, p_value); - MonoException *exc = NULL; - GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc); - if (exc) { - if (r_exc) { - *r_exc = exc; - } else { - GDMonoUtils::set_pending_exception(exc); - } - } -} +void GDMonoProperty::set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc) { + uint8_t *buffer = (uint8_t *)alloca(param_buffer_size); + unsigned int offset = 0; -void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) { - MonoException *exc = NULL; - GDMonoUtils::property_set_value(mono_property, p_object, p_params, &exc); + void *params[1] = { + GDMonoMarshal::variant_to_managed_unboxed(p_value, type, buffer, offset) + }; +#ifdef DEBUG_ENABLED + CRASH_COND(offset != param_buffer_size); +#endif + + MonoException *exc = NULL; + GDMonoUtils::property_set_value(mono_property, p_object, params, &exc); if (exc) { if (r_exc) { *r_exc = exc; diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h index d1d19b193ac..1fc7349bd68 100644 --- a/modules/mono/mono_gd/gd_mono_property.h +++ b/modules/mono/mono_gd/gd_mono_property.h @@ -45,6 +45,8 @@ class GDMonoProperty : public IMonoClassMember { bool attrs_fetched; MonoCustomAttrInfo *attributes; + unsigned int param_buffer_size; + public: virtual GDMonoClass *get_enclosing_class() const GD_FINAL { return owner; } @@ -64,8 +66,7 @@ public: _FORCE_INLINE_ ManagedType get_type() const { return type; } - void set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc = NULL); - void set_value(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL); + void set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc = NULL); MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = NULL); bool get_bool_value(MonoObject *p_object); diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index d94aaaeebcf..1552b70bd01 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -460,13 +460,6 @@ MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, M return ret; } -MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)r_exc); - GD_MONO_END_RUNTIME_INVOKE; - return ret; -} - MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) { GD_MONO_BEGIN_RUNTIME_INVOKE; MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index f0012ba80a8..5a0c36d6390 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -135,7 +135,6 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() { } MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc); -MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc); MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc); diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp index 4e214d595ac..e531ee610c6 100644 --- a/modules/mono/signal_awaiter_utils.cpp +++ b/modules/mono/signal_awaiter_utils.cpp @@ -88,11 +88,15 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc set_completed(true); int signal_argc = p_argcount - 1; - MonoArray *signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), signal_argc); + MonoArray *signal_args = NULL; - for (int i = 0; i < signal_argc; i++) { - MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_args[i]); - mono_array_setref(signal_args, i, boxed); + if (signal_argc > 0) { + signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), signal_argc); + + for (int i = 0; i < signal_argc; i++) { + MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_args[i]); + mono_array_setref(signal_args, i, boxed); + } } MonoException *exc = NULL;