diff options
Diffstat (limited to 'modules/mono/mono_gd')
22 files changed, 739 insertions, 180 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index bba7df2c6a..7699e0d0cd 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -30,6 +30,7 @@ #include "gd_mono.h" +#include <mono/metadata/environment.h> #include <mono/metadata/exception.h> #include <mono/metadata/mono-config.h> #include <mono/metadata/mono-debug.h> @@ -212,7 +213,7 @@ void GDMono::initialize() { String config_dir; #ifdef TOOLS_ENABLED -#ifdef WINDOWS_ENABLED +#if defined(WINDOWS_ENABLED) mono_reg_info = MonoRegUtils::find_mono(); if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) { @@ -222,7 +223,7 @@ void GDMono::initialize() { if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) { config_dir = mono_reg_info.config_dir; } -#elif OSX_ENABLED +#elif defined(OSX_ENABLED) const char *c_assembly_rootdir = mono_assembly_getrootdir(); const char *c_config_dir = mono_get_config_dir(); @@ -250,17 +251,19 @@ void GDMono::initialize() { String bundled_config_dir = GodotSharpDirs::get_data_mono_etc_dir(); #ifdef TOOLS_ENABLED - if (DirAccess::exists(bundled_assembly_rootdir) && DirAccess::exists(bundled_config_dir)) { + if (DirAccess::exists(bundled_assembly_rootdir)) { assembly_rootdir = bundled_assembly_rootdir; + } + + if (DirAccess::exists(bundled_config_dir)) { config_dir = bundled_config_dir; } #ifdef WINDOWS_ENABLED if (assembly_rootdir.empty() || config_dir.empty()) { + ERR_PRINT("Cannot find Mono in the registry"); // Assertion: if they are not set, then they weren't found in the registry CRASH_COND(mono_reg_info.assembly_dir.length() > 0 || mono_reg_info.config_dir.length() > 0); - - ERR_PRINT("Cannot find Mono in the registry"); } #endif // WINDOWS_ENABLED @@ -657,8 +660,6 @@ bool GDMono::_load_project_assembly() { if (success) { mono_assembly_set_main(project_assembly->get_assembly()); - - CSharpLanguage::get_singleton()->project_assembly_loaded(); } else { if (OS::get_singleton()->is_stdout_verbose()) print_error("Mono: Failed to load project assembly"); @@ -808,6 +809,8 @@ Error GDMono::_unload_scripts_domain() { mono_gc_collect(mono_gc_max_generation()); + GDMonoUtils::clear_godot_api_cache(); + _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain)); core_api_assembly = NULL; @@ -865,7 +868,7 @@ Error GDMono::reload_scripts_domain() { } } - CSharpLanguage::get_singleton()->_uninitialize_script_bindings(); + CSharpLanguage::get_singleton()->_on_scripts_domain_unloaded(); Error err = _load_scripts_domain(); if (err != OK) { @@ -927,6 +930,7 @@ Error GDMono::reload_scripts_domain() { Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { CRASH_COND(p_domain == NULL); + CRASH_COND(p_domain == SCRIPTS_DOMAIN); // Should use _unload_scripts_domain() instead String domain_name = mono_domain_get_friendly_name(p_domain); @@ -1008,7 +1012,9 @@ void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) { if (ScriptDebugger::get_singleton()) ScriptDebugger::get_singleton()->idle_poll(); #endif - abort(); + + exit(mono_environment_exitcode_get()); + GD_UNREACHABLE(); } @@ -1077,8 +1083,6 @@ GDMono::~GDMono() { } assemblies.clear(); - GDMonoUtils::clear_cache(); - print_verbose("Mono: Runtime cleanup..."); mono_jit_cleanup(root_domain); diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index 8fec28b186..f1f0015ac9 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -46,11 +46,17 @@ bool GDMonoAssembly::in_preload = false; Vector<String> GDMonoAssembly::search_dirs; -void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config) { +void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config, const String &p_custom_bcl_dir) { - const char *rootdir = mono_assembly_getrootdir(); - if (rootdir) { - String framework_dir = String::utf8(rootdir).plus_file("mono").plus_file("4.5"); + String framework_dir; + + if (!p_custom_bcl_dir.empty()) { + framework_dir = p_custom_bcl_dir; + } else if (mono_assembly_getrootdir()) { + framework_dir = String::utf8(mono_assembly_getrootdir()).plus_file("mono").plus_file("4.5"); + } + + if (!framework_dir.empty()) { r_search_dirs.push_back(framework_dir); r_search_dirs.push_back(framework_dir.plus_file("Facades")); } diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index 32432af37d..39749dfc1d 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -122,7 +122,7 @@ public: GDMonoClass *get_object_derived_class(const StringName &p_class); - static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String()); + static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String(), const String &p_custom_bcl_dir = String()); static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly); diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index 92324d73f9..4342f46109 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -55,7 +55,8 @@ String GDMonoClass::get_full_name() const { } MonoType *GDMonoClass::get_mono_type() { - // Care, you cannot compare MonoType pointers + // Careful, you cannot compare two MonoType*. + // There is mono_metadata_type_equal, how is this different from comparing two MonoClass*? return get_mono_type(mono_class); } @@ -260,6 +261,11 @@ bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) { return get_fetched_method_unknown_params(p_name) != NULL; } +bool GDMonoClass::implements_interface(GDMonoClass *p_interface) { + + return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr()); +} + GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) { 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 4af909450e..249422b844 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -135,6 +135,8 @@ public: void fetch_attributes(); void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base); + bool implements_interface(GDMonoClass *p_interface); + GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0); GDMonoMethod *get_method(MonoMethod *p_raw_method); GDMonoMethod *get_method(MonoMethod *p_raw_method, 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 5e9d4db122..2e79f87625 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -313,6 +313,38 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), + GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype)); + mono_field_set_value(p_object, mono_field, managed); + break; + } + + if (type_class->implements_interface(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; + } + + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), + GDMonoUtils::Marshal::make_generic_array_type(elem_reftype)); + mono_field_set_value(p_object, mono_field, managed); + break; + } + + if (type_class->implements_interface(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_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name()); ERR_FAIL(); } break; @@ -420,26 +452,44 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type()); - MonoException *exc = NULL; + 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; + } + + 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; + } - GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType); - MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + // The order in which we check the following interfaces is very important (dictionaries and generics first) - if (is_dict) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class); + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), + GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype)); mono_field_set_value(p_object, mono_field, managed); break; } - exc = NULL; + if (type.type_class->implements_interface(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; + } - GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType); - MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), + GDMonoUtils::Marshal::make_generic_array_type(elem_reftype)); + mono_field_set_value(p_object, mono_field, managed); + break; + } - if (is_array) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class); + if (type.type_class->implements_interface(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; } diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h index e348583370..a7727ddf34 100644 --- a/modules/mono/mono_gd/gd_mono_field.h +++ b/modules/mono/mono_gd/gd_mono_field.h @@ -47,9 +47,11 @@ class GDMonoField : public IMonoClassMember { MonoCustomAttrInfo *attributes; public: - virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_FIELD; } + virtual GDMonoClass *get_enclosing_class() const GD_FINAL { return owner; } - virtual StringName get_name() GD_FINAL { return name; } + virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_FIELD; } + + virtual StringName get_name() const GD_FINAL { return name; } virtual bool is_static() GD_FINAL; virtual Visibility get_visibility() GD_FINAL; diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h index dd8c047386..d7962eac8b 100644 --- a/modules/mono/mono_gd/gd_mono_header.h +++ b/modules/mono/mono_gd/gd_mono_header.h @@ -35,24 +35,12 @@ class GDMonoAssembly; class GDMonoClass; -class IMonoClassMember; class GDMonoField; -class GDMonoProperty; class GDMonoMethod; +class GDMonoProperty; -struct ManagedType { - int type_encoding; - GDMonoClass *type_class; - - ManagedType() : - type_encoding(0), - type_class(NULL) { - } +class IMonoClassMember; - ManagedType(int p_type_encoding, GDMonoClass *p_type_class) : - type_encoding(p_type_encoding), - type_class(p_type_class) { - } -}; +#include "managed_type.h" #endif // GD_MONO_HEADER_H diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp index c8cba5cf1b..63bcfe053c 100644 --- a/modules/mono/mono_gd/gd_mono_internals.cpp +++ b/modules/mono/mono_gd/gd_mono_internals.cpp @@ -111,7 +111,8 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { void unhandled_exception(MonoException *p_exc) { mono_unhandled_exception((MonoObject *)p_exc); // prints the exception as well - abort(); + // Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders + GDMono::unhandled_exception_hook((MonoObject *)p_exc, NULL); GD_UNREACHABLE(); } diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index ec89df1959..a6e04e561d 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -37,6 +37,7 @@ #include "core/os/os.h" #include "../godotsharp_dirs.h" +#include "../utils/string_utils.h" static int log_level_get_id(const char *p_log_level) { @@ -72,8 +73,11 @@ static void mono_log_callback(const char *log_domain, const char *log_level, con if (fatal) { ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: " + GDMonoLog::get_singleton()->get_log_file_path() + "\n"); - // If we were to abort without flushing, the log wouldn't get written. + // Make sure to flush before aborting f->flush(); + f->close(); + memdelete(f); + abort(); } } @@ -93,17 +97,9 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) { return true; } -void GDMonoLog::_open_log_file(const String &p_file_path) { - - log_file = FileAccess::open(p_file_path, FileAccess::WRITE); - - ERR_EXPLAIN("Failed to create log file"); - ERR_FAIL_COND(!log_file); -} - void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) { - static const uint64_t MAX_SECS = 5 * 86400; + static const uint64_t MAX_SECS = 5 * 86400; // 5 days DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); ERR_FAIL_COND(!da); @@ -120,10 +116,9 @@ void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) { if (!current.ends_with(".txt")) continue; - String name = current.get_basename(); - uint64_t unixtime = (uint64_t)name.to_int64(); + uint64_t modified_time = FileAccess::get_modified_time(da->get_current_dir().plus_file(current)); - if (OS::get_singleton()->get_unix_time() - unixtime > MAX_SECS) { + if (OS::get_singleton()->get_unix_time() - modified_time > MAX_SECS) { da->remove(current); } } @@ -133,26 +128,47 @@ void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) { void GDMonoLog::initialize() { + CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8(); + + if (log_level.length() != 0 && log_level_get_id(log_level.get_data()) == -1) { + ERR_PRINTS(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): " + log_level.get_data()); + log_level = CharString(); + } + + if (log_level.length() == 0) { #ifdef DEBUG_ENABLED - const char *log_level = "debug"; + log_level = String("info").utf8(); #else - const char *log_level = "warning"; + log_level = String("warning").utf8(); #endif + } String logs_dir = GodotSharpDirs::get_mono_logs_dir(); if (_try_create_logs_dir(logs_dir)) { _delete_old_log_files(logs_dir); - log_file_path = logs_dir.plus_file(String::num_int64(OS::get_singleton()->get_unix_time()) + ".txt"); - _open_log_file(log_file_path); + OS::Date date_now = OS::get_singleton()->get_date(); + OS::Time time_now = OS::get_singleton()->get_time(); + int pid = OS::get_singleton()->get_process_id(); + + String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d (%d).txt", + date_now.year, date_now.month, date_now.day, + time_now.hour, time_now.min, time_now.sec, pid); + + log_file_path = logs_dir.plus_file(log_file_name); + + log_file = FileAccess::open(log_file_path, FileAccess::WRITE); + if (!log_file) { + ERR_PRINT("Mono: Cannot create log file"); + } } - mono_trace_set_level_string(log_level); - log_level_id = log_level_get_id(log_level); + mono_trace_set_level_string(log_level.get_data()); + log_level_id = log_level_get_id(log_level.get_data()); if (log_file) { - print_verbose("Mono: Logfile is " + log_file_path); + OS::get_singleton()->print("Mono: Logfile is: %s\n", log_file_path.utf8().get_data()); mono_trace_set_log_handler(mono_log_callback, this); } else { OS::get_singleton()->printerr("Mono: No log file, using default log handler\n"); diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h index a477e5edee..91d0557aa3 100644 --- a/modules/mono/mono_gd/gd_mono_log.h +++ b/modules/mono/mono_gd/gd_mono_log.h @@ -41,7 +41,6 @@ class GDMonoLog { String log_file_path; bool _try_create_logs_dir(const String &p_logs_dir); - void _open_log_file(const String &p_file_path); void _delete_old_log_files(const String &p_logs_dir); static GDMonoLog *singleton; diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 7fe8ae608a..87157ed233 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -156,26 +156,52 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { if (CACHED_CLASS(Array) == type_class) { return Variant::ARRAY; } + + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); + + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) { + return Variant::DICTIONARY; + } + + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { + return Variant::DICTIONARY; + } + + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) { + return Variant::ARRAY; + } + + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { + return Variant::ARRAY; + } } break; case MONO_TYPE_GENERICINST: { 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 = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { + return Variant::DICTIONARY; + } + + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { + return Variant::ARRAY; + } + + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) + return Variant::DICTIONARY; - if (is_dict) { + if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { return Variant::DICTIONARY; } - exc = NULL; - GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType); - MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) + return Variant::ARRAY; - if (is_array) { + if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { return Variant::ARRAY; } } break; @@ -188,6 +214,63 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { return Variant::NIL; } +bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) { + switch (p_array_type.type_encoding) { + case MONO_TYPE_GENERICINST: { + MonoReflectionType *array_reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_array_type.type_class->get_mono_type()); + + if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype)) { + MonoReflectionType *elem_reftype; + + GDMonoUtils::Marshal::array_get_element_type(array_reftype, &elem_reftype); + + r_elem_type = ManagedType::from_reftype(elem_reftype); + return true; + } + + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(array_reftype, &elem_reftype)) { + r_elem_type = ManagedType::from_reftype(elem_reftype); + return true; + } + } break; + default: { + } break; + } + + return false; +} + +bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, ManagedType &r_key_type, ManagedType &r_value_type) { + switch (p_dictionary_type.type_encoding) { + case MONO_TYPE_GENERICINST: { + MonoReflectionType *dict_reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_dictionary_type.type_class->get_mono_type()); + + if (GDMonoUtils::Marshal::type_is_generic_dictionary(dict_reftype)) { + MonoReflectionType *key_reftype; + MonoReflectionType *value_reftype; + + GDMonoUtils::Marshal::dictionary_get_key_value_types(dict_reftype, &key_reftype, &value_reftype); + + r_key_type = ManagedType::from_reftype(key_reftype); + r_value_type = ManagedType::from_reftype(value_reftype); + return true; + } + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(dict_reftype, &key_reftype, &value_reftype)) { + r_key_type = ManagedType::from_reftype(key_reftype); + r_value_type = ManagedType::from_reftype(value_reftype); + return true; + } + } break; + default: { + } break; + } + + return false; +} + String mono_to_utf8_string(MonoString *p_mono_string) { MonoError error; char *utf8 = mono_string_to_utf8_checked(p_mono_string, &error); @@ -453,6 +536,30 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty if (CACHED_CLASS(Array) == type_class) { return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); } + + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), + GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype)); + } + + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); + } + + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + return GDMonoUtils::create_managed_from(p_var->operator Array(), + GDMonoUtils::Marshal::make_generic_array_type(elem_reftype)); + } + + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { + return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); + } } break; case MONO_TYPE_OBJECT: { // Variant @@ -547,23 +654,35 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty case MONO_TYPE_GENERICINST: { 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 = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_dict) { + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { 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 = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_array) { + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class); } + + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), + GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype)); + } + + if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); + } + + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + return GDMonoUtils::create_managed_from(p_var->operator Array(), + GDMonoUtils::Marshal::make_generic_array_type(elem_reftype)); + } + + if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { + return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); + } } break; } break; } @@ -577,15 +696,9 @@ Variant mono_object_to_variant(MonoObject *p_obj) { if (!p_obj) return Variant(); - GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj)); - ERR_FAIL_COND_V(!tclass, Variant()); - - MonoType *raw_type = tclass->get_mono_type(); - - ManagedType type; + ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj)); - type.type_encoding = mono_type_get_type(raw_type); - type.type_class = tclass; + ERR_FAIL_COND_V(!type.type_class, Variant()); switch (type.type_encoding) { case MONO_TYPE_BOOLEAN: @@ -717,47 +830,73 @@ Variant mono_object_to_variant(MonoObject *p_obj) { if (CACHED_CLASS(Array) == type_class) { MonoException *exc = NULL; - Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, (MonoObject **)&exc); + Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, &exc); UNLIKELY_UNHANDLED_EXCEPTION(exc); return ptr ? Variant(*ptr) : Variant(); } if (CACHED_CLASS(Dictionary) == type_class) { MonoException *exc = NULL; - Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, (MonoObject **)&exc); + Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, &exc); UNLIKELY_UNHANDLED_EXCEPTION(exc); return ptr ? Variant(*ptr) : Variant(); } + + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); + + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) { + return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj); + } + + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { + return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj); + } + + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) { + return GDMonoUtils::Marshal::enumerable_to_array(p_obj); + } + + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { + return GDMonoUtils::Marshal::enumerable_to_array(p_obj); + } } break; case MONO_TYPE_GENERICINST: { 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 = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_dict) { - exc = NULL; + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { + 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 = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_array) { - exc = NULL; + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { + MonoException *exc = NULL; MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc); UNLIKELY_UNHANDLED_EXCEPTION(exc); return *unbox<Array *>(ret); } + + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) { + return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj); + } + + if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { + return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj); + } + + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) { + return GDMonoUtils::Marshal::enumerable_to_array(p_obj); + } + + if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { + return GDMonoUtils::Marshal::enumerable_to_array(p_obj); + } } break; } @@ -880,7 +1019,7 @@ MonoArray *PoolStringArray_to_mono_array(const PoolStringArray &p_array) { for (int i = 0; i < p_array.size(); i++) { MonoString *boxed = mono_string_from_godot(r[i]); - mono_array_set(ret, MonoString *, i, boxed); + mono_array_setref(ret, i, boxed); } return ret; @@ -985,4 +1124,5 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) { 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 4f86e02f87..3fa958ac32 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -32,6 +32,7 @@ #define GDMONOMARSHAL_H #include "core/variant.h" + #include "gd_mono.h" #include "gd_mono_utils.h" @@ -58,6 +59,9 @@ T unbox(MonoObject *p_obj) { Variant::Type managed_to_variant_type(const ManagedType &p_type); +bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type); +bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, ManagedType &r_key_type, ManagedType &r_value_type); + // String String mono_to_utf8_string(MonoString *p_mono_string); diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 7f11e4671d..968b316a3e 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -74,6 +74,10 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) { method_info = MethodInfo(); } +GDMonoClass *GDMonoMethod::get_enclosing_class() const { + return GDMono::get_singleton()->get_class(mono_method_get_class(mono_method)); +} + bool GDMonoMethod::is_static() { return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC; } @@ -105,7 +109,7 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, for (int i = 0; i < params_count; i++) { MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]); - mono_array_set(params, MonoObject *, i, boxed_param); + mono_array_setref(params, i, boxed_param); } MonoException *exc = NULL; diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index f74cef438d..2fc8628f27 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -57,9 +57,11 @@ class GDMonoMethod : public IMonoClassMember { MonoMethod *mono_method; public: - virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_METHOD; } + virtual GDMonoClass *get_enclosing_class() const GD_FINAL; - virtual StringName get_name() GD_FINAL { return name; } + virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_METHOD; } + + virtual StringName get_name() const GD_FINAL { return name; } virtual bool is_static() GD_FINAL; diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index 5842e26241..f1da00638f 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -142,7 +142,7 @@ 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); + mono_array_setref(params, 0, p_value); MonoException *exc = NULL; GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc); if (exc) { diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h index 2700c460b0..d6efa60412 100644 --- a/modules/mono/mono_gd/gd_mono_property.h +++ b/modules/mono/mono_gd/gd_mono_property.h @@ -47,9 +47,11 @@ class GDMonoProperty : public IMonoClassMember { MonoCustomAttrInfo *attributes; public: - virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_PROPERTY; } + virtual GDMonoClass *get_enclosing_class() const GD_FINAL { return owner; } - virtual StringName get_name() GD_FINAL { return name; } + virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_PROPERTY; } + + virtual StringName get_name() const GD_FINAL { return name; } virtual bool is_static() GD_FINAL; virtual Visibility get_visibility() GD_FINAL; diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 6cc1c8afc2..1b32f1126e 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -50,6 +50,7 @@ MonoCache mono_cache; #define CACHE_AND_CHECK(m_var, m_val) \ { \ + CRASH_COND(m_var != NULL); \ m_var = m_val; \ if (!m_var) { \ ERR_EXPLAIN("Mono Cache: Member " #m_var " is null"); \ @@ -63,8 +64,11 @@ MonoCache mono_cache; #define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val) #define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.method_##m_class##_##m_method, m_val) #define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val) +#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.property_##m_class##_##m_property, m_val) -void MonoCache::clear_members() { +void MonoCache::clear_corlib_cache() { + + corlib_cache_updated = false; class_MonoObject = NULL; class_bool = NULL; @@ -81,6 +85,9 @@ void MonoCache::clear_members() { class_String = NULL; class_IntPtr = NULL; + class_System_Collections_IEnumerable = NULL; + class_System_Collections_IDictionary = NULL; + #ifdef DEBUG_ENABLED class_System_Diagnostics_StackTrace = NULL; methodthunk_System_Diagnostics_StackTrace_GetFrames = NULL; @@ -89,6 +96,11 @@ void MonoCache::clear_members() { #endif class_KeyNotFoundException = NULL; +} + +void MonoCache::clear_godot_api_cache() { + + godot_api_cache_updated = false; rawclass_Dictionary = NULL; @@ -105,7 +117,7 @@ void MonoCache::clear_members() { class_NodePath = NULL; class_RID = NULL; class_GodotObject = NULL; - class_GodotReference = NULL; + class_GodotResource = NULL; class_Node = NULL; class_Control = NULL; class_Spatial = NULL; @@ -143,19 +155,33 @@ void MonoCache::clear_members() { methodthunk_GodotObject_Dispose = 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; - task_scheduler_handle = Ref<MonoGCHandle>(); -} + // Start of MarshalUtils methods -void MonoCache::cleanup() { + methodthunk_MarshalUtils_TypeIsGenericArray = NULL; + methodthunk_MarshalUtils_TypeIsGenericDictionary = NULL; - corlib_cache_updated = false; - godot_api_cache_updated = false; + methodthunk_MarshalUtils_ArrayGetElementType = NULL; + methodthunk_MarshalUtils_DictionaryGetKeyValueTypes = NULL; + + methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType = NULL; + methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType = NULL; + methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info = NULL; + methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info = NULL; + + methodthunk_MarshalUtils_MakeGenericArrayType = NULL; + methodthunk_MarshalUtils_MakeGenericDictionaryType = NULL; + + methodthunk_MarshalUtils_EnumerableToArray = NULL; + methodthunk_MarshalUtils_IDictionaryToDictionary = NULL; + methodthunk_MarshalUtils_GenericIDictionaryToDictionary = NULL; + + // End of MarshalUtils methods + + task_scheduler_handle = Ref<MonoGCHandle>(); } #define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class)) @@ -178,6 +204,9 @@ void update_corlib_cache() { CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class())); CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class())); + CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable")); + CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary")); + #ifdef DEBUG_ENABLED CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace")); CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_thunk("GetFrames")); @@ -205,7 +234,7 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath)); CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID)); CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object)); - CACHE_CLASS_AND_CHECK(GodotReference, GODOT_API_CLASS(Reference)); + CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource)); CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node)); CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control)); CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial)); @@ -242,29 +271,44 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, (GodotObject_Dispose)CACHED_CLASS(GodotObject)->get_method_thunk("Dispose", 0)); CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method_thunk("GetPtr", 0)); CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method_thunk("GetPtr", 0)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsArrayGenericType", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsDictionaryGenericType", 1)); CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("SignalCallback", 1)); CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0)); CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0)); + // Start of MarshalUtils methods + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, (TypeIsGenericArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericArray", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, (TypeIsGenericDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericDictionary", 1)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, (GenericIEnumerableIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, (GenericIDictionaryIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, (GenericIEnumerableIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info, (GenericIDictionaryIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 3)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, (MakeGenericArrayType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericArrayType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, (MakeGenericDictionaryType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericDictionaryType", 2)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, (EnumerableToArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("EnumerableToArray", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, (IDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IDictionaryToDictionary", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryToDictionary, (GenericIDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryToDictionary", 2)); + + // End of MarshalUtils methods + #ifdef DEBUG_ENABLED CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4)); #endif // TODO Move to CSharpLanguage::init() and do handle disposal MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr()); - GDMonoUtils::runtime_object_init(task_scheduler); + GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler)); mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler); mono_cache.godot_api_cache_updated = true; } -void clear_cache() { - mono_cache.cleanup(); - mono_cache.clear_members(); -} - MonoObject *unmanaged_get_managed(Object *unmanaged) { if (!unmanaged) @@ -355,11 +399,10 @@ MonoThread *get_current_thread() { return mono_thread_current(); } -void runtime_object_init(MonoObject *p_this_obj) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - // FIXME: Do not use mono_runtime_object_init, it aborts if an exception is thrown - mono_runtime_object_init(p_this_obj); - GD_MONO_END_RUNTIME_INVOKE; +void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) { + GDMonoMethod *ctor = p_class->get_method(".ctor", 0); + ERR_FAIL_NULL(ctor); + ctor->invoke_raw(p_this_obj, NULL, r_exc); } GDMonoClass *get_object_class(MonoObject *p_object) { @@ -421,7 +464,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object); // Construct - GDMonoUtils::runtime_object_init(mono_object); + GDMonoUtils::runtime_object_init(mono_object, p_class); return mono_object; } @@ -431,7 +474,7 @@ MonoObject *create_managed_from(const NodePath &p_from) { ERR_FAIL_NULL_V(mono_object, NULL); // Construct - GDMonoUtils::runtime_object_init(mono_object); + GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(NodePath)); CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from))); @@ -443,7 +486,7 @@ MonoObject *create_managed_from(const RID &p_from) { ERR_FAIL_NULL_V(mono_object, NULL); // Construct - GDMonoUtils::runtime_object_init(mono_object); + GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(RID)); CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from))); @@ -615,11 +658,6 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) { } void debug_unhandled_exception(MonoException *p_exc) { -#ifdef DEBUG_ENABLED - GDMonoUtils::debug_send_unhandled_exception_error(p_exc); - if (ScriptDebugger::get_singleton()) - ScriptDebugger::get_singleton()->idle_poll(); -#endif GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well GD_UNREACHABLE(); } @@ -712,7 +750,118 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool & } void dispose(MonoObject *p_mono_object, MonoException **r_exc) { - invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, (MonoObject **)r_exc); + invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, r_exc); +} + +namespace Marshal { + +MonoBoolean type_is_generic_array(MonoReflectionType *p_reftype) { + TypeIsGenericArray thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype) { + TypeIsGenericDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) { + ArrayGetElementType thunk = CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_array_reftype, r_elem_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); } +void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { + DictionaryGetKeyValueTypes thunk = CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_dict_reftype, r_key_reftype, r_value_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); +} + +MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) { + GenericIEnumerableIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) { + GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) { + GenericIEnumerableIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_elem_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { + GenericIDictionaryIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_key_reftype, r_value_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +Array enumerable_to_array(MonoObject *p_enumerable) { + Array result; + EnumerableToArray thunk = CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_enumerable, &result, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return result; +} + +Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) { + Dictionary result; + IDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_idictionary, &result, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return result; +} + +Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) { + Dictionary result; + GenericIDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_generic_idictionary, &result, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return result; +} + +GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) { + MakeGenericArrayType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType); + MonoException *exc = NULL; + MonoReflectionType *reftype = invoke_method_thunk(thunk, p_elem_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); +} + +GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) { + MakeGenericDictionaryType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType); + MonoException *exc = NULL; + MonoReflectionType *reftype = invoke_method_thunk(thunk, p_key_reftype, p_value_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); +} + +} // namespace Marshal + +// namespace Marshal + } // namespace GDMonoUtils diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index e88bf1ced9..00e1ffdd31 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -49,18 +49,56 @@ namespace GDMonoUtils { -typedef void (*GodotObject_Dispose)(MonoObject *, 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 **); +typedef void (*GodotObject_Dispose)(MonoObject *, MonoException **); +typedef Array *(*Array_GetPtr)(MonoObject *, MonoException **); +typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoException **); +typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoException **); +typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoException **); +typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoException **); +typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoException **); +typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoException **); + +typedef MonoBoolean (*TypeIsGenericArray)(MonoReflectionType *, MonoException **); +typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoException **); + +typedef void (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **); +typedef void (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); + +typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType)(MonoReflectionType *, MonoException **); +typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType)(MonoReflectionType *, MonoException **); +typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType_with_info)(MonoReflectionType *, MonoReflectionType **, MonoException **); +typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType_with_info)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); + +typedef MonoReflectionType *(*MakeGenericArrayType)(MonoReflectionType *, MonoException **); +typedef MonoReflectionType *(*MakeGenericDictionaryType)(MonoReflectionType *, MonoReflectionType *, MonoException **); + +typedef void (*EnumerableToArray)(MonoObject *, Array *, MonoException **); +typedef void (*IDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **); +typedef void (*GenericIDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **); + +namespace Marshal { + +MonoBoolean type_is_generic_array(MonoReflectionType *p_reftype); +MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype); + +void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype); +void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype); + +MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype); +MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype); +MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype); +MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype); + +GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype); +GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype); + +Array enumerable_to_array(MonoObject *p_enumerable); +Dictionary idictionary_to_dictionary(MonoObject *p_idictionary); +Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary); + +} // namespace Marshal + +// End of MarshalUtils methods struct MonoCache { @@ -83,6 +121,9 @@ struct MonoCache { GDMonoClass *class_String; GDMonoClass *class_IntPtr; + GDMonoClass *class_System_Collections_IEnumerable; + GDMonoClass *class_System_Collections_IDictionary; + #ifdef DEBUG_ENABLED GDMonoClass *class_System_Diagnostics_StackTrace; StackTrace_GetFrames methodthunk_System_Diagnostics_StackTrace_GetFrames; @@ -108,7 +149,7 @@ struct MonoCache { GDMonoClass *class_NodePath; GDMonoClass *class_RID; GDMonoClass *class_GodotObject; - GDMonoClass *class_GodotReference; + GDMonoClass *class_GodotResource; GDMonoClass *class_Node; GDMonoClass *class_Control; GDMonoClass *class_Spatial; @@ -146,25 +187,43 @@ struct MonoCache { GodotObject_Dispose methodthunk_GodotObject_Dispose; 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; + // Start of MarshalUtils methods + + TypeIsGenericArray methodthunk_MarshalUtils_TypeIsGenericArray; + TypeIsGenericDictionary methodthunk_MarshalUtils_TypeIsGenericDictionary; + + ArrayGetElementType methodthunk_MarshalUtils_ArrayGetElementType; + DictionaryGetKeyValueTypes methodthunk_MarshalUtils_DictionaryGetKeyValueTypes; + + GenericIEnumerableIsAssignableFromType methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType; + GenericIDictionaryIsAssignableFromType methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType; + GenericIEnumerableIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info; + GenericIDictionaryIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info; + + MakeGenericArrayType methodthunk_MarshalUtils_MakeGenericArrayType; + MakeGenericDictionaryType methodthunk_MarshalUtils_MakeGenericDictionaryType; + + EnumerableToArray methodthunk_MarshalUtils_EnumerableToArray; + IDictionaryToDictionary methodthunk_MarshalUtils_IDictionaryToDictionary; + GenericIDictionaryToDictionary methodthunk_MarshalUtils_GenericIDictionaryToDictionary; + + // End of MarshalUtils methods + Ref<MonoGCHandle> task_scheduler_handle; bool corlib_cache_updated; bool godot_api_cache_updated; - void clear_members(); - void cleanup(); + void clear_corlib_cache(); + void clear_godot_api_cache(); MonoCache() { - corlib_cache_updated = false; - godot_api_cache_updated = false; - - clear_members(); + clear_corlib_cache(); + clear_godot_api_cache(); } }; @@ -172,7 +231,13 @@ extern MonoCache mono_cache; void update_corlib_cache(); void update_godot_api_cache(); -void clear_cache(); + +inline void clear_corlib_cache() { + mono_cache.clear_corlib_cache(); +} +inline void clear_godot_api_cache() { + mono_cache.clear_godot_api_cache(); +} _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) { p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2); @@ -194,7 +259,7 @@ _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); +void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = NULL); GDMonoClass *get_object_class(MonoObject *p_object); GDMonoClass *type_get_proxy_class(const StringName &p_type); @@ -255,6 +320,7 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc); #define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field) #define CACHED_METHOD(m_class, m_method) (GDMonoUtils::mono_cache.method_##m_class##_##m_method) #define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method) +#define CACHED_PROPERTY(m_class, m_property) (GDMonoUtils::mono_cache.property_##m_class##_##m_property) #ifdef REAL_T_IS_DOUBLE #define REAL_T_MONOCLASS CACHED_CLASS_RAW(double) diff --git a/modules/mono/mono_gd/i_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h index 553d9edc72..f4de4e3230 100644 --- a/modules/mono/mono_gd/i_mono_class_member.h +++ b/modules/mono/mono_gd/i_mono_class_member.h @@ -53,9 +53,11 @@ public: virtual ~IMonoClassMember() {} - virtual MemberType get_member_type() = 0; + virtual GDMonoClass *get_enclosing_class() const = 0; - virtual StringName get_name() = 0; + virtual MemberType get_member_type() const = 0; + + virtual StringName get_name() const = 0; virtual bool is_static() = 0; diff --git a/modules/mono/mono_gd/managed_type.cpp b/modules/mono/mono_gd/managed_type.cpp new file mode 100644 index 0000000000..9f736b71cd --- /dev/null +++ b/modules/mono/mono_gd/managed_type.cpp @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* managed_type.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "managed_type.h" + +#include "gd_mono.h" +#include "gd_mono_class.h" + +ManagedType ManagedType::from_class(GDMonoClass *p_class) { + return ManagedType(mono_type_get_type(p_class->get_mono_type()), p_class); +} + +ManagedType ManagedType::from_class(MonoClass *p_mono_class) { + GDMonoClass *tclass = GDMono::get_singleton()->get_class(p_mono_class); + ERR_FAIL_COND_V(!tclass, ManagedType()); + + return ManagedType(mono_type_get_type(tclass->get_mono_type()), tclass); +} + +ManagedType ManagedType::from_type(MonoType *p_mono_type) { + MonoClass *mono_class = mono_class_from_mono_type(p_mono_type); + GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_class); + ERR_FAIL_COND_V(!tclass, ManagedType()); + + return ManagedType(mono_type_get_type(p_mono_type), tclass); +} + +ManagedType ManagedType::from_reftype(MonoReflectionType *p_mono_reftype) { + MonoType *mono_type = mono_reflection_type_get_type(p_mono_reftype); + return from_type(mono_type); +} diff --git a/modules/mono/mono_gd/managed_type.h b/modules/mono/mono_gd/managed_type.h new file mode 100644 index 0000000000..a537e56aea --- /dev/null +++ b/modules/mono/mono_gd/managed_type.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* managed_type.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef MANAGED_TYPE_H +#define MANAGED_TYPE_H + +#include <mono/metadata/object.h> + +#include "gd_mono_header.h" + +struct ManagedType { + int type_encoding; + GDMonoClass *type_class; + + static ManagedType from_class(GDMonoClass *p_class); + static ManagedType from_class(MonoClass *p_mono_class); + static ManagedType from_type(MonoType *p_mono_type); + static ManagedType from_reftype(MonoReflectionType *p_mono_reftype); + + ManagedType() : + type_encoding(0), + type_class(NULL) { + } + + ManagedType(int p_type_encoding, GDMonoClass *p_type_class) : + type_encoding(p_type_encoding), + type_class(p_type_class) { + } +}; + +#endif // MANAGED_TYPE_H |