summaryrefslogtreecommitdiff
path: root/modules/mono/mono_gd/gd_mono_utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/mono_gd/gd_mono_utils.cpp')
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp129
1 files changed, 102 insertions, 27 deletions
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);