summaryrefslogtreecommitdiff
path: root/modules/mono/mono_gd
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/mono_gd')
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp32
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h8
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp45
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h3
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp173
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h5
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp19
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp129
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h31
9 files changed, 300 insertions, 145 deletions
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 66339d7ae6..e2597a7d42 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -33,23 +33,37 @@
#include <mono/metadata/attrdefs.h>
#include "gd_mono_assembly.h"
+#include "gd_mono_marshal.h"
-MonoType *GDMonoClass::get_raw_type(GDMonoClass *p_class) {
+String GDMonoClass::get_full_name(MonoClass *p_mono_class) {
+ // mono_type_get_full_name is not exposed to embedders, but this seems to do the job
+ MonoReflectionType *type_obj = mono_type_get_object(mono_domain_get(), get_mono_type(p_mono_class));
- return mono_class_get_type(p_class->get_mono_ptr());
-}
+ MonoException *exc = NULL;
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ MonoString *str = mono_object_to_string((MonoObject *)type_obj, (MonoObject **)&exc);
+ GD_MONO_END_RUNTIME_INVOKE;
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
-bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
+ return GDMonoMarshal::mono_string_to_godot(str);
+}
- return mono_class_is_assignable_from(mono_class, p_from->mono_class);
+MonoType *GDMonoClass::get_mono_type(MonoClass *p_mono_class) {
+ return mono_class_get_type(p_mono_class);
}
String GDMonoClass::get_full_name() const {
+ return get_full_name(mono_class);
+}
- String res = namespace_name;
- if (res.length())
- res += ".";
- return res + class_name;
+MonoType *GDMonoClass::get_mono_type() {
+ // Care, you cannot compare MonoType pointers
+ return get_mono_type(mono_class);
+}
+
+bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
+
+ return mono_class_is_assignable_from(mono_class, p_from->mono_class);
}
GDMonoClass *GDMonoClass::get_parent_class() {
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index 417c138594..f81ab84cd0 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -98,7 +98,11 @@ class GDMonoClass {
GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
public:
- static MonoType *get_raw_type(GDMonoClass *p_class);
+ static String get_full_name(MonoClass *p_mono_class);
+ static MonoType *get_mono_type(MonoClass *p_mono_class);
+
+ String get_full_name() const;
+ MonoType *get_mono_type();
bool is_assignable_from(GDMonoClass *p_from) const;
@@ -108,8 +112,6 @@ public:
_FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; }
_FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
- String get_full_name() const;
-
GDMonoClass *get_parent_class();
#ifdef TOOLS_ENABLED
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 3b91777ed4..d3a673dc1b 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -148,7 +148,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class));
+ 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_AND_BREAK(Array);
@@ -200,6 +200,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (CACHED_CLASS(Dictionary) == type_class) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
+ if (CACHED_CLASS(Array) == type_class) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
ERR_FAIL();
} break;
@@ -248,10 +260,13 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
case Variant::DICTIONARY: {
- MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+ mono_field_set_value(p_object, mono_field, managed);
+ } break;
+ case Variant::ARRAY: {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
mono_field_set_value(p_object, mono_field, managed);
} break;
- case Variant::ARRAY: SET_FROM_ARRAY_AND_BREAK(Array);
case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
case Variant::POOL_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
@@ -265,8 +280,28 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
} break;
case MONO_TYPE_GENERICINST: {
- if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) {
- MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
+ MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
+
+ MonoException *exc = NULL;
+
+ GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
+ MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ if (is_dict) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class);
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
+ exc = NULL;
+
+ GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
+ MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ if (is_array) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class);
mono_field_set_value(p_object, mono_field, managed);
break;
}
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
index 2b5110f0b9..72a5439044 100644
--- a/modules/mono/mono_gd/gd_mono_header.h
+++ b/modules/mono/mono_gd/gd_mono_header.h
@@ -45,7 +45,8 @@ struct ManagedType {
GDMonoClass *type_class;
ManagedType() {
- type_class = 0;
+ type_encoding = 0;
+ type_class = NULL;
}
};
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 5cd77d63e2..de91e71bab 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -120,7 +120,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
+ MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
return Variant::ARRAY;
@@ -162,12 +162,36 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
if (CACHED_CLASS(RID) == type_class) {
return Variant::_RID;
}
+
+ if (CACHED_CLASS(Dictionary) == type_class) {
+ return Variant::DICTIONARY;
+ }
+
+ if (CACHED_CLASS(Array) == type_class) {
+ return Variant::ARRAY;
+ }
} break;
case MONO_TYPE_GENERICINST: {
- if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
+ MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
+
+ MonoException *exc = NULL;
+ GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
+ MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ if (is_dict) {
return Variant::DICTIONARY;
}
+
+ exc = NULL;
+ GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
+ MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ if (is_array) {
+ return Variant::ARRAY;
+ }
} break;
default: {
@@ -216,6 +240,7 @@ 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);
}
@@ -315,7 +340,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
+ 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());
@@ -360,6 +385,14 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
if (CACHED_CLASS(RID) == type_class) {
return GDMonoUtils::create_managed_from(p_var->operator RID());
}
+
+ if (CACHED_CLASS(Dictionary) == type_class) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+ }
+
+ if (CACHED_CLASS(Array) == type_class) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+ }
} break;
case MONO_TYPE_OBJECT: {
// Variant
@@ -411,9 +444,9 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
}
case Variant::DICTIONARY:
- return Dictionary_to_mono_object(p_var->operator Dictionary());
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
case Variant::ARRAY:
- return (MonoObject *)Array_to_mono_array(p_var->operator 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:
@@ -433,8 +466,24 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
break;
case MONO_TYPE_GENERICINST: {
- if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
- return Dictionary_to_mono_object(p_var->operator Dictionary());
+ MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
+
+ MonoException *exc = NULL;
+ GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
+ MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ if (is_dict) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class);
+ }
+
+ exc = NULL;
+ GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
+ MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ if (is_array) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
}
} break;
} break;
@@ -452,7 +501,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
ERR_FAIL_COND_V(!tclass, Variant());
- MonoType *raw_type = tclass->get_raw_type(tclass);
+ MonoType *raw_type = tclass->get_mono_type();
ManagedType type;
@@ -531,7 +580,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class));
+ MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
return mono_array_to_Array((MonoArray *)p_obj);
@@ -579,11 +628,51 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj));
return ptr ? Variant(*ptr) : Variant();
}
+
+ if (CACHED_CLASS(Array) == type_class) {
+ MonoException *exc = NULL;
+ GDMonoUtils::Array_GetPtr get_ptr = CACHED_METHOD_THUNK(Array, GetPtr);
+ Array *ptr = get_ptr(p_obj, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return ptr ? Variant(*ptr) : Variant();
+ }
+
+ if (CACHED_CLASS(Dictionary) == type_class) {
+ MonoException *exc = NULL;
+ GDMonoUtils::Dictionary_GetPtr get_ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr);
+ Dictionary *ptr = get_ptr(p_obj, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return ptr ? Variant(*ptr) : Variant();
+ }
} break;
case MONO_TYPE_GENERICINST: {
- if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) {
- return mono_object_to_Dictionary(p_obj);
+ MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
+
+ MonoException *exc = NULL;
+
+ GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
+ MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ if (is_dict) {
+ MonoException *exc = NULL;
+ MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return *unbox<Dictionary *>(ret);
+ }
+
+ exc = NULL;
+
+ GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
+ MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ if (is_array) {
+ MonoException *exc = NULL;
+ MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return *unbox<Array *>(ret);
}
} break;
}
@@ -822,66 +911,4 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) {
return ret;
}
-
-MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict) {
- MonoArray *keys = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size());
- MonoArray *values = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size());
-
- int i = 0;
- const Variant *dkey = NULL;
- while ((dkey = p_dict.next(dkey))) {
- mono_array_set(keys, MonoObject *, i, variant_to_mono_object(dkey));
- mono_array_set(values, MonoObject *, i, variant_to_mono_object(p_dict[*dkey]));
- i++;
- }
-
- GDMonoUtils::MarshalUtils_ArraysToDict arrays_to_dict = CACHED_METHOD_THUNK(MarshalUtils, ArraysToDictionary);
-
- MonoException *exc = NULL;
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = arrays_to_dict(keys, values, (MonoObject **)&exc);
- GD_MONO_END_RUNTIME_INVOKE;
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL_V(NULL);
- }
-
- return ret;
-}
-
-Dictionary mono_object_to_Dictionary(MonoObject *p_dict) {
- Dictionary ret;
-
- if (!p_dict)
- return ret;
-
- GDMonoUtils::MarshalUtils_DictToArrays dict_to_arrays = CACHED_METHOD_THUNK(MarshalUtils, DictionaryToArrays);
-
- MonoArray *keys = NULL;
- MonoArray *values = NULL;
- MonoException *exc = NULL;
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- dict_to_arrays(p_dict, &keys, &values, (MonoObject **)&exc);
- GD_MONO_END_RUNTIME_INVOKE;
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL_V(Dictionary());
- }
-
- int length = mono_array_length(keys);
-
- for (int i = 0; i < length; i++) {
- MonoObject *key_obj = mono_array_get(keys, MonoObject *, i);
- MonoObject *value_obj = mono_array_get(values, MonoObject *, i);
-
- Variant key = key_obj ? mono_object_to_variant(key_obj) : Variant();
- Variant value = value_obj ? mono_object_to_variant(value_obj) : Variant();
-
- ret[key] = value;
- }
-
- return ret;
-}
} // namespace GDMonoMarshal
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 6572408ab5..464f584a0a 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -143,11 +143,6 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array);
MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array);
-// Dictionary
-
-MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict);
-Dictionary mono_object_to_Dictionary(MonoObject *p_dict);
-
#ifdef YOLO_COPY
#define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in;
#define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in);
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index 1f837a2d78..a1c710c26c 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -139,23 +139,8 @@ bool GDMonoProperty::has_setter() {
}
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_set(params, MonoObject *, 0, p_value);
-
- MonoException *exc = NULL;
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- mono_runtime_invoke_array(prop_method, p_object, params, (MonoObject **)&exc);
- GD_MONO_END_RUNTIME_INVOKE;
-
- if (exc) {
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
+ void *params[1] = { p_value };
+ set_value(p_object, params, r_exc);
}
void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index a229552b76..7cd922138f 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -87,6 +87,8 @@ void MonoCache::clear_members() {
method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL;
#endif
+ class_KeyNotFoundException = NULL;
+
rawclass_Dictionary = NULL;
class_Vector2 = NULL;
@@ -107,6 +109,8 @@ void MonoCache::clear_members() {
class_Control = NULL;
class_Spatial = NULL;
class_WeakRef = NULL;
+ class_Array = NULL;
+ class_Dictionary = NULL;
class_MarshalUtils = NULL;
#ifdef DEBUG_ENABLED
@@ -134,8 +138,10 @@ void MonoCache::clear_members() {
field_Image_ptr = NULL;
field_RID_ptr = NULL;
- methodthunk_MarshalUtils_DictionaryToArrays = NULL;
- methodthunk_MarshalUtils_ArraysToDictionary = NULL;
+ methodthunk_Array_GetPtr = NULL;
+ methodthunk_Dictionary_GetPtr = NULL;
+ methodthunk_MarshalUtils_IsArrayGenericType = NULL;
+ methodthunk_MarshalUtils_IsDictionaryGenericType = NULL;
methodthunk_SignalAwaiter_SignalCallback = NULL;
methodthunk_SignalAwaiter_FailureCallback = NULL;
methodthunk_GodotTaskScheduler_Activate = NULL;
@@ -175,6 +181,8 @@ void update_corlib_cache() {
CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
#endif
+ CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException"));
+
mono_cache.corlib_cache_updated = true;
}
@@ -198,6 +206,8 @@ void update_godot_api_cache() {
CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
+ CACHE_CLASS_AND_CHECK(Array, GODOT_API_CLASS(Array));
+ CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_CLASS(Dictionary));
CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
#ifdef DEBUG_ENABLED
@@ -224,8 +234,10 @@ void update_godot_api_cache() {
CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryToArrays, (MarshalUtils_DictToArrays)CACHED_CLASS(MarshalUtils)->get_method("DictionaryToArrays", 3)->get_thunk());
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArraysToDictionary, (MarshalUtils_ArraysToDict)CACHED_CLASS(MarshalUtils)->get_method("ArraysToDictionary", 2)->get_thunk());
+ CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_CLASS(Array)->get_method("GetPtr", 0)->get_thunk());
+ CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_CLASS(Dictionary)->get_method("GetPtr", 0)->get_thunk());
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method("IsArrayGenericType", 1)->get_thunk());
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method("IsDictionaryGenericType", 1)->get_thunk());
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)->get_thunk());
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk());
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk());
@@ -234,24 +246,9 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)->get_thunk());
#endif
- {
- /*
- * TODO Right now we only support Dictionary<object, object>.
- * It would be great if we could support other key/value types
- * without forcing the user to copy the entries.
- */
- GDMonoMethod *method_get_dict_type = CACHED_CLASS(MarshalUtils)->get_method("GetDictionaryType", 0);
- ERR_FAIL_NULL(method_get_dict_type);
- MonoReflectionType *dict_refl_type = (MonoReflectionType *)method_get_dict_type->invoke(NULL);
- ERR_FAIL_NULL(dict_refl_type);
- MonoType *dict_type = mono_reflection_type_get_type(dict_refl_type);
- ERR_FAIL_NULL(dict_type);
-
- CACHE_RAW_MONO_CLASS_AND_CHECK(Dictionary, mono_class_from_mono_type(dict_type));
- }
-
+ // TODO Move to CSharpLanguage::init()
MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
- mono_runtime_object_init(task_scheduler);
+ GDMonoUtils::runtime_object_init(task_scheduler);
mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
mono_cache.godot_api_cache_updated = true;
@@ -304,6 +301,12 @@ MonoThread *get_current_thread() {
return mono_thread_current();
}
+void runtime_object_init(MonoObject *p_this_obj) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ mono_runtime_object_init(p_this_obj);
+ GD_MONO_END_RUNTIME_INVOKE;
+}
+
GDMonoClass *get_object_class(MonoObject *p_object) {
return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
}
@@ -358,7 +361,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
// Construct
- mono_runtime_object_init(mono_object);
+ GDMonoUtils::runtime_object_init(mono_object);
return mono_object;
}
@@ -368,7 +371,7 @@ MonoObject *create_managed_from(const NodePath &p_from) {
ERR_FAIL_NULL_V(mono_object, NULL);
// Construct
- mono_runtime_object_init(mono_object);
+ GDMonoUtils::runtime_object_init(mono_object);
CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
@@ -380,13 +383,73 @@ MonoObject *create_managed_from(const RID &p_from) {
ERR_FAIL_NULL_V(mono_object, NULL);
// Construct
- mono_runtime_object_init(mono_object);
+ GDMonoUtils::runtime_object_init(mono_object);
CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
return mono_object;
}
+MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) {
+ MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
+ ERR_FAIL_NULL_V(mono_object, NULL);
+
+ // Search constructor that takes a pointer as parameter
+ MonoMethod *m;
+ void *iter = NULL;
+ while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
+ if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
+ MonoMethodSignature *sig = mono_method_signature(m);
+ void *front = NULL;
+ if (mono_signature_get_param_count(sig) == 1 &&
+ mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
+ break;
+ }
+ }
+ }
+
+ CRASH_COND(m == NULL);
+
+ Array *new_array = memnew(Array(p_from));
+ void *args[1] = { &new_array };
+
+ MonoException *exc = NULL;
+ mono_runtime_invoke(m, mono_object, args, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ return mono_object;
+}
+
+MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) {
+ MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
+ ERR_FAIL_NULL_V(mono_object, NULL);
+
+ // Search constructor that takes a pointer as parameter
+ MonoMethod *m;
+ void *iter = NULL;
+ while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
+ if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
+ MonoMethodSignature *sig = mono_method_signature(m);
+ void *front = NULL;
+ if (mono_signature_get_param_count(sig) == 1 &&
+ mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
+ break;
+ }
+ }
+ }
+
+ CRASH_COND(m == NULL);
+
+ Dictionary *new_dict = memnew(Dictionary(p_from));
+ void *args[1] = { &new_dict };
+
+ MonoException *exc = NULL;
+ mono_runtime_invoke(m, mono_object, args, (MonoObject **)&exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ return mono_object;
+}
+
MonoDomain *create_domain(const String &p_friendly_name) {
MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
@@ -400,10 +463,10 @@ MonoDomain *create_domain(const String &p_friendly_name) {
return domain;
}
-String get_exception_name_and_message(MonoException *p_ex) {
+String get_exception_name_and_message(MonoException *p_exc) {
String res;
- MonoClass *klass = mono_object_get_class((MonoObject *)p_ex);
+ MonoClass *klass = mono_object_get_class((MonoObject *)p_exc);
MonoType *type = mono_class_get_type(klass);
char *full_name = mono_type_full_name(type);
@@ -413,12 +476,24 @@ String get_exception_name_and_message(MonoException *p_ex) {
res += ": ";
MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
- MonoString *msg = (MonoString *)mono_property_get_value(prop, (MonoObject *)p_ex, NULL, NULL);
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ MonoString *msg = (MonoString *)mono_property_get_value(prop, (MonoObject *)p_exc, NULL, NULL);
+ GD_MONO_END_RUNTIME_INVOKE;
res += GDMonoMarshal::mono_string_to_godot(msg);
return res;
}
+void set_exception_message(MonoException *p_exc, String message) {
+ MonoClass *klass = mono_object_get_class((MonoObject *)p_exc);
+ MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
+ MonoString *msg = GDMonoMarshal::mono_string_from_godot(message);
+ void *params[1] = { msg };
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ mono_property_set_value(prop, (MonoObject *)p_exc, params, NULL);
+ GD_MONO_END_RUNTIME_INVOKE;
+}
+
void debug_print_unhandled_exception(MonoException *p_exc) {
print_unhandled_exception(p_exc);
debug_send_unhandled_exception_error(p_exc);
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 4f8e5932cd..d6774ed41d 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -41,14 +41,24 @@
#include "object.h"
#include "reference.h"
+#define UNLIKELY_UNHANDLED_EXCEPTION(m_exc) \
+ if (unlikely(m_exc != NULL)) { \
+ GDMonoUtils::debug_unhandled_exception(m_exc); \
+ _UNREACHABLE_(); \
+ }
+
namespace GDMonoUtils {
-typedef MonoObject *(*MarshalUtils_DictToArrays)(MonoObject *, MonoArray **, MonoArray **, MonoObject **);
-typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoObject **);
+typedef Array *(*Array_GetPtr)(MonoObject *, MonoObject **);
+typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoObject **);
typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
+typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
+typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
+typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
+typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **);
struct MonoCache {
@@ -79,6 +89,8 @@ struct MonoCache {
GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
#endif
+ GDMonoClass *class_KeyNotFoundException;
+
MonoClass *rawclass_Dictionary;
// -----------------------------------------------
@@ -100,6 +112,8 @@ struct MonoCache {
GDMonoClass *class_Control;
GDMonoClass *class_Spatial;
GDMonoClass *class_WeakRef;
+ GDMonoClass *class_Array;
+ GDMonoClass *class_Dictionary;
GDMonoClass *class_MarshalUtils;
#ifdef DEBUG_ENABLED
@@ -127,8 +141,10 @@ struct MonoCache {
GDMonoField *field_Image_ptr;
GDMonoField *field_RID_ptr;
- MarshalUtils_DictToArrays methodthunk_MarshalUtils_DictionaryToArrays;
- MarshalUtils_ArraysToDict methodthunk_MarshalUtils_ArraysToDictionary;
+ Array_GetPtr methodthunk_Array_GetPtr;
+ Dictionary_GetPtr methodthunk_Dictionary_GetPtr;
+ IsArrayGenericType methodthunk_MarshalUtils_IsArrayGenericType;
+ IsDictionaryGenericType methodthunk_MarshalUtils_IsDictionaryGenericType;
SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
@@ -175,6 +191,8 @@ _FORCE_INLINE_ bool is_main_thread() {
return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
}
+void runtime_object_init(MonoObject *p_this_obj);
+
GDMonoClass *get_object_class(MonoObject *p_object);
GDMonoClass *type_get_proxy_class(const StringName &p_type);
GDMonoClass *get_class_native_base(GDMonoClass *p_class);
@@ -183,10 +201,13 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
MonoObject *create_managed_from(const NodePath &p_from);
MonoObject *create_managed_from(const RID &p_from);
+MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class);
+MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class);
MonoDomain *create_domain(const String &p_friendly_name);
-String get_exception_name_and_message(MonoException *p_ex);
+String get_exception_name_and_message(MonoException *p_exc);
+void set_exception_message(MonoException *p_exc, String message);
void debug_print_unhandled_exception(MonoException *p_exc);
void debug_send_unhandled_exception_error(MonoException *p_exc);