diff options
Diffstat (limited to 'modules/mono/mono_gd')
26 files changed, 1117 insertions, 892 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index eb4c263745..3298c5da4c 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -58,14 +58,25 @@ #ifdef ANDROID_ENABLED #include "android_mono_config.h" -#include "gd_mono_android.h" +#include "support/android_support.h" +#elif defined(IPHONE_ENABLED) +#include "support/ios_support.h" +#endif + +#if defined(TOOL_ENABLED) && defined(GD_MONO_SINGLE_APPDOMAIN) +// This will no longer be the case if we replace appdomains with AssemblyLoadContext +#error "Editor build requires support for multiple appdomains" +#endif + +#if defined(GD_MONO_HOT_RELOAD) && defined(GD_MONO_SINGLE_APPDOMAIN) +#error "Hot reloading requires multiple appdomains" #endif // TODO: // This has turn into a gigantic mess. There's too much going on here. Too much #ifdef as well. // It's just painful to read... It needs to be re-structured. Please, clean this up, future me. -GDMono *GDMono::singleton = NULL; +GDMono *GDMono::singleton = nullptr; namespace { @@ -118,12 +129,8 @@ void gd_mono_profiler_init() { } } -#if defined(DEBUG_ENABLED) - void gd_mono_debug_init() { - mono_debug_init(MONO_DEBUG_FORMAT_MONO); - CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8(); #ifdef TOOLS_ENABLED @@ -148,6 +155,10 @@ void gd_mono_debug_init() { return; // Exported games don't use the project settings to setup the debugger agent #endif + // Debugging enabled + + mono_debug_init(MONO_DEBUG_FORMAT_MONO); + // --debugger-agent=help const char *options[] = { "--soft-breakpoints", @@ -156,7 +167,6 @@ void gd_mono_debug_init() { mono_jit_parse_options(2, (char **)options); } -#endif // defined(DEBUG_ENABLED) #endif // !defined(JAVASCRIPT_ENABLED) #if defined(JAVASCRIPT_ENABLED) @@ -164,6 +174,7 @@ MonoDomain *gd_initialize_mono_runtime() { const char *vfs_prefix = "managed"; int enable_debugging = 0; + // TODO: Provide a way to enable debugging on WASM release builds. #ifdef DEBUG_ENABLED enable_debugging = 1; #endif @@ -174,11 +185,16 @@ MonoDomain *gd_initialize_mono_runtime() { } #else MonoDomain *gd_initialize_mono_runtime() { -#ifdef DEBUG_ENABLED gd_mono_debug_init(); + +#if defined(IPHONE_ENABLED) || defined(ANDROID_ENABLED) + // I don't know whether this actually matters or not + const char *runtime_version = "mobile"; +#else + const char *runtime_version = "v4.0.30319"; #endif - return mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319"); + return mono_jit_init_version("GodotEngine.RootDomain", runtime_version); } #endif @@ -314,14 +330,22 @@ void GDMono::initialize() { determine_mono_dirs(assembly_rootdir, config_dir); // Leak if we call mono_set_dirs more than once - mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : NULL, - config_dir.length() ? config_dir.utf8().get_data() : NULL); + mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : nullptr, + config_dir.length() ? config_dir.utf8().get_data() : nullptr); add_mono_shared_libs_dir_to_path(); #endif +#ifdef ANDROID_ENABLED + mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data()); +#else + mono_config_parse(nullptr); +#endif + #if defined(ANDROID_ENABLED) - GDMonoAndroid::initialize(); + gdmono::android::support::initialize(); +#elif defined(IPHONE_ENABLED) + gdmono::ios::support::initialize(); #endif GDMonoAssembly::initialize(); @@ -330,13 +354,7 @@ void GDMono::initialize() { gd_mono_profiler_init(); #endif -#ifdef ANDROID_ENABLED - mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data()); -#else - mono_config_parse(NULL); -#endif - - mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL); + mono_install_unhandled_exception_hook(&unhandled_exception_hook, nullptr); #ifndef TOOLS_ENABLED // Exported games that don't use C# must still work. They likely don't ship with mscorlib. @@ -355,7 +373,7 @@ void GDMono::initialize() { #endif // NOTE: Internal calls must be registered after the Mono runtime initialization. - // Otherwise registration fails with the error: 'assertion 'hash != NULL' failed'. + // Otherwise registration fails with the error: 'assertion 'hash != nullptr' failed'. root_domain = gd_initialize_mono_runtime(); ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime."); @@ -371,15 +389,19 @@ void GDMono::initialize() { print_verbose("Mono: Runtime initialized"); #if defined(ANDROID_ENABLED) - GDMonoAndroid::register_internal_calls(); + gdmono::android::support::register_internal_calls(); #endif // mscorlib assembly MUST be present at initialization bool corlib_loaded = _load_corlib_assembly(); ERR_FAIL_COND_MSG(!corlib_loaded, "Mono: Failed to load mscorlib assembly."); +#ifndef GD_MONO_SINGLE_APPDOMAIN Error domain_load_err = _load_scripts_domain(); ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain."); +#else + scripts_domain = root_domain; +#endif _register_internal_calls(); @@ -491,11 +513,15 @@ void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) { assemblies[p_domain_id][p_assembly->get_name()] = p_assembly; } -GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) { +GDMonoAssembly *GDMono::get_loaded_assembly(const String &p_name) { + + if (p_name == "mscorlib") + return get_corlib_assembly(); MonoDomain *domain = mono_domain_get(); uint32_t domain_id = domain ? mono_domain_get_id(domain) : 0; - return assemblies[domain_id].getptr(p_name); + GDMonoAssembly **result = assemblies[domain_id].getptr(p_name); + return result ? *result : nullptr; } bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) { @@ -517,7 +543,7 @@ bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMo print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "..."); MonoImageOpenStatus status = MONO_IMAGE_OK; - MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly); + MonoAssembly *assembly = mono_assembly_load_full(p_aname, nullptr, &status, p_refonly); if (!assembly) return false; @@ -528,7 +554,7 @@ bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMo GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name); - ERR_FAIL_COND_V(stored_assembly == NULL, false); + ERR_FAIL_COND_V(stored_assembly == nullptr, false); ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false); *r_assembly = *stored_assembly; @@ -549,14 +575,6 @@ bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMo if (!assembly) return false; -#ifdef DEBUG_ENABLED - uint32_t domain_id = mono_domain_get_id(mono_domain_get()); - GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name); - - ERR_FAIL_COND_V(stored_assembly == NULL, false); - ERR_FAIL_COND_V(*stored_assembly != assembly, false); -#endif - *r_assembly = assembly; print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path()); @@ -576,15 +594,15 @@ ApiAssemblyInfo::Version ApiAssemblyInfo::Version::get_from_loaded_assembly(GDMo if (nativecalls_klass) { GDMonoField *api_hash_field = nativecalls_klass->get_field("godot_api_hash"); if (api_hash_field) - api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(NULL)); + api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(nullptr)); GDMonoField *binds_ver_field = nativecalls_klass->get_field("bindings_version"); if (binds_ver_field) - api_assembly_version.bindings_version = GDMonoMarshal::unbox<uint32_t>(binds_ver_field->get_value(NULL)); + api_assembly_version.bindings_version = GDMonoMarshal::unbox<uint32_t>(binds_ver_field->get_value(nullptr)); GDMonoField *cs_glue_ver_field = nativecalls_klass->get_field("cs_glue_version"); if (cs_glue_ver_field) - api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(NULL)); + api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(nullptr)); } return api_assembly_version; @@ -715,7 +733,7 @@ bool GDMono::_temp_domain_load_are_assemblies_out_of_sync(const String &p_config GDMono::LoadedApiAssembly temp_editor_api_assembly; if (!_try_load_api_assemblies(temp_core_api_assembly, temp_editor_api_assembly, - p_config, /* refonly: */ true, /* loaded_callback: */ NULL)) { + p_config, /* refonly: */ true, /* loaded_callback: */ nullptr)) { return temp_core_api_assembly.out_of_sync || temp_editor_api_assembly.out_of_sync; } @@ -894,8 +912,8 @@ void GDMono::_load_api_assemblies() { bool api_assemblies_loaded = _try_load_api_assemblies_preset(); +#if defined(TOOLS_ENABLED) && !defined(GD_MONO_SINGLE_APPDOMAIN) if (!api_assemblies_loaded) { -#ifdef TOOLS_ENABLED // The API assemblies are out of sync or some other error happened. Fine, try one more time, but // this time update them from the prebuilt assemblies directory before trying to load them again. @@ -916,8 +934,8 @@ void GDMono::_load_api_assemblies() { // 4. Try loading the updated assemblies api_assemblies_loaded = _try_load_api_assemblies_preset(); -#endif } +#endif if (!api_assemblies_loaded) { // welp... too bad @@ -982,8 +1000,8 @@ void GDMono::_install_trace_listener() { GDMonoClass *debug_utils = get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, "DebuggingUtils"); GDMonoMethod *install_func = debug_utils->get_method("InstallTraceListener"); - MonoException *exc = NULL; - install_func->invoke_raw(NULL, NULL, &exc); + MonoException *exc = nullptr; + install_func->invoke_raw(nullptr, nullptr, &exc); if (exc) { GDMonoUtils::debug_print_unhandled_exception(exc); ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener."); @@ -991,9 +1009,10 @@ void GDMono::_install_trace_listener() { #endif } +#ifndef GD_MONO_SINGLE_APPDOMAIN Error GDMono::_load_scripts_domain() { - ERR_FAIL_COND_V(scripts_domain != NULL, ERR_BUG); + ERR_FAIL_COND_V(scripts_domain != nullptr, ERR_BUG); print_verbose("Mono: Loading scripts domain..."); @@ -1010,7 +1029,7 @@ Error GDMono::_unload_scripts_domain() { ERR_FAIL_NULL_V(scripts_domain, ERR_BUG); - print_verbose("Mono: Unloading scripts domain..."); + print_verbose("Mono: Finalizing scripts domain..."); if (mono_domain_get() != root_domain) mono_domain_set(root_domain, true); @@ -1029,21 +1048,23 @@ Error GDMono::_unload_scripts_domain() { _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain)); - core_api_assembly.assembly = NULL; + core_api_assembly.assembly = nullptr; #ifdef TOOLS_ENABLED - editor_api_assembly.assembly = NULL; + editor_api_assembly.assembly = nullptr; #endif - project_assembly = NULL; + project_assembly = nullptr; #ifdef TOOLS_ENABLED - tools_assembly = NULL; - tools_project_editor_assembly = NULL; + tools_assembly = nullptr; + tools_project_editor_assembly = nullptr; #endif MonoDomain *domain = scripts_domain; - scripts_domain = NULL; + scripts_domain = nullptr; + + print_verbose("Mono: Unloading scripts domain..."); - MonoException *exc = NULL; + MonoException *exc = nullptr; mono_domain_try_unload(domain, (MonoObject **)&exc); if (exc) { @@ -1054,6 +1075,7 @@ Error GDMono::_unload_scripts_domain() { return OK; } +#endif #ifdef GD_MONO_HOT_RELOAD Error GDMono::reload_scripts_domain() { @@ -1092,9 +1114,10 @@ Error GDMono::reload_scripts_domain() { } #endif +#ifndef GD_MONO_SINGLE_APPDOMAIN Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { - CRASH_COND(p_domain == NULL); + CRASH_COND(p_domain == nullptr); CRASH_COND(p_domain == GDMono::get_singleton()->get_scripts_domain()); // Should use _unload_scripts_domain() instead String domain_name = mono_domain_get_friendly_name(p_domain); @@ -1112,7 +1135,7 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { _domain_assemblies_cleanup(mono_domain_get_id(p_domain)); - MonoException *exc = NULL; + MonoException *exc = nullptr; mono_domain_try_unload(p_domain, (MonoObject **)&exc); if (exc) { @@ -1123,6 +1146,7 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { return OK; } +#endif GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) { @@ -1134,7 +1158,7 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) { uint32_t domain_id = mono_domain_get_id(mono_domain_get()); HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id]; - const String *k = NULL; + const String *k = nullptr; while ((k = domain_assemblies.next(k))) { GDMonoAssembly *assembly = domain_assemblies.get(*k); if (assembly->get_image() == image) { @@ -1145,30 +1169,34 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) { } } - return NULL; + return nullptr; } GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &p_name) { + GDMonoClass *klass = corlib_assembly->get_class(p_namespace, p_name); + if (klass) + return klass; + uint32_t domain_id = mono_domain_get_id(mono_domain_get()); HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id]; - const String *k = NULL; + const String *k = nullptr; while ((k = domain_assemblies.next(k))) { GDMonoAssembly *assembly = domain_assemblies.get(*k); - GDMonoClass *klass = assembly->get_class(p_namespace, p_name); + klass = assembly->get_class(p_namespace, p_name); if (klass) return klass; } - return NULL; + return nullptr; } void GDMono::_domain_assemblies_cleanup(uint32_t p_domain_id) { HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id]; - const String *k = NULL; + const String *k = nullptr; while ((k = domain_assemblies.next(k))) { memdelete(domain_assemblies.get(*k)); } @@ -1202,14 +1230,14 @@ GDMono::GDMono() { runtime_initialized = false; finalizing_scripts_domain = false; - root_domain = NULL; - scripts_domain = NULL; + root_domain = nullptr; + scripts_domain = nullptr; - corlib_assembly = NULL; - project_assembly = NULL; + corlib_assembly = nullptr; + project_assembly = nullptr; #ifdef TOOLS_ENABLED - tools_assembly = NULL; - tools_project_editor_assembly = NULL; + tools_assembly = nullptr; + tools_project_editor_assembly = nullptr; #endif api_core_hash = 0; @@ -1223,18 +1251,50 @@ GDMono::GDMono() { GDMono::~GDMono() { if (is_runtime_initialized()) { +#ifndef GD_MONO_SINGLE_APPDOMAIN if (scripts_domain) { Error err = _unload_scripts_domain(); if (err != OK) { ERR_PRINT("Mono: Failed to unload scripts domain."); } } +#else + CRASH_COND(scripts_domain != root_domain); + + print_verbose("Mono: Finalizing scripts domain..."); + + if (mono_domain_get() != root_domain) + mono_domain_set(root_domain, true); + + finalizing_scripts_domain = true; + + if (!mono_domain_finalize(root_domain, 2000)) { + ERR_PRINT("Mono: Domain finalization timeout."); + } - const uint32_t *k = NULL; + finalizing_scripts_domain = false; + + mono_gc_collect(mono_gc_max_generation()); + + GDMonoCache::clear_godot_api_cache(); + + _domain_assemblies_cleanup(mono_domain_get_id(root_domain)); + + core_api_assembly.assembly = nullptr; + + project_assembly = nullptr; + + root_domain = nullptr; + scripts_domain = nullptr; + + // Leave the rest to 'mono_jit_cleanup' +#endif + + const uint32_t *k = nullptr; while ((k = assemblies.next(k))) { HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies.get(*k); - const String *kk = NULL; + const String *kk = nullptr; while ((kk = domain_assemblies.next(kk))) { memdelete(domain_assemblies.get(*kk)); } @@ -1245,22 +1305,22 @@ GDMono::~GDMono() { mono_jit_cleanup(root_domain); -#if defined(ANDROID_ENABLED) - GDMonoAndroid::cleanup(); -#endif - print_verbose("Mono: Finalized"); runtime_initialized = false; } +#if defined(ANDROID_ENABLED) + gdmono::android::support::cleanup(); +#endif + if (gdmono_log) memdelete(gdmono_log); - singleton = NULL; + singleton = nullptr; } -_GodotSharp *_GodotSharp::singleton = NULL; +_GodotSharp *_GodotSharp::singleton = nullptr; void _GodotSharp::attach_thread() { @@ -1288,7 +1348,7 @@ int32_t _GodotSharp::get_scripts_domain_id() { bool _GodotSharp::is_scripts_domain_loaded() { - return GDMono::get_singleton()->is_runtime_initialized() && GDMono::get_singleton()->get_scripts_domain() != NULL; + return GDMono::get_singleton()->is_runtime_initialized() && GDMono::get_singleton()->get_scripts_domain() != nullptr; } bool _GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) { @@ -1327,7 +1387,10 @@ bool _GodotSharp::is_runtime_initialized() { void _GodotSharp::_reload_assemblies(bool p_soft_reload) { #ifdef GD_MONO_HOT_RELOAD - CSharpLanguage::get_singleton()->reload_assemblies(p_soft_reload); + // This method may be called more than once with `call_deferred`, so we need to check + // again if reloading is needed to avoid reloading multiple times unnecessarily. + if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) + CSharpLanguage::get_singleton()->reload_assemblies(p_soft_reload); #endif } @@ -1353,5 +1416,5 @@ _GodotSharp::_GodotSharp() { _GodotSharp::~_GodotSharp() { - singleton = NULL; + singleton = nullptr; } diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 9528c64f8d..4898833e8e 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -91,7 +91,7 @@ public: bool out_of_sync; LoadedApiAssembly() : - assembly(NULL), + assembly(nullptr), out_of_sync(false) { } }; @@ -144,8 +144,10 @@ private: void _register_internal_calls(); +#ifndef GD_MONO_SINGLE_APPDOMAIN Error _load_scripts_domain(); Error _unload_scripts_domain(); +#endif void _domain_assemblies_cleanup(uint32_t p_domain_id); @@ -198,7 +200,7 @@ public: #ifdef TOOLS_ENABLED bool copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config); - String update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync = NULL, const bool *p_editor_api_out_of_sync = NULL); + String update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync = nullptr, const bool *p_editor_api_out_of_sync = nullptr); #endif static GDMono *get_singleton() { return singleton; } @@ -209,7 +211,7 @@ public: // Do not use these, unless you know what you're doing void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly); - GDMonoAssembly **get_loaded_assembly(const String &p_name); + GDMonoAssembly *get_loaded_assembly(const String &p_name); _FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized && !mono_runtime_is_shutting_down() /* stays true after shutdown finished */; } @@ -263,7 +265,7 @@ public: this->prev_domain = prev_domain; mono_domain_set(p_domain, false); } else { - this->prev_domain = NULL; + this->prev_domain = nullptr; } } diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index 6da1db249c..8439769d84 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -42,9 +42,6 @@ #include "gd_mono_cache.h" #include "gd_mono_class.h" -bool GDMonoAssembly::no_search = false; -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, const String &p_custom_bcl_dir) { @@ -94,19 +91,30 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin #endif } +// This is how these assembly loading hooks work: +// +// - The 'search' hook checks if the assembly has already been loaded, to avoid loading again. +// - The 'preload' hook does the actual loading and is only called if the +// 'search' hook didn't find the assembly in the list of loaded assemblies. +// - The 'load' hook is called after the assembly has been loaded. Its job is to add the +// assembly to the list of loaded assemblies so that the 'search' hook can look it up. + void GDMonoAssembly::assembly_load_hook(MonoAssembly *assembly, void *user_data) { - if (no_search) - return; - - // If our search and preload hooks fail to load the assembly themselves, the mono runtime still might. - // Just do Assembly.LoadFrom("/Full/Path/On/Disk.dll"); - // In this case, we wouldn't have the assembly known in GDMono, which causes crashes - // if any class inside the assembly is looked up by Godot. - // And causing a lookup like that is as easy as throwing an exception defined in it... - // No, we can't make the assembly load hooks smart enough because they get passed a MonoAssemblyName* only, - // not the disk path passed to say Assembly.LoadFrom(). - _wrap_mono_assembly(assembly); + String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly))); + + MonoImage *image = mono_assembly_get_image(assembly); + + GDMonoAssembly *gdassembly = memnew(GDMonoAssembly(name, image, assembly)); + +#ifdef GD_MONO_HOT_RELOAD + const char *path = mono_image_get_filename(image); + if (FileAccess::exists(path)) + gdassembly->modified_time = FileAccess::get_modified_time(path); +#endif + + MonoDomain *domain = mono_domain_get(); + GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, gdassembly); } MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) { @@ -132,71 +140,24 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d String name = String::utf8(mono_assembly_name_get_name(aname)); bool has_extension = name.ends_with(".dll") || name.ends_with(".exe"); - if (no_search) - return NULL; - - GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name); + GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name); if (loaded_asm) - return (*loaded_asm)->get_assembly(); - - no_search = true; // Avoid the recursion madness - - GDMonoAssembly *res = _load_assembly_search(name, search_dirs, refonly); - - no_search = false; + return loaded_asm->get_assembly(); - return res ? res->get_assembly() : NULL; + return nullptr; } -static thread_local MonoImage *image_corlib_loading = NULL; - MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, void *user_data, bool refonly) { (void)user_data; // UNUSED - { - // If we find the assembly here, we load it with 'mono_assembly_load_from_full', - // which in turn invokes load hooks before returning the MonoAssembly to us. - // One of the load hooks is 'load_aot_module'. This hook can end up calling preload hooks - // again for the same assembly in certain in certain circumstances (the 'do_load_image' part). - // If this is the case and we return NULL due to the no_search condition below, - // it will result in an internal crash later on. Therefore we need to return the assembly we didn't - // get yet from 'mono_assembly_load_from_full'. Luckily we have the image, which already got it. - // This must be done here. If done in search hooks, it would cause 'mono_assembly_load_from_full' - // to think another MonoAssembly for this assembly was already loaded, making it delete its own, - // when in fact both pointers were the same... This hooks thing is confusing. - if (image_corlib_loading) { - return mono_image_get_assembly(image_corlib_loading); - } - } - - if (no_search) - return NULL; - - no_search = true; - in_preload = true; - String name = String::utf8(mono_assembly_name_get_name(aname)); - bool has_extension = name.ends_with(".dll"); - - GDMonoAssembly *res = NULL; - if (has_extension ? name == "mscorlib.dll" : name == "mscorlib") { - GDMonoAssembly **stored_assembly = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name); - if (stored_assembly) - return (*stored_assembly)->get_assembly(); - - res = _load_assembly_search("mscorlib.dll", search_dirs, refonly); - } - - no_search = false; - in_preload = false; - - return res ? res->get_assembly() : NULL; + return _load_assembly_search(name, search_dirs, refonly); } -GDMonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly) { +MonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly) { - GDMonoAssembly *res = NULL; + MonoAssembly *res = nullptr; String path; bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe"); @@ -207,28 +168,28 @@ GDMonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, cons if (has_extension) { path = search_dir.plus_file(p_name); if (FileAccess::exists(path)) { - res = _load_assembly_from(p_name.get_basename(), path, p_refonly); - if (res != NULL) + res = _real_load_assembly_from(path, p_refonly); + if (res != nullptr) return res; } } else { path = search_dir.plus_file(p_name + ".dll"); if (FileAccess::exists(path)) { - res = _load_assembly_from(p_name, path, p_refonly); - if (res != NULL) + res = _real_load_assembly_from(path, p_refonly); + if (res != nullptr) return res; } path = search_dir.plus_file(p_name + ".exe"); if (FileAccess::exists(path)) { - res = _load_assembly_from(p_name, path, p_refonly); - if (res != NULL) + res = _real_load_assembly_from(path, p_refonly); + if (res != nullptr) return res; } } } - return NULL; + return nullptr; } String GDMonoAssembly::find_assembly(const String &p_name) { @@ -258,91 +219,50 @@ String GDMonoAssembly::find_assembly(const String &p_name) { return String(); } -GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) { - - GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path)); - - Error err = assembly->load(p_refonly); - - if (err != OK) { - memdelete(assembly); - ERR_FAIL_V(NULL); - } - - MonoDomain *domain = mono_domain_get(); - GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, assembly); - - return assembly; -} - -void GDMonoAssembly::_wrap_mono_assembly(MonoAssembly *assembly) { - String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly))); - - MonoImage *image = mono_assembly_get_image(assembly); - - GDMonoAssembly *gdassembly = memnew(GDMonoAssembly(name, mono_image_get_filename(image))); - Error err = gdassembly->wrapper_for_image(image); - - if (err != OK) { - memdelete(gdassembly); - ERR_FAIL(); - } - - MonoDomain *domain = mono_domain_get(); - GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, gdassembly); -} - void GDMonoAssembly::initialize() { fill_search_dirs(search_dirs); - mono_install_assembly_search_hook(&assembly_search_hook, NULL); - mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, NULL); - mono_install_assembly_preload_hook(&assembly_preload_hook, NULL); - mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, NULL); - mono_install_assembly_load_hook(&assembly_load_hook, NULL); + mono_install_assembly_search_hook(&assembly_search_hook, nullptr); + mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, nullptr); + mono_install_assembly_preload_hook(&assembly_preload_hook, nullptr); + mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, nullptr); + mono_install_assembly_load_hook(&assembly_load_hook, nullptr); } -Error GDMonoAssembly::load(bool p_refonly) { - - ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE); - - refonly = p_refonly; +MonoAssembly *GDMonoAssembly::_real_load_assembly_from(const String &p_path, bool p_refonly) { - uint64_t last_modified_time = FileAccess::get_modified_time(path); - - Vector<uint8_t> data = FileAccess::get_file_as_array(path); - ERR_FAIL_COND_V(data.empty(), ERR_FILE_CANT_READ); + Vector<uint8_t> data = FileAccess::get_file_as_array(p_path); + ERR_FAIL_COND_V_MSG(data.empty(), nullptr, "Could read the assembly in the specified location"); String image_filename; #ifdef ANDROID_ENABLED - if (path.begins_with("res://")) { - image_filename = path.substr(6, path.length()); + if (p_path.begins_with("res://")) { + image_filename = p_path.substr(6, p_path.length()); } else { - image_filename = ProjectSettings::get_singleton()->globalize_path(path); + image_filename = ProjectSettings::get_singleton()->globalize_path(p_path); } #else // FIXME: globalize_path does not work on exported games - image_filename = ProjectSettings::get_singleton()->globalize_path(path); + image_filename = ProjectSettings::get_singleton()->globalize_path(p_path); #endif MonoImageOpenStatus status = MONO_IMAGE_OK; - image = mono_image_open_from_data_with_name( + MonoImage *image = mono_image_open_from_data_with_name( (char *)&data[0], data.size(), - true, &status, refonly, - image_filename.utf8().get_data()); + true, &status, p_refonly, + image_filename.utf8()); - ERR_FAIL_COND_V(status != MONO_IMAGE_OK, ERR_FILE_CANT_OPEN); - ERR_FAIL_NULL_V(image, ERR_FILE_CANT_OPEN); + ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !image, nullptr, "Failed to open assembly image from the loaded data"); #ifdef DEBUG_ENABLED Vector<uint8_t> pdb_data; - String pdb_path(path + ".pdb"); + String pdb_path(p_path + ".pdb"); if (!FileAccess::exists(pdb_path)) { - pdb_path = path.get_basename() + ".pdb"; // without .dll + pdb_path = p_path.get_basename() + ".pdb"; // without .dll if (!FileAccess::exists(pdb_path)) goto no_pdb; @@ -357,44 +277,21 @@ no_pdb: #endif - bool is_corlib_preload = in_preload && name == "mscorlib"; - - if (is_corlib_preload) - image_corlib_loading = image; + status = MONO_IMAGE_OK; - assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, refonly); + MonoAssembly *assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, p_refonly); - if (is_corlib_preload) - image_corlib_loading = NULL; - - ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN); + ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !assembly, nullptr, "Failed to load assembly for image"); // Decrement refcount which was previously incremented by mono_image_open_from_data_with_name mono_image_close(image); - loaded = true; - modified_time = last_modified_time; - - return OK; -} - -Error GDMonoAssembly::wrapper_for_image(MonoImage *p_image) { - - ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE); - - assembly = mono_image_get_assembly(p_image); - ERR_FAIL_NULL_V(assembly, FAILED); - - image = p_image; - - loaded = true; - - return OK; + return assembly; } void GDMonoAssembly::unload() { - ERR_FAIL_COND(!loaded); + ERR_FAIL_NULL(image); // Should not be called if already unloaded for (Map<MonoClass *, GDMonoClass *>::Element *E = cached_raw.front(); E; E = E->next()) { memdelete(E->value()); @@ -403,14 +300,17 @@ void GDMonoAssembly::unload() { cached_classes.clear(); cached_raw.clear(); - assembly = NULL; - image = NULL; - loaded = false; + assembly = nullptr; + image = nullptr; +} + +String GDMonoAssembly::get_path() const { + return String::utf8(mono_image_get_filename(image)); } GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const StringName &p_name) { - ERR_FAIL_COND_V(!loaded, NULL); + ERR_FAIL_NULL_V(image, nullptr); ClassKey key(p_namespace, p_name); @@ -422,7 +322,7 @@ GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const Stri MonoClass *mono_class = mono_class_from_name(image, String(p_namespace).utf8(), String(p_name).utf8()); if (!mono_class) - return NULL; + return nullptr; GDMonoClass *wrapped_class = memnew(GDMonoClass(p_namespace, p_name, mono_class, this)); @@ -434,7 +334,7 @@ GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const Stri GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) { - ERR_FAIL_COND_V(!loaded, NULL); + ERR_FAIL_NULL_V(image, nullptr); Map<MonoClass *, GDMonoClass *>::Element *match = cached_raw.find(p_mono_class); @@ -454,7 +354,7 @@ GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) { GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) { - GDMonoClass *match = NULL; + GDMonoClass *match = nullptr; if (gdobject_class_cache_updated) { Map<StringName, GDMonoClass *>::Element *result = gdobject_class_cache.find(p_class); @@ -486,7 +386,7 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) GDMonoClass *current_nested = nested_classes.front()->get(); nested_classes.pop_back(); - void *iter = NULL; + void *iter = nullptr; while (true) { MonoClass *raw_nested = mono_class_get_nested_types(current_nested->get_mono_ptr(), &iter); @@ -514,32 +414,38 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) { - GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name); - if (loaded_asm) - return *loaded_asm; -#ifdef DEBUG_ENABLED - CRASH_COND(!FileAccess::exists(p_path)); -#endif - no_search = true; - GDMonoAssembly *res = _load_assembly_from(p_name, p_path, p_refonly); - no_search = false; - return res; -} + if (p_name == "mscorlib" || p_name == "mscorlib.dll") + return GDMono::get_singleton()->get_corlib_assembly(); -GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) { + // We need to manually call the search hook in this case, as it won't be called in the next step + MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8()); + MonoAssembly *assembly = mono_assembly_invoke_search_hook(aname); + mono_assembly_name_free(aname); + mono_free(aname); + + if (!assembly) { + assembly = _real_load_assembly_from(p_path, p_refonly); + ERR_FAIL_NULL_V(assembly, nullptr); + } - loaded = false; - gdobject_class_cache_updated = false; - name = p_name; - path = p_path; - refonly = false; - modified_time = 0; - assembly = NULL; - image = NULL; + GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name); + ERR_FAIL_NULL_V_MSG(loaded_asm, nullptr, "Loaded assembly missing from table. Did we not receive the load hook?"); + + return loaded_asm; +} + +GDMonoAssembly::GDMonoAssembly(const String &p_name, MonoImage *p_image, MonoAssembly *p_assembly) : + name(p_name), + image(p_image), + assembly(p_assembly), +#ifdef GD_MONO_HOT_RELOAD + modified_time(0), +#endif + gdobject_class_cache_updated(false) { } GDMonoAssembly::~GDMonoAssembly() { - if (loaded) + if (image) unload(); } diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index 4740e10339..43c8225b74 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -68,24 +68,20 @@ class GDMonoAssembly { StringName class_name; }; - MonoAssembly *assembly; + String name; MonoImage *image; + MonoAssembly *assembly; - bool refonly; - bool loaded; - - String name; - String path; +#ifdef GD_MONO_HOT_RELOAD uint64_t modified_time; - - HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes; - Map<MonoClass *, GDMonoClass *> cached_raw; +#endif bool gdobject_class_cache_updated; Map<StringName, GDMonoClass *> gdobject_class_cache; - static bool no_search; - static bool in_preload; + HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes; + Map<MonoClass *, GDMonoClass *> cached_raw; + static Vector<String> search_dirs; static void assembly_load_hook(MonoAssembly *assembly, void *user_data); @@ -97,25 +93,24 @@ class GDMonoAssembly { static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly); static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly); - static GDMonoAssembly *_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly); - static GDMonoAssembly *_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly); - static void _wrap_mono_assembly(MonoAssembly *assembly); + static MonoAssembly *_real_load_assembly_from(const String &p_path, bool p_refonly); + static MonoAssembly *_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly); friend class GDMono; static void initialize(); public: - Error load(bool p_refonly); - Error wrapper_for_image(MonoImage *p_image); void unload(); - _FORCE_INLINE_ bool is_refonly() const { return refonly; } - _FORCE_INLINE_ bool is_loaded() const { return loaded; } _FORCE_INLINE_ MonoImage *get_image() const { return image; } _FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; } _FORCE_INLINE_ String get_name() const { return name; } - _FORCE_INLINE_ String get_path() const { return path; } + +#ifdef GD_MONO_HOT_RELOAD _FORCE_INLINE_ uint64_t get_modified_time() const { return modified_time; } +#endif + + String get_path() const; GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name); GDMonoClass *get_class(MonoClass *p_mono_class); @@ -128,7 +123,7 @@ public: static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly); - GDMonoAssembly(const String &p_name, const String &p_path = String()); + GDMonoAssembly(const String &p_name, MonoImage *p_image, MonoAssembly *p_assembly); ~GDMonoAssembly(); }; diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index be0b846702..5ddf18d544 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -40,11 +40,11 @@ namespace GDMonoCache { CachedData cached_data; -#define CACHE_AND_CHECK(m_var, m_val) \ - { \ - CRASH_COND(m_var != NULL); \ - m_var = m_val; \ - ERR_FAIL_COND_MSG(m_var == NULL, "Mono Cache: Member " #m_var " is null."); \ +#define CACHE_AND_CHECK(m_var, m_val) \ + { \ + CRASH_COND(m_var != nullptr); \ + m_var = m_val; \ + ERR_FAIL_COND_MSG(m_var == nullptr, "Mono Cache: Member " #m_var " is null."); \ } #define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_class, m_val) @@ -54,12 +54,12 @@ CachedData cached_data; #define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(cached_data.method_##m_class##_##m_method, m_val) #define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(cached_data.property_##m_class##_##m_property, m_val) -#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \ - { \ - CRASH_COND(!m_var.is_null()); \ - ERR_FAIL_COND_MSG(m_val == NULL, "Mono Cache: Method for member " #m_var " is null."); \ - m_var.set_from_method(m_val); \ - ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \ +#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \ + { \ + CRASH_COND(!m_var.is_null()); \ + ERR_FAIL_COND_MSG(m_val == nullptr, "Mono Cache: Method for member " #m_var " is null."); \ + m_var.set_from_method(m_val); \ + ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \ } #define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_METHOD_THUNK_AND_CHECK_IMPL(cached_data.methodthunk_##m_class##_##m_method, m_val) @@ -68,93 +68,94 @@ void CachedData::clear_corlib_cache() { corlib_cache_updated = false; - class_MonoObject = NULL; - class_bool = NULL; - class_int8_t = NULL; - class_int16_t = NULL; - class_int32_t = NULL; - class_int64_t = NULL; - class_uint8_t = NULL; - class_uint16_t = NULL; - class_uint32_t = NULL; - class_uint64_t = NULL; - class_float = NULL; - class_double = NULL; - class_String = NULL; - class_IntPtr = NULL; - - class_System_Collections_IEnumerable = NULL; - class_System_Collections_IDictionary = NULL; + class_MonoObject = nullptr; + class_bool = nullptr; + class_int8_t = nullptr; + class_int16_t = nullptr; + class_int32_t = nullptr; + class_int64_t = nullptr; + class_uint8_t = nullptr; + class_uint16_t = nullptr; + class_uint32_t = nullptr; + class_uint64_t = nullptr; + class_float = nullptr; + class_double = nullptr; + class_String = nullptr; + class_IntPtr = nullptr; + + class_System_Collections_IEnumerable = nullptr; + class_System_Collections_ICollection = nullptr; + class_System_Collections_IDictionary = nullptr; #ifdef DEBUG_ENABLED - class_System_Diagnostics_StackTrace = NULL; + class_System_Diagnostics_StackTrace = nullptr; methodthunk_System_Diagnostics_StackTrace_GetFrames.nullify(); - method_System_Diagnostics_StackTrace_ctor_bool = NULL; - method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL; + method_System_Diagnostics_StackTrace_ctor_bool = nullptr; + method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr; #endif - class_KeyNotFoundException = NULL; + class_KeyNotFoundException = nullptr; } void CachedData::clear_godot_api_cache() { godot_api_cache_updated = false; - rawclass_Dictionary = NULL; - - class_Vector2 = NULL; - class_Vector2i = NULL; - class_Rect2 = NULL; - class_Rect2i = NULL; - class_Transform2D = NULL; - class_Vector3 = NULL; - class_Vector3i = NULL; - class_Basis = NULL; - class_Quat = NULL; - class_Transform = NULL; - class_AABB = NULL; - class_Color = NULL; - class_Plane = NULL; - class_StringName = NULL; - class_NodePath = NULL; - class_RID = NULL; - class_GodotObject = NULL; - class_GodotResource = NULL; - class_Node = NULL; - class_Control = NULL; - class_Spatial = NULL; - class_WeakRef = NULL; - class_Callable = NULL; - class_SignalInfo = NULL; - class_Array = NULL; - class_Dictionary = NULL; - class_MarshalUtils = NULL; - class_ISerializationListener = NULL; + rawclass_Dictionary = nullptr; + + class_Vector2 = nullptr; + class_Vector2i = nullptr; + class_Rect2 = nullptr; + class_Rect2i = nullptr; + class_Transform2D = nullptr; + class_Vector3 = nullptr; + class_Vector3i = nullptr; + class_Basis = nullptr; + class_Quat = nullptr; + class_Transform = nullptr; + class_AABB = nullptr; + class_Color = nullptr; + class_Plane = nullptr; + class_StringName = nullptr; + class_NodePath = nullptr; + class_RID = nullptr; + class_GodotObject = nullptr; + class_GodotResource = nullptr; + class_Node = nullptr; + class_Control = nullptr; + class_Node3D = nullptr; + class_WeakRef = nullptr; + class_Callable = nullptr; + class_SignalInfo = nullptr; + class_Array = nullptr; + class_Dictionary = nullptr; + class_MarshalUtils = nullptr; + class_ISerializationListener = nullptr; #ifdef DEBUG_ENABLED - class_DebuggingUtils = NULL; + class_DebuggingUtils = nullptr; methodthunk_DebuggingUtils_GetStackFrameInfo.nullify(); #endif - class_ExportAttribute = NULL; - field_ExportAttribute_hint = NULL; - field_ExportAttribute_hintString = NULL; - class_SignalAttribute = NULL; - class_ToolAttribute = NULL; - class_RemoteAttribute = NULL; - class_MasterAttribute = NULL; - class_PuppetAttribute = NULL; - class_RemoteSyncAttribute = NULL; - class_MasterSyncAttribute = NULL; - class_PuppetSyncAttribute = NULL; - class_GodotMethodAttribute = NULL; - field_GodotMethodAttribute_methodName = NULL; - - field_GodotObject_ptr = NULL; - field_StringName_ptr = NULL; - field_NodePath_ptr = NULL; - field_Image_ptr = NULL; - field_RID_ptr = NULL; + class_ExportAttribute = nullptr; + field_ExportAttribute_hint = nullptr; + field_ExportAttribute_hintString = nullptr; + class_SignalAttribute = nullptr; + class_ToolAttribute = nullptr; + class_RemoteAttribute = nullptr; + class_MasterAttribute = nullptr; + class_PuppetAttribute = nullptr; + class_RemoteSyncAttribute = nullptr; + class_MasterSyncAttribute = nullptr; + class_PuppetSyncAttribute = nullptr; + class_GodotMethodAttribute = nullptr; + field_GodotMethodAttribute_methodName = nullptr; + + field_GodotObject_ptr = nullptr; + field_StringName_ptr = nullptr; + field_NodePath_ptr = nullptr; + field_Image_ptr = nullptr; + field_RID_ptr = nullptr; methodthunk_GodotObject_Dispose.nullify(); methodthunk_Array_GetPtr.nullify(); @@ -171,22 +172,18 @@ void CachedData::clear_godot_api_cache() { methodthunk_MarshalUtils_TypeIsGenericArray.nullify(); methodthunk_MarshalUtils_TypeIsGenericDictionary.nullify(); + methodthunk_MarshalUtils_TypeIsSystemGenericList.nullify(); + methodthunk_MarshalUtils_TypeIsSystemGenericDictionary.nullify(); + methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify(); + methodthunk_MarshalUtils_TypeIsGenericICollection.nullify(); + methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify(); methodthunk_MarshalUtils_ArrayGetElementType.nullify(); methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify(); - methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType.nullify(); - methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType.nullify(); - methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info.nullify(); - methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info.nullify(); - methodthunk_MarshalUtils_MakeGenericArrayType.nullify(); methodthunk_MarshalUtils_MakeGenericDictionaryType.nullify(); - methodthunk_MarshalUtils_EnumerableToArray.nullify(); - methodthunk_MarshalUtils_IDictionaryToDictionary.nullify(); - methodthunk_MarshalUtils_GenericIDictionaryToDictionary.nullify(); - // End of MarshalUtils methods task_scheduler_handle = Ref<MonoGCHandleRef>(); @@ -213,6 +210,7 @@ void update_corlib_cache() { 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_ICollection, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "ICollection")); CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary")); #ifdef DEBUG_ENABLED @@ -251,7 +249,7 @@ void update_godot_api_cache() { 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)); + CACHE_CLASS_AND_CHECK(Node3D, GODOT_API_CLASS(Node3D)); CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef)); CACHE_CLASS_AND_CHECK(Callable, GODOT_API_CLASS(Callable)); CACHE_CLASS_AND_CHECK(SignalInfo, GODOT_API_CLASS(SignalInfo)); @@ -297,22 +295,18 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericArray", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericDictionary", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericList, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericList", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericDictionary", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIEnumerable, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIEnumerable", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIEnumerableIsAssignableFromType", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryIsAssignableFromType", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIEnumerableIsAssignableFromType", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryIsAssignableFromType", 3)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericArrayType", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericDictionaryType", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, GODOT_API_CLASS(MarshalUtils)->get_method("EnumerableToArray", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("IDictionaryToDictionary", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryToDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryToDictionary", 2)); - // End of MarshalUtils methods #ifdef DEBUG_ENABLED diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index b2dacee67c..3cf2bd6ce5 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -58,6 +58,7 @@ struct CachedData { GDMonoClass *class_IntPtr; // System.IntPtr GDMonoClass *class_System_Collections_IEnumerable; + GDMonoClass *class_System_Collections_ICollection; GDMonoClass *class_System_Collections_IDictionary; #ifdef DEBUG_ENABLED @@ -92,7 +93,7 @@ struct CachedData { GDMonoClass *class_GodotResource; GDMonoClass *class_Node; GDMonoClass *class_Control; - GDMonoClass *class_Spatial; + GDMonoClass *class_Node3D; GDMonoClass *class_WeakRef; GDMonoClass *class_Callable; GDMonoClass *class_SignalInfo; @@ -141,22 +142,18 @@ struct CachedData { GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericArray; GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericDictionary; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericList; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericDictionary; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary; GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType; GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info; - GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericArrayType; GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericDictionaryType; - GDMonoMethodThunk<MonoObject *, Array *> methodthunk_MarshalUtils_EnumerableToArray; - GDMonoMethodThunk<MonoObject *, Dictionary *> methodthunk_MarshalUtils_IDictionaryToDictionary; - GDMonoMethodThunk<MonoObject *, Dictionary *> methodthunk_MarshalUtils_GenericIDictionaryToDictionary; - // End of MarshalUtils methods Ref<MonoGCHandleRef> task_scheduler_handle; @@ -186,14 +183,6 @@ inline void clear_godot_api_cache() { cached_data.clear_godot_api_cache(); } -_FORCE_INLINE_ bool tools_godot_api_check() { -#ifdef TOOLS_ENABLED - return cached_data.godot_api_cache_updated; -#else - return true; // Assume it's updated if this was called, otherwise it's a bug -#endif -} - } // namespace GDMonoCache #define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class) diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index 648f5f6c6b..2c65f7e3a0 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -31,6 +31,7 @@ #include "gd_mono_class.h" #include <mono/metadata/attrdefs.h> +#include <mono/metadata/debug-helpers.h> #include "gd_mono_assembly.h" #include "gd_mono_cache.h" @@ -40,7 +41,7 @@ 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)); - MonoException *exc = NULL; + MonoException *exc = nullptr; MonoString *str = GDMonoUtils::object_to_string((MonoObject *)type_obj, &exc); UNHANDLED_EXCEPTION(exc); @@ -55,7 +56,11 @@ String GDMonoClass::get_full_name() const { return get_full_name(mono_class); } -MonoType *GDMonoClass::get_mono_type() { +String GDMonoClass::get_type_desc() const { + return GDMonoUtils::get_type_desc(get_mono_type()); +} + +MonoType *GDMonoClass::get_mono_type() const { // 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); @@ -76,12 +81,12 @@ bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const { GDMonoClass *GDMonoClass::get_parent_class() { MonoClass *parent_mono_class = mono_class_get_parent(mono_class); - return parent_mono_class ? GDMono::get_singleton()->get_class(parent_mono_class) : NULL; + return parent_mono_class ? GDMono::get_singleton()->get_class(parent_mono_class) : nullptr; } GDMonoClass *GDMonoClass::get_nesting_class() { MonoClass *nesting_type = mono_class_get_nesting_type(mono_class); - return nesting_type ? GDMono::get_singleton()->get_class(nesting_type) : NULL; + return nesting_type ? GDMono::get_singleton()->get_class(nesting_type) : nullptr; } #ifdef TOOLS_ENABLED @@ -92,9 +97,9 @@ Vector<MonoClassField *> GDMonoClass::get_enum_fields() { Vector<MonoClassField *> enum_fields; - void *iter = NULL; - MonoClassField *raw_field = NULL; - while ((raw_field = mono_class_get_fields(get_mono_ptr(), &iter)) != NULL) { + void *iter = nullptr; + MonoClassField *raw_field = nullptr; + while ((raw_field = mono_class_get_fields(get_mono_ptr(), &iter)) != nullptr) { uint32_t field_flags = mono_field_get_flags(raw_field); // Enums have an instance field named value__ which holds the value of the enum. @@ -126,21 +131,21 @@ bool GDMonoClass::has_attribute(GDMonoClass *p_attr_class) { MonoObject *GDMonoClass::get_attribute(GDMonoClass *p_attr_class) { #ifdef DEBUG_ENABLED - ERR_FAIL_NULL_V(p_attr_class, NULL); + ERR_FAIL_NULL_V(p_attr_class, nullptr); #endif if (!attrs_fetched) fetch_attributes(); if (!attributes) - return NULL; + return nullptr; return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr()); } void GDMonoClass::fetch_attributes() { - ERR_FAIL_COND(attributes != NULL); + ERR_FAIL_COND(attributes != nullptr); attributes = mono_custom_attrs_from_class(get_mono_ptr()); attrs_fetched = true; @@ -153,9 +158,9 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base if (methods_fetched) return; - void *iter = NULL; - MonoMethod *raw_method = NULL; - while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) { + void *iter = nullptr; + MonoMethod *raw_method = nullptr; + while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) { StringName name = mono_method_get_name(raw_method); // get_method implicitly fetches methods and adds them to this->methods @@ -198,7 +203,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base } #endif - uint32_t flags = mono_method_get_flags(method->mono_method, NULL); + uint32_t flags = mono_method_get_flags(method->mono_method, nullptr); if (!(flags & MONO_METHOD_ATTR_VIRTUAL)) continue; @@ -242,21 +247,21 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) { - ERR_FAIL_COND_V(!methods_fetched, NULL); + ERR_FAIL_COND_V(!methods_fetched, nullptr); - const MethodKey *k = NULL; + const MethodKey *k = nullptr; while ((k = methods.next(k))) { if (k->name == p_name) return methods.get(*k); } - return NULL; + return nullptr; } bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) { - return get_fetched_method_unknown_params(p_name) != NULL; + return get_fetched_method_unknown_params(p_name) != nullptr; } bool GDMonoClass::implements_interface(GDMonoClass *p_interface) { @@ -264,6 +269,12 @@ bool GDMonoClass::implements_interface(GDMonoClass *p_interface) { return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr()); } +bool GDMonoClass::has_public_parameterless_ctor() { + + GDMonoMethod *ctor = get_method(".ctor", 0); + return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC; +} + GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) { MethodKey key = MethodKey(p_name, p_params_count); @@ -274,7 +285,7 @@ GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_cou return *match; if (methods_fetched) - return NULL; + return nullptr; MonoMethod *raw_method = mono_class_get_method_from_name(mono_class, String(p_name).utf8().get_data(), p_params_count); @@ -285,7 +296,7 @@ GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_cou return method; } - return NULL; + return nullptr; } GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method) { @@ -307,7 +318,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count) { - ERR_FAIL_NULL_V(p_raw_method, NULL); + ERR_FAIL_NULL_V(p_raw_method, nullptr); MethodKey key = MethodKey(p_name, p_params_count); @@ -328,7 +339,10 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class); mono_method_desc_free(desc); - ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, NULL); + if (!method) + return nullptr; + + ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, nullptr); return get_method(method); } @@ -341,7 +355,7 @@ GDMonoField *GDMonoClass::get_field(const StringName &p_name) { return result->value(); if (fields_fetched) - return NULL; + return nullptr; MonoClassField *raw_field = mono_class_get_field_from_name(mono_class, String(p_name).utf8().get_data()); @@ -352,7 +366,7 @@ GDMonoField *GDMonoClass::get_field(const StringName &p_name) { return field; } - return NULL; + return nullptr; } const Vector<GDMonoField *> &GDMonoClass::get_all_fields() { @@ -360,9 +374,9 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() { if (fields_fetched) return fields_list; - void *iter = NULL; - MonoClassField *raw_field = NULL; - while ((raw_field = mono_class_get_fields(mono_class, &iter)) != NULL) { + void *iter = nullptr; + MonoClassField *raw_field = nullptr; + while ((raw_field = mono_class_get_fields(mono_class, &iter)) != nullptr) { StringName name = mono_field_get_name(raw_field); Map<StringName, GDMonoField *>::Element *match = fields.find(name); @@ -389,7 +403,7 @@ GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) { return result->value(); if (properties_fetched) - return NULL; + return nullptr; MonoProperty *raw_property = mono_class_get_property_from_name(mono_class, String(p_name).utf8().get_data()); @@ -400,7 +414,7 @@ GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) { return property; } - return NULL; + return nullptr; } const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() { @@ -408,9 +422,9 @@ const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() { if (properties_fetched) return properties_list; - void *iter = NULL; - MonoProperty *raw_property = NULL; - while ((raw_property = mono_class_get_properties(mono_class, &iter)) != NULL) { + void *iter = nullptr; + MonoProperty *raw_property = nullptr; + while ((raw_property = mono_class_get_properties(mono_class, &iter)) != nullptr) { StringName name = mono_property_get_name(raw_property); Map<StringName, GDMonoProperty *>::Element *match = properties.find(name); @@ -433,9 +447,9 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() { if (delegates_fetched) return delegates_list; - void *iter = NULL; - MonoClass *raw_class = NULL; - while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != NULL) { + void *iter = nullptr; + MonoClass *raw_class = nullptr; + while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != nullptr) { if (mono_class_is_delegate(raw_class)) { StringName name = mono_class_get_name(raw_class); @@ -459,9 +473,9 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() { const Vector<GDMonoMethod *> &GDMonoClass::get_all_methods() { if (!method_list_fetched) { - void *iter = NULL; - MonoMethod *raw_method = NULL; - while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) { + void *iter = nullptr; + MonoMethod *raw_method = nullptr; + while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) { method_list.push_back(memnew(GDMonoMethod(mono_method_get_name(raw_method), raw_method))); } @@ -479,7 +493,7 @@ GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name assembly = p_assembly; attrs_fetched = false; - attributes = NULL; + attributes = nullptr; methods_fetched = false; method_list_fetched = false; @@ -512,7 +526,7 @@ GDMonoClass::~GDMonoClass() { Vector<GDMonoMethod *> deleted_methods; deleted_methods.resize(methods.size()); - const MethodKey *k = NULL; + const MethodKey *k = nullptr; while ((k = methods.next(k))) { GDMonoMethod *method = methods.get(*k); diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index 0c9a8cdafe..9237aae057 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -31,8 +31,6 @@ #ifndef GD_MONO_CLASS_H #define GD_MONO_CLASS_H -#include <mono/metadata/debug-helpers.h> - #include "core/map.h" #include "core/ustring.h" @@ -107,7 +105,8 @@ public: static MonoType *get_mono_type(MonoClass *p_mono_class); String get_full_name() const; - MonoType *get_mono_type(); + String get_type_desc() const; + MonoType *get_mono_type() const; uint32_t get_flags() const; bool is_static() const; @@ -137,6 +136,7 @@ public: void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base); bool implements_interface(GDMonoClass *p_interface); + bool has_public_parameterless_ctor(); GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0); GDMonoMethod *get_method(MonoMethod *p_raw_method); diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 11942c47d9..e76cb84d43 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -116,7 +116,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ case MONO_TYPE_STRING: { if (p_value.get_type() == Variant::NIL) { // Otherwise, Variant -> String would return the string "Null" - MonoString *mono_string = NULL; + MonoString *mono_string = nullptr; mono_field_set_value(p_object, mono_field, mono_string); } else { MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value); @@ -322,6 +322,13 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) { + MonoArray *managed = GDMonoMarshal::Array_to_mono_array(p_value.operator ::Array(), array_type_class); + mono_field_set_value(p_object, mono_field, managed); + break; + } + ERR_FAIL_MSG("Attempted to convert Variant to a managed array of unmarshallable element type."); } break; @@ -353,56 +360,22 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } - if (CACHED_CLASS(Dictionary) == type_class) { + // Godot.Collections.Dictionary or IDictionary + if (CACHED_CLASS(Dictionary) == type_class || type_class == CACHED_CLASS(System_Collections_IDictionary)) { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary)); mono_field_set_value(p_object, mono_field, managed); break; } - if (CACHED_CLASS(Array) == type_class) { + // Godot.Collections.Array or ICollection or IEnumerable + if (CACHED_CLASS(Array) == type_class || + type_class == CACHED_CLASS(System_Collections_ICollection) || + type_class == CACHED_CLASS(System_Collections_IEnumerable)) { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); mono_field_set_value(p_object, mono_field, managed); break; } - // The order in which we check the following interfaces is very important (dictionaries and generics first) - - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), 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))) { - if (GDMonoCache::tools_godot_api_check()) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); - mono_field_set_value(p_object, mono_field, managed); - break; - } else { - MonoObject *managed = (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_value.operator Array()); - mono_field_set_value(p_object, mono_field, managed); - break; - } - } - ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + type_class->get_name() + "'."); } break; @@ -535,52 +508,62 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type()); + // Godot.Collections.Dictionary<TKey, TValue> if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class); mono_field_set_value(p_object, mono_field, managed); break; } + // Godot.Collections.Array<T> 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; } - // 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)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), - GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype)); + // System.Collections.Generic.Dictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { + MonoReflectionType *key_reftype = nullptr; + MonoReflectionType *value_reftype = nullptr; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + MonoObject *managed = GDMonoMarshal::Dictionary_to_system_generic_dict(p_value.operator Dictionary(), + type.type_class, key_reftype, value_reftype); mono_field_set_value(p_object, mono_field, managed); break; } - if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary)); + // System.Collections.Generic.List<T> + if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { + MonoReflectionType *elem_reftype = nullptr; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + MonoObject *managed = GDMonoMarshal::Array_to_system_generic_list(p_value.operator Array(), + type.type_class, elem_reftype); mono_field_set_value(p_object, mono_field, managed); break; } - 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)); + // IDictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { + MonoReflectionType *key_reftype; + MonoReflectionType *value_reftype; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); + + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), godot_dict_class); mono_field_set_value(p_object, mono_field, managed); break; } - if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - if (GDMonoCache::tools_godot_api_check()) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); - mono_field_set_value(p_object, mono_field, managed); - break; - } else { - MonoObject *managed = (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_value.operator Array()); - mono_field_set_value(p_object, mono_field, managed); - break; - } + // ICollection<T> or IEnumerable<T> + if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { + MonoReflectionType *elem_reftype; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); + + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), godot_array_class); + mono_field_set_value(p_object, mono_field, managed); + break; } } break; @@ -623,19 +606,19 @@ bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) { } MonoObject *GDMonoField::get_attribute(GDMonoClass *p_attr_class) { - ERR_FAIL_NULL_V(p_attr_class, NULL); + ERR_FAIL_NULL_V(p_attr_class, nullptr); if (!attrs_fetched) fetch_attributes(); if (!attributes) - return NULL; + return nullptr; return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr()); } void GDMonoField::fetch_attributes() { - ERR_FAIL_COND(attributes != NULL); + ERR_FAIL_COND(attributes != nullptr); attributes = mono_custom_attrs_from_field(owner->get_mono_ptr(), mono_field); attrs_fetched = true; } @@ -671,7 +654,7 @@ GDMonoField::GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner) { type.type_class = GDMono::get_singleton()->get_class(field_type_class); attrs_fetched = false; - attributes = NULL; + attributes = nullptr; } GDMonoField::~GDMonoField() { diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp index 53e642f317..1898785699 100644 --- a/modules/mono/mono_gd/gd_mono_internals.cpp +++ b/modules/mono/mono_gd/gd_mono_internals.cpp @@ -61,7 +61,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { GDMonoClass *native = GDMonoUtils::get_class_native_base(klass); - CRASH_COND(native == NULL); + CRASH_COND(native == nullptr); if (native == klass) { // If it's just a wrapper Godot class and not a custom inheriting class, then attach a @@ -119,7 +119,7 @@ void unhandled_exception(MonoException *p_exc) { if (GDMono::get_singleton()->get_unhandled_exception_policy() == GDMono::POLICY_TERMINATE_APP) { // Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders - GDMono::unhandled_exception_hook((MonoObject *)p_exc, NULL); + GDMono::unhandled_exception_hook((MonoObject *)p_exc, nullptr); GD_UNREACHABLE(); } else { #ifdef DEBUG_ENABLED diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index 76828a66e0..ca16c2b76a 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -46,13 +46,13 @@ static CharString get_default_log_level() { #endif } -GDMonoLog *GDMonoLog::singleton = NULL; +GDMonoLog *GDMonoLog::singleton = nullptr; -#if !defined(JAVASCRIPT_ENABLED) +#ifdef GD_MONO_LOG_ENABLED static int get_log_level_id(const char *p_log_level) { - const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", NULL }; + const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", nullptr }; int i = 0; while (valid_log_levels[i]) { @@ -191,7 +191,7 @@ GDMonoLog::GDMonoLog() { GDMonoLog::~GDMonoLog() { - singleton = NULL; + singleton = nullptr; if (log_file) { log_file->close(); @@ -213,7 +213,7 @@ GDMonoLog::GDMonoLog() { GDMonoLog::~GDMonoLog() { - singleton = NULL; + singleton = nullptr; } #endif // !defined(JAVASCRIPT_ENABLED) diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h index ecf4c78b1a..1fc21f7df5 100644 --- a/modules/mono/mono_gd/gd_mono_log.h +++ b/modules/mono/mono_gd/gd_mono_log.h @@ -35,13 +35,18 @@ #include "core/typedefs.h" -#if !defined(JAVASCRIPT_ENABLED) +#if !defined(JAVASCRIPT_ENABLED) && !defined(IPHONE_ENABLED) +// We have custom mono log callbacks for WASM and iOS +#define GD_MONO_LOG_ENABLED +#endif + +#ifdef GD_MONO_LOG_ENABLED #include "core/os/file_access.h" #endif class GDMonoLog { -#if !defined(JAVASCRIPT_ENABLED) +#ifdef GD_MONO_LOG_ENABLED int log_level_id; FileAccess *log_file; diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 0de5352752..91ee07388b 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -154,6 +154,10 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_ if (array_type->eklass == CACHED_CLASS_RAW(Color)) return Variant::PACKED_COLOR_ARRAY; + + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) + return Variant::ARRAY; } break; case MONO_TYPE_CLASS: { @@ -184,23 +188,14 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_ 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(mono_domain_get(), 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))) { + // IDictionary + if (p_type.type_class == 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))) { + // ICollection or IEnumerable + if (p_type.type_class == CACHED_CLASS(System_Collections_ICollection) || + p_type.type_class == CACHED_CLASS(System_Collections_IEnumerable)) { return Variant::ARRAY; } } break; @@ -214,27 +209,33 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_ case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); + // Godot.Collections.Dictionary<TKey, TValue> if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { return Variant::DICTIONARY; } + // Godot.Collections.Array<T> 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 (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { + // System.Collections.Generic.Dictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { return Variant::DICTIONARY; } - if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) + // System.Collections.Generic.List<T> + if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { return Variant::ARRAY; + } - if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { + // IDictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { + return Variant::DICTIONARY; + } + + // ICollection<T> or IEnumerable<T> + if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { return Variant::ARRAY; } } break; @@ -252,10 +253,20 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) { switch (p_array_type.type_encoding) { + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: { + MonoArrayType *array_type = mono_type_get_array_type(p_array_type.type_class->get_mono_type()); + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + r_elem_type = ManagedType::from_class(array_type_class); + return true; + } break; case MONO_TYPE_GENERICINST: { MonoReflectionType *array_reftype = mono_type_get_object(mono_domain_get(), p_array_type.type_class->get_mono_type()); - if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype)) { + if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype) || + GDMonoUtils::Marshal::type_is_system_generic_list(array_reftype) || + GDMonoUtils::Marshal::type_is_generic_icollection(array_reftype) || + GDMonoUtils::Marshal::type_is_generic_ienumerable(array_reftype)) { MonoReflectionType *elem_reftype; GDMonoUtils::Marshal::array_get_element_type(array_reftype, &elem_reftype); @@ -263,12 +274,6 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_ 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; @@ -282,7 +287,9 @@ bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, Ma case MONO_TYPE_GENERICINST: { MonoReflectionType *dict_reftype = mono_type_get_object(mono_domain_get(), p_dictionary_type.type_class->get_mono_type()); - if (GDMonoUtils::Marshal::type_is_generic_dictionary(dict_reftype)) { + if (GDMonoUtils::Marshal::type_is_generic_dictionary(dict_reftype) || + GDMonoUtils::Marshal::type_is_system_generic_dictionary(dict_reftype) || + GDMonoUtils::Marshal::type_is_generic_idictionary(dict_reftype)) { MonoReflectionType *key_reftype; MonoReflectionType *value_reftype; @@ -292,13 +299,6 @@ bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, Ma 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; @@ -410,7 +410,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty case MONO_TYPE_STRING: { if (p_var->get_type() == Variant::NIL) - return NULL; // Otherwise, Variant -> String would return the string "Null" + return nullptr; // Otherwise, Variant -> String would return the string "Null" return (MonoObject *)mono_string_from_godot(p_var->operator String()); } break; @@ -537,7 +537,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty return BOX_ENUM(enum_baseclass, val); } default: { - ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to a managed enum value of unmarshallable base type."); + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed enum value of unmarshallable base type."); } } } @@ -577,7 +577,11 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty if (array_type->eklass == CACHED_CLASS_RAW(Color)) return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray()); - ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to a managed array of unmarshallable element type."); + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) + return (MonoObject *)Array_to_mono_array(p_var->operator Array(), array_type_class); + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed array of unmarshallable element type."); } break; case MONO_TYPE_CLASS: { @@ -600,41 +604,17 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty return GDMonoUtils::create_managed_from(p_var->operator RID()); } - if (CACHED_CLASS(Dictionary) == type_class) { + // Godot.Collections.Dictionary or IDictionary + if (CACHED_CLASS(Dictionary) == type_class || CACHED_CLASS(System_Collections_IDictionary) == type_class) { return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); } - if (CACHED_CLASS(Array) == type_class) { + // Godot.Collections.Array or ICollection or IEnumerable + if (CACHED_CLASS(Array) == type_class || + CACHED_CLASS(System_Collections_ICollection) == type_class || + CACHED_CLASS(System_Collections_IEnumerable) == type_class) { return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); } - - // The order in which we check the following interfaces is very important (dictionaries and generics first) - - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), 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))) { - if (GDMonoCache::tools_godot_api_check()) { - return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); - } else { - return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array()); - } - } } break; case MONO_TYPE_OBJECT: { // Variant @@ -749,51 +729,61 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty case Variant::PACKED_COLOR_ARRAY: return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray()); default: - return NULL; + return nullptr; } break; case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); + // Godot.Collections.Dictionary<TKey, TValue> if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class); } + // Godot.Collections.Array<T> 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)); + // System.Collections.Generic.Dictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { + MonoReflectionType *key_reftype = nullptr; + MonoReflectionType *value_reftype = nullptr; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + return Dictionary_to_system_generic_dict(p_var->operator Dictionary(), p_type.type_class, key_reftype, value_reftype); } - if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); + // System.Collections.Generic.List<T> + if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { + MonoReflectionType *elem_reftype = nullptr; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + return Array_to_system_generic_list(p_var->operator Array(), p_type.type_class, elem_reftype); } - 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)); + // IDictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { + MonoReflectionType *key_reftype; + MonoReflectionType *value_reftype; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); + + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), godot_dict_class); } - if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - if (GDMonoCache::tools_godot_api_check()) { - return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); - } else { - return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array()); - } + // ICollection<T> or IEnumerable<T> + if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { + MonoReflectionType *elem_reftype; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); + + return GDMonoUtils::create_managed_from(p_var->operator Array(), godot_array_class); } } break; } break; } - ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to an unmarshallable managed type. Name: '" + - p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + "."); + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to an unmarshallable managed type. Name: '" + + p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + "."); } Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) { @@ -831,7 +821,7 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return unbox<double>(p_obj); case MONO_TYPE_STRING: { - if (p_obj == NULL) + if (p_obj == nullptr) return Variant(); // NIL return mono_string_to_godot_not_null((MonoString *)p_obj); } break; @@ -922,6 +912,10 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type if (array_type->eklass == CACHED_CLASS_RAW(Color)) return mono_array_to_PackedColorArray((MonoArray *)p_obj); + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) + return mono_array_to_Array((MonoArray *)p_obj); + if (p_fail_with_err) { ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant."); } else { @@ -935,7 +929,7 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type // GodotObject if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj)); - if (ptr != NULL) { + if (ptr != nullptr) { Reference *ref = Object::cast_to<Reference>(ptr); return ref ? Variant(Ref<Reference>(ref)) : Variant(ptr); } @@ -957,74 +951,55 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return ptr ? Variant(*ptr) : Variant(); } - if (CACHED_CLASS(Array) == type_class) { - MonoException *exc = NULL; - Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc); - UNHANDLED_EXCEPTION(exc); - return ptr ? Variant(*ptr) : Variant(); - } - + // Godot.Collections.Dictionary if (CACHED_CLASS(Dictionary) == type_class) { - MonoException *exc = NULL; + MonoException *exc = nullptr; Dictionary *ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr).invoke(p_obj, &exc); 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(mono_domain_get(), 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); + // Godot.Collections.Array + if (CACHED_CLASS(Array) == type_class) { + MonoException *exc = nullptr; + Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc); + UNHANDLED_EXCEPTION(exc); + return ptr ? Variant(*ptr) : Variant(); } } break; case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); + // Godot.Collections.Dictionary<TKey, TValue> if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - MonoException *exc = NULL; + MonoException *exc = nullptr; MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc); UNHANDLED_EXCEPTION(exc); return *unbox<Dictionary *>(ret); } + // Godot.Collections.Array<T> if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - MonoException *exc = NULL; + MonoException *exc = nullptr; MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc); 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 (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { - return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj); + // System.Collections.Generic.Dictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { + MonoReflectionType *key_reftype = nullptr; + MonoReflectionType *value_reftype = nullptr; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + return system_generic_dict_to_Dictionary(p_obj, p_type.type_class, key_reftype, value_reftype); } - if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) { - return GDMonoUtils::Marshal::enumerable_to_array(p_obj); - } - - if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - return GDMonoUtils::Marshal::enumerable_to_array(p_obj); + // System.Collections.Generic.List<T> + if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { + MonoReflectionType *elem_reftype = nullptr; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + return system_generic_list_to_Array(p_obj, p_type.type_class, elem_reftype); } } break; } @@ -1064,9 +1039,9 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) { ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj)); Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type); - if (var.get_type() == Variant::NIL && p_obj != NULL) { + if (var.get_type() == Variant::NIL && p_obj != nullptr) { // Cannot convert MonoObject* to Variant; fallback to 'ToString()'. - MonoException *exc = NULL; + MonoException *exc = nullptr; MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc); if (exc) { @@ -1081,6 +1056,80 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) { } } +MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) { + String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) + + ", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)"; + GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true); + CRASH_COND(ctor == nullptr); + + MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); + ERR_FAIL_NULL_V(mono_object, nullptr); + + GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype); + MonoObject *godot_dict = GDMonoUtils::create_managed_from(p_dict, godot_dict_class); + + void *ctor_args[1] = { godot_dict }; + + MonoException *exc = nullptr; + ctor->invoke_raw(mono_object, ctor_args, &exc); + UNHANDLED_EXCEPTION(exc); + + return mono_object; +} + +Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]] GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) { + GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype); + String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) + + ", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)"; + GDMonoMethod *godot_dict_ctor = godot_dict_class->get_method_with_desc(ctor_desc, true); + CRASH_COND(godot_dict_ctor == nullptr); + + MonoObject *godot_dict = mono_object_new(mono_domain_get(), godot_dict_class->get_mono_ptr()); + ERR_FAIL_NULL_V(godot_dict, Dictionary()); + + void *ctor_args[1] = { p_obj }; + + MonoException *exc = nullptr; + godot_dict_ctor->invoke_raw(godot_dict, ctor_args, &exc); + UNHANDLED_EXCEPTION(exc); + + exc = nullptr; + MonoObject *ret = godot_dict_class->get_method("GetPtr")->invoke(godot_dict, &exc); + UNHANDLED_EXCEPTION(exc); + + return *unbox<Dictionary *>(ret); +} + +MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) { + GDMonoClass *elem_class = ManagedType::from_reftype(p_elem_reftype).type_class; + + String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + elem_class->get_type_desc() + ">)"; + GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true); + CRASH_COND(ctor == nullptr); + + MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); + ERR_FAIL_NULL_V(mono_object, nullptr); + + void *ctor_args[1] = { Array_to_mono_array(p_array, elem_class) }; + + MonoException *exc = nullptr; + ctor->invoke_raw(mono_object, ctor_args, &exc); + UNHANDLED_EXCEPTION(exc); + + return mono_object; +} + +Array system_generic_list_to_Array(MonoObject *p_obj, GDMonoClass *p_class, [[maybe_unused]] MonoReflectionType *p_elem_reftype) { + GDMonoMethod *to_array = p_class->get_method("ToArray", 0); + CRASH_COND(to_array == nullptr); + + MonoException *exc = nullptr; + MonoArray *mono_array = (MonoArray *)to_array->invoke_raw(p_obj, nullptr, &exc); + UNHANDLED_EXCEPTION(exc); + + return mono_array_to_Array(mono_array); +} + MonoArray *Array_to_mono_array(const Array &p_array) { int length = p_array.size(); MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), length); @@ -1093,6 +1142,18 @@ MonoArray *Array_to_mono_array(const Array &p_array) { return ret; } +MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class) { + int length = p_array.size(); + MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class->get_mono_ptr(), length); + + for (int i = 0; i < length; i++) { + MonoObject *boxed = variant_to_mono_object(p_array[i]); + mono_array_setref(ret, i, boxed); + } + + return ret; +} + Array mono_array_to_Array(MonoArray *p_array) { Array ret; if (!p_array) @@ -1393,7 +1454,7 @@ Callable managed_to_callable(const M_Callable &p_managed_callable) { } else { Object *target = p_managed_callable.target ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_callable.target)) : - NULL; + nullptr; StringName *method_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name)); StringName method = method_ptr ? *method_ptr : StringName(); return Callable(target, method); @@ -1408,7 +1469,7 @@ M_Callable callable_to_managed(const Callable &p_callable) { if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) { ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom); return { - NULL, NULL, + nullptr, nullptr, managed_callable->get_delegate() }; } else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) { @@ -1416,30 +1477,30 @@ M_Callable callable_to_managed(const Callable &p_callable) { return { GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(signal_awaiter_callable->get_object())), GDMonoUtils::create_managed_from(signal_awaiter_callable->get_signal()), - NULL + nullptr }; } else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) { EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom); return { GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(event_signal_callable->get_object())), GDMonoUtils::create_managed_from(event_signal_callable->get_signal()), - NULL + nullptr }; } // Some other CallableCustom. We only support ManagedCallable. - return { NULL, NULL, NULL }; + return { nullptr, nullptr, nullptr }; } else { MonoObject *target_managed = GDMonoUtils::unmanaged_get_managed(p_callable.get_object()); MonoObject *method_string_name_managed = GDMonoUtils::create_managed_from(p_callable.get_method()); - return { target_managed, method_string_name_managed, NULL }; + return { target_managed, method_string_name_managed, nullptr }; } } Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal) { Object *owner = p_managed_signal.owner ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_signal.owner)) : - NULL; + nullptr; StringName *name_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name)); StringName name = name_ptr ? *name_ptr : StringName(); return Signal(owner, name); diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 7d09f46b00..f2d887e6d6 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -63,7 +63,7 @@ T *unbox_addr(MonoObject *p_obj) { #define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x) #define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x) -Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant = NULL); +Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant = nullptr); 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); @@ -81,7 +81,7 @@ _FORCE_INLINE_ String mono_string_to_godot_not_null(MonoString *p_mono_string) { } _FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) { - if (p_mono_string == NULL) + if (p_mono_string == nullptr) return String(); return mono_string_to_godot_not_null(p_mono_string); @@ -123,9 +123,18 @@ Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_ty /// If the MonoObject* cannot be converted to Variant, then 'ToString()' is called instead. String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc); +// System.Collections.Generic + +MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype); +Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype); + +MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype); +Array system_generic_list_to_Array(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype); + // Array MonoArray *Array_to_mono_array(const Array &p_array); +MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class); Array mono_array_to_Array(MonoArray *p_array); // PackedInt32Array diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index e6a1ec2697..432aa74a6f 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -30,13 +30,14 @@ #include "gd_mono_method.h" +#include <mono/metadata/attrdefs.h> +#include <mono/metadata/debug-helpers.h> + #include "gd_mono_cache.h" #include "gd_mono_class.h" #include "gd_mono_marshal.h" #include "gd_mono_utils.h" -#include <mono/metadata/attrdefs.h> - void GDMonoMethod::_update_signature() { // Apparently MonoMethodSignature needs not to be freed. // mono_method_signature caches the result, we don't need to cache it ourselves. @@ -58,9 +59,9 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) { } } - void *iter = NULL; + void *iter = nullptr; MonoType *param_raw_type; - while ((param_raw_type = mono_signature_get_params(p_method_sig, &iter)) != NULL) { + while ((param_raw_type = mono_signature_get_params(p_method_sig, &iter)) != nullptr) { ManagedType param_type; param_type.type_encoding = mono_type_get_type(param_raw_type); @@ -81,11 +82,11 @@ GDMonoClass *GDMonoMethod::get_enclosing_class() const { } bool GDMonoMethod::is_static() { - return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC; + return mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_STATIC; } IMonoClassMember::Visibility GDMonoMethod::get_visibility() { - switch (mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) { + switch (mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) { case MONO_METHOD_ATTR_PRIVATE: return IMonoClassMember::PRIVATE; case MONO_METHOD_ATTR_FAM_AND_ASSEM: @@ -102,7 +103,7 @@ IMonoClassMember::Visibility GDMonoMethod::get_visibility() { } MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) const { - MonoException *exc = NULL; + MonoException *exc = nullptr; MonoObject *ret; if (params_count > 0) { @@ -115,11 +116,11 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc); } else { - ret = GDMonoUtils::runtime_invoke(mono_method, p_object, NULL, &exc); + ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc); } if (exc) { - ret = NULL; + ret = nullptr; if (r_exc) { *r_exc = exc; } else { @@ -131,16 +132,16 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, } MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoException **r_exc) const { - ERR_FAIL_COND_V(get_parameters_count() > 0, NULL); - return invoke_raw(p_object, NULL, r_exc); + ERR_FAIL_COND_V(get_parameters_count() > 0, nullptr); + return invoke_raw(p_object, nullptr, r_exc); } MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) const { - MonoException *exc = NULL; + MonoException *exc = nullptr; MonoObject *ret = GDMonoUtils::runtime_invoke(mono_method, p_object, p_params, &exc); if (exc) { - ret = NULL; + ret = nullptr; if (r_exc) { *r_exc = exc; } else { @@ -164,19 +165,19 @@ bool GDMonoMethod::has_attribute(GDMonoClass *p_attr_class) { } MonoObject *GDMonoMethod::get_attribute(GDMonoClass *p_attr_class) { - ERR_FAIL_NULL_V(p_attr_class, NULL); + ERR_FAIL_NULL_V(p_attr_class, nullptr); if (!attrs_fetched) fetch_attributes(); if (!attributes) - return NULL; + return nullptr; return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr()); } void GDMonoMethod::fetch_attributes() { - ERR_FAIL_COND(attributes != NULL); + ERR_FAIL_COND(attributes != nullptr); attributes = mono_custom_attrs_from_method(mono_method); attrs_fetched = true; } @@ -281,7 +282,7 @@ GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) { method_info_fetched = false; attrs_fetched = false; - attributes = NULL; + attributes = nullptr; _update_signature(); } diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index d4379f41fe..54b2eba3e8 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -76,9 +76,9 @@ public: _FORCE_INLINE_ int get_parameters_count() const { return params_count; } _FORCE_INLINE_ ManagedType get_return_type() const { return return_type; } - MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = NULL) const; - MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = NULL) const; - MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL) const; + MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = nullptr) const; + MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = nullptr) const; + MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = nullptr) const; String get_full_name(bool p_signature = false) const; String get_full_name_no_class() const; diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h index d8c9a5eb02..0e05e974e9 100644 --- a/modules/mono/mono_gd/gd_mono_method_thunk.h +++ b/modules/mono/mono_gd/gd_mono_method_thunk.h @@ -39,7 +39,7 @@ #include "gd_mono_method.h" #include "gd_mono_utils.h" -#if !defined(JAVASCRIPT_ENABLED) +#if !defined(JAVASCRIPT_ENABLED) && !defined(IPHONE_ENABLED) #define HAVE_METHOD_THUNKS #endif @@ -60,16 +60,16 @@ public: } _FORCE_INLINE_ bool is_null() { - return mono_method_thunk == NULL; + return mono_method_thunk == nullptr; } _FORCE_INLINE_ void nullify() { - mono_method_thunk = NULL; + mono_method_thunk = nullptr; } _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == NULL); + CRASH_COND(p_mono_method == nullptr); CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID); if (p_mono_method->is_static()) { @@ -82,7 +82,7 @@ public: } GDMonoMethodThunk() : - mono_method_thunk(NULL) { + mono_method_thunk(nullptr) { } explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) { @@ -106,16 +106,16 @@ public: } _FORCE_INLINE_ bool is_null() { - return mono_method_thunk == NULL; + return mono_method_thunk == nullptr; } _FORCE_INLINE_ void nullify() { - mono_method_thunk = NULL; + mono_method_thunk = nullptr; } _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == NULL); + CRASH_COND(p_mono_method == nullptr); CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID); if (p_mono_method->is_static()) { @@ -128,12 +128,12 @@ public: } GDMonoMethodThunkR() : - mono_method_thunk(NULL) { + mono_method_thunk(nullptr) { } explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == NULL); + CRASH_COND(p_mono_method == nullptr); #endif mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); } @@ -146,7 +146,7 @@ struct VariadicInvokeMonoMethodImpl { static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) { if (p_mono_method->is_static()) { void *args[ThunkParamCount] = { p_arg1, p_args... }; - p_mono_method->invoke_raw(NULL, args, r_exc); + p_mono_method->invoke_raw(nullptr, args, r_exc); } else { void *args[ThunkParamCount] = { p_args... }; p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc); @@ -167,7 +167,7 @@ struct VariadicInvokeMonoMethod<0> { #ifdef DEBUG_ENABLED CRASH_COND(!p_mono_method->is_static()); #endif - p_mono_method->invoke_raw(NULL, NULL, r_exc); + p_mono_method->invoke_raw(nullptr, nullptr, r_exc); } }; @@ -176,9 +176,9 @@ struct VariadicInvokeMonoMethod<1, P1> { static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) { if (p_mono_method->is_static()) { void *args[1] = { p_arg1 }; - p_mono_method->invoke_raw(NULL, args, r_exc); + p_mono_method->invoke_raw(nullptr, args, r_exc); } else { - p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc); + p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc); } } }; @@ -203,7 +203,7 @@ struct VariadicInvokeMonoMethodRImpl { static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) { if (p_mono_method->is_static()) { void *args[ThunkParamCount] = { p_arg1, p_args... }; - MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc); + MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc); return unbox_if_needed<R>(r, p_mono_method->get_return_type()); } else { void *args[ThunkParamCount] = { p_args... }; @@ -226,7 +226,7 @@ struct VariadicInvokeMonoMethodR<0, R> { #ifdef DEBUG_ENABLED CRASH_COND(!p_mono_method->is_static()); #endif - MonoObject *r = p_mono_method->invoke_raw(NULL, NULL, r_exc); + MonoObject *r = p_mono_method->invoke_raw(nullptr, nullptr, r_exc); return unbox_if_needed<R>(r, p_mono_method->get_return_type()); } }; @@ -236,10 +236,10 @@ struct VariadicInvokeMonoMethodR<1, R, P1> { static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) { if (p_mono_method->is_static()) { void *args[1] = { p_arg1 }; - MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc); + MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc); return unbox_if_needed<R>(r, p_mono_method->get_return_type()); } else { - MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc); + MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc); return unbox_if_needed<R>(r, p_mono_method->get_return_type()); } } @@ -256,16 +256,16 @@ public: } _FORCE_INLINE_ bool is_null() { - return mono_method == NULL; + return mono_method == nullptr; } _FORCE_INLINE_ void nullify() { - mono_method = NULL; + mono_method = nullptr; } _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == NULL); + CRASH_COND(p_mono_method == nullptr); CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID); if (p_mono_method->is_static()) { @@ -278,7 +278,7 @@ public: } GDMonoMethodThunk() : - mono_method(NULL) { + mono_method(nullptr) { } explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) { @@ -297,16 +297,16 @@ public: } _FORCE_INLINE_ bool is_null() { - return mono_method == NULL; + return mono_method == nullptr; } _FORCE_INLINE_ void nullify() { - mono_method = NULL; + mono_method = nullptr; } _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { #ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == NULL); + CRASH_COND(p_mono_method == nullptr); CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID); if (p_mono_method->is_static()) { @@ -319,7 +319,7 @@ public: } GDMonoMethodThunkR() : - mono_method(NULL) { + mono_method(nullptr) { } explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) { diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index 3b5ce58d80..c3e7598f2d 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -57,7 +57,7 @@ GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_own MonoMethodSignature *setter_sig = mono_method_signature(prop_method); - void *iter = NULL; + void *iter = nullptr; MonoType *param_raw_type = mono_signature_get_params(setter_sig, &iter); type.type_encoding = mono_type_get_type(param_raw_type); @@ -66,7 +66,7 @@ GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_own } attrs_fetched = false; - attributes = NULL; + attributes = nullptr; } GDMonoProperty::~GDMonoProperty() { @@ -77,17 +77,17 @@ GDMonoProperty::~GDMonoProperty() { bool GDMonoProperty::is_static() { MonoMethod *prop_method = mono_property_get_get_method(mono_property); - if (prop_method == NULL) + if (prop_method == nullptr) prop_method = mono_property_get_set_method(mono_property); - return mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_STATIC; + return mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_STATIC; } IMonoClassMember::Visibility GDMonoProperty::get_visibility() { MonoMethod *prop_method = mono_property_get_get_method(mono_property); - if (prop_method == NULL) + if (prop_method == nullptr) prop_method = mono_property_get_set_method(mono_property); - switch (mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) { + switch (mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) { case MONO_METHOD_ATTR_PRIVATE: return IMonoClassMember::PRIVATE; case MONO_METHOD_ATTR_FAM_AND_ASSEM: @@ -116,36 +116,36 @@ bool GDMonoProperty::has_attribute(GDMonoClass *p_attr_class) { } MonoObject *GDMonoProperty::get_attribute(GDMonoClass *p_attr_class) { - ERR_FAIL_NULL_V(p_attr_class, NULL); + ERR_FAIL_NULL_V(p_attr_class, nullptr); if (!attrs_fetched) fetch_attributes(); if (!attributes) - return NULL; + return nullptr; return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr()); } void GDMonoProperty::fetch_attributes() { - ERR_FAIL_COND(attributes != NULL); + ERR_FAIL_COND(attributes != nullptr); attributes = mono_custom_attrs_from_property(owner->get_mono_ptr(), mono_property); attrs_fetched = true; } bool GDMonoProperty::has_getter() { - return mono_property_get_get_method(mono_property) != NULL; + return mono_property_get_get_method(mono_property) != nullptr; } bool GDMonoProperty::has_setter() { - return mono_property_get_set_method(mono_property) != NULL; + return mono_property_get_set_method(mono_property) != nullptr; } void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) { MonoMethod *prop_method = mono_property_get_set_method(mono_property); MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1); mono_array_setref(params, 0, p_value); - MonoException *exc = NULL; + MonoException *exc = nullptr; GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc); if (exc) { if (r_exc) { @@ -157,7 +157,7 @@ void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoEx } void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) { - MonoException *exc = NULL; + MonoException *exc = nullptr; GDMonoUtils::property_set_value(mono_property, p_object, p_params, &exc); if (exc) { @@ -170,11 +170,11 @@ void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoExcept } MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoException **r_exc) { - MonoException *exc = NULL; - MonoObject *ret = GDMonoUtils::property_get_value(mono_property, p_object, NULL, &exc); + MonoException *exc = nullptr; + MonoObject *ret = GDMonoUtils::property_get_value(mono_property, p_object, nullptr, &exc); if (exc) { - ret = NULL; + ret = nullptr; if (r_exc) { *r_exc = exc; } else { diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h index 2aec64f565..4653758a86 100644 --- a/modules/mono/mono_gd/gd_mono_property.h +++ b/modules/mono/mono_gd/gd_mono_property.h @@ -65,9 +65,9 @@ public: _FORCE_INLINE_ ManagedType get_type() const { return type; } - void set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc = NULL); - void set_value(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL); - MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = NULL); + void set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc = nullptr); + void set_value(MonoObject *p_object, void **p_params, MonoException **r_exc = nullptr); + MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = nullptr); bool get_bool_value(MonoObject *p_object); int get_int_value(MonoObject *p_object); diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index cdb26ae61b..f9d492dabb 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -30,6 +30,7 @@ #include "gd_mono_utils.h" +#include <mono/metadata/debug-helpers.h> #include <mono/metadata/exception.h> #include "core/debugger/engine_debugger.h" @@ -57,7 +58,7 @@ namespace GDMonoUtils { MonoObject *unmanaged_get_managed(Object *unmanaged) { if (!unmanaged) - return NULL; + return nullptr; if (unmanaged->get_script_instance()) { CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance()); @@ -71,7 +72,7 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) { void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); - ERR_FAIL_NULL_V(data, NULL); + ERR_FAIL_NULL_V(data, nullptr); CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value(); @@ -82,7 +83,7 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) { // Already had a binding that needs to be setup CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, unmanaged); - ERR_FAIL_COND_V(!script_binding.inited, NULL); + ERR_FAIL_COND_V(!script_binding.inited, nullptr); } } @@ -99,11 +100,11 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) { #ifdef DEBUG_ENABLED CRASH_COND(script_binding.type_name == StringName()); - CRASH_COND(script_binding.wrapper_class == NULL); + CRASH_COND(script_binding.wrapper_class == nullptr); #endif MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged); - ERR_FAIL_NULL_V(mono_object, NULL); + ERR_FAIL_NULL_V(mono_object, nullptr); gchandle = MonoGCHandleData::new_strong_handle(mono_object); @@ -127,10 +128,15 @@ void set_main_thread(MonoThread *p_thread) { } MonoThread *attach_current_thread() { - ERR_FAIL_COND_V(!GDMono::get_singleton()->is_runtime_initialized(), NULL); + ERR_FAIL_COND_V(!GDMono::get_singleton()->is_runtime_initialized(), nullptr); MonoDomain *scripts_domain = GDMono::get_singleton()->get_scripts_domain(); +#ifndef GD_MONO_SINGLE_APPDOMAIN MonoThread *mono_thread = mono_thread_attach(scripts_domain ? scripts_domain : mono_get_root_domain()); - ERR_FAIL_NULL_V(mono_thread, NULL); +#else + // The scripts domain is the root domain + MonoThread *mono_thread = mono_thread_attach(scripts_domain); +#endif + ERR_FAIL_NULL_V(mono_thread, nullptr); return mono_thread; } @@ -152,7 +158,7 @@ MonoThread *get_current_thread() { } bool is_thread_attached() { - return mono_domain_get() != NULL; + return mono_domain_get() != nullptr; } uint32_t new_strong_gchandle(MonoObject *p_object) { @@ -174,11 +180,11 @@ void free_gchandle(uint32_t p_gchandle) { 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); + ctor->invoke_raw(p_this_obj, nullptr, r_exc); } bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b) { - MonoException *exc = NULL; + MonoException *exc = nullptr; MonoBoolean res = CACHED_METHOD_THUNK(Delegate, Equals).invoke((MonoObject *)p_a, (MonoObject *)p_b, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; @@ -221,18 +227,18 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class) { if (assembly == GDMono::get_singleton()->get_editor_api_assembly()) return klass; #endif - } while ((klass = klass->get_parent_class()) != NULL); + } while ((klass = klass->get_parent_class()) != nullptr); - return NULL; + return nullptr; } MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) { bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), p_native); - ERR_FAIL_COND_V_MSG(!parent_is_object_class, NULL, + ERR_FAIL_COND_V_MSG(!parent_is_object_class, nullptr, "Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'."); MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); - ERR_FAIL_NULL_V(mono_object, NULL); + ERR_FAIL_NULL_V(mono_object, nullptr); CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object); @@ -244,7 +250,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa MonoObject *create_managed_from(const StringName &p_from) { MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(StringName)); - ERR_FAIL_NULL_V(mono_object, NULL); + ERR_FAIL_NULL_V(mono_object, nullptr); // Construct GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(StringName)); @@ -256,7 +262,7 @@ MonoObject *create_managed_from(const StringName &p_from) { MonoObject *create_managed_from(const NodePath &p_from) { MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(NodePath)); - ERR_FAIL_NULL_V(mono_object, NULL); + ERR_FAIL_NULL_V(mono_object, nullptr); // Construct GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(NodePath)); @@ -268,7 +274,7 @@ MonoObject *create_managed_from(const NodePath &p_from) { MonoObject *create_managed_from(const RID &p_from) { MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(RID)); - ERR_FAIL_NULL_V(mono_object, NULL); + ERR_FAIL_NULL_V(mono_object, nullptr); // Construct GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(RID)); @@ -280,15 +286,15 @@ MonoObject *create_managed_from(const RID &p_from) { MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) { MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); - ERR_FAIL_NULL_V(mono_object, NULL); + ERR_FAIL_NULL_V(mono_object, nullptr); // Search constructor that takes a pointer as parameter MonoMethod *m; - void *iter = NULL; + void *iter = nullptr; 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; + void *front = nullptr; 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; @@ -296,12 +302,12 @@ MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) { } } - CRASH_COND(m == NULL); + CRASH_COND(m == nullptr); Array *new_array = memnew(Array(p_from)); void *args[1] = { &new_array }; - MonoException *exc = NULL; + MonoException *exc = nullptr; GDMonoUtils::runtime_invoke(m, mono_object, args, &exc); UNHANDLED_EXCEPTION(exc); @@ -310,15 +316,15 @@ MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) { MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) { MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); - ERR_FAIL_NULL_V(mono_object, NULL); + ERR_FAIL_NULL_V(mono_object, nullptr); // Search constructor that takes a pointer as parameter MonoMethod *m; - void *iter = NULL; + void *iter = nullptr; 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; + void *front = nullptr; 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; @@ -326,12 +332,12 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) } } - CRASH_COND(m == NULL); + CRASH_COND(m == nullptr); Dictionary *new_dict = memnew(Dictionary(p_from)); void *args[1] = { &new_dict }; - MonoException *exc = NULL; + MonoException *exc = nullptr; GDMonoUtils::runtime_invoke(m, mono_object, args, &exc); UNHANDLED_EXCEPTION(exc); @@ -341,7 +347,7 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) MonoDomain *create_domain(const String &p_friendly_name) { print_verbose("Mono: Creating domain '" + p_friendly_name + "'..."); - MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL); + MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), nullptr); if (domain) { // Workaround to avoid this exception: @@ -353,6 +359,14 @@ MonoDomain *create_domain(const String &p_friendly_name) { return domain; } +String get_type_desc(MonoType *p_type) { + return mono_type_full_name(p_type); +} + +String get_type_desc(MonoReflectionType *p_reftype) { + return get_type_desc(mono_reflection_type_get_type(p_reftype)); +} + String get_exception_name_and_message(MonoException *p_exc) { String res; @@ -366,7 +380,7 @@ String get_exception_name_and_message(MonoException *p_exc) { res += ": "; MonoProperty *prop = mono_class_get_property_from_name(klass, "Message"); - MonoString *msg = (MonoString *)property_get_value(prop, (MonoObject *)p_exc, NULL, NULL); + MonoString *msg = (MonoString *)property_get_value(prop, (MonoObject *)p_exc, nullptr, nullptr); res += GDMonoMarshal::mono_string_to_godot(msg); return res; @@ -377,7 +391,7 @@ void set_exception_message(MonoException *p_exc, String message) { MonoProperty *prop = mono_class_get_property_from_name(klass, "Message"); MonoString *msg = GDMonoMarshal::mono_string_from_godot(message); void *params[1] = { msg }; - property_set_value(prop, (MonoObject *)p_exc, params, NULL); + property_set_value(prop, (MonoObject *)p_exc, params, nullptr); } void debug_print_unhandled_exception(MonoException *p_exc) { @@ -410,14 +424,14 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) { Vector<ScriptLanguage::StackInfo> si; String exc_msg; - while (p_exc != NULL) { + while (p_exc != nullptr) { GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace); MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr()); MonoBoolean need_file_info = true; void *ctor_args[2] = { p_exc, &need_file_info }; - MonoException *unexpected_exc = NULL; + MonoException *unexpected_exc = nullptr; CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc); if (unexpected_exc) { @@ -426,7 +440,7 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) { } Vector<ScriptLanguage::StackInfo> _si; - if (stack_trace != NULL) { + if (stack_trace != nullptr) { _si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace); for (int i = _si.size() - 1; i >= 0; i--) si.insert(0, _si[i]); @@ -436,10 +450,10 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) { GDMonoClass *exc_class = GDMono::get_singleton()->get_class(mono_get_exception_class()); GDMonoProperty *inner_exc_prop = exc_class->get_property("InnerException"); - CRASH_COND(inner_exc_prop == NULL); + CRASH_COND(inner_exc_prop == nullptr); MonoObject *inner_exc = inner_exc_prop->get_value((MonoObject *)p_exc); - if (inner_exc != NULL) + if (inner_exc != nullptr) si.insert(0, separator); p_exc = (MonoException *)inner_exc; @@ -565,7 +579,7 @@ namespace Marshal { bool type_is_generic_array(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - MonoException *exc = NULL; + MonoException *exc = nullptr; MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; @@ -573,94 +587,75 @@ bool type_is_generic_array(MonoReflectionType *p_reftype) { bool type_is_generic_dictionary(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - MonoException *exc = NULL; + MonoException *exc = nullptr; MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } -void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) { - MonoException *exc = NULL; - CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc); - UNHANDLED_EXCEPTION(exc); -} - -void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { - MonoException *exc = NULL; - CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes).invoke(p_dict_reftype, r_key_reftype, r_value_reftype, &exc); - UNHANDLED_EXCEPTION(exc); -} - -bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) { +bool type_is_system_generic_list(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - MonoException *exc = NULL; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType).invoke(p_reftype, &exc); + MonoException *exc = nullptr; + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericList).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } -bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) { +bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - MonoException *exc = NULL; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType).invoke(p_reftype, &exc); + MonoException *exc = nullptr; + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericDictionary).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } -bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) { +bool type_is_generic_ienumerable(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - MonoException *exc = NULL; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info).invoke(p_reftype, r_elem_reftype, &exc); + MonoException *exc = nullptr; + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIEnumerable).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } -bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { +bool type_is_generic_icollection(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - MonoException *exc = NULL; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info).invoke(p_reftype, r_key_reftype, r_value_reftype, &exc); + MonoException *exc = nullptr; + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericICollection).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } -Array enumerable_to_array(MonoObject *p_enumerable) { - NO_GLUE_RET(Array()); - Array result; - MonoException *exc = NULL; - CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray).invoke(p_enumerable, &result, &exc); +bool type_is_generic_idictionary(MonoReflectionType *p_reftype) { + NO_GLUE_RET(false); + MonoException *exc = nullptr; + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIDictionary).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); - return result; + return (bool)res; } -Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) { - NO_GLUE_RET(Dictionary()); - Dictionary result; - MonoException *exc = NULL; - CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary).invoke(p_idictionary, &result, &exc); +void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) { + MonoException *exc = nullptr; + CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc); UNHANDLED_EXCEPTION(exc); - return result; } -Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) { - NO_GLUE_RET(Dictionary()); - Dictionary result; - MonoException *exc = NULL; - CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary).invoke(p_generic_idictionary, &result, &exc); +void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { + MonoException *exc = nullptr; + CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes).invoke(p_dict_reftype, r_key_reftype, r_value_reftype, &exc); UNHANDLED_EXCEPTION(exc); - return result; } GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) { - NO_GLUE_RET(NULL); - MonoException *exc = NULL; + NO_GLUE_RET(nullptr); + MonoException *exc = nullptr; MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType).invoke(p_elem_reftype, &exc); 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) { - NO_GLUE_RET(NULL); - MonoException *exc = NULL; + NO_GLUE_RET(nullptr); + MonoException *exc = nullptr; MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType).invoke(p_key_reftype, p_value_reftype, &exc); UNHANDLED_EXCEPTION(exc); return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); @@ -669,7 +664,7 @@ GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, Mon } // namespace Marshal ScopeThreadAttach::ScopeThreadAttach() : - mono_thread(NULL) { + mono_thread(nullptr) { if (likely(GDMono::get_singleton()->is_runtime_initialized()) && unlikely(!mono_domain_get())) { mono_thread = GDMonoUtils::attach_current_thread(); } @@ -682,7 +677,7 @@ ScopeThreadAttach::~ScopeThreadAttach() { } StringName get_native_godot_class_name(GDMonoClass *p_class) { - MonoObject *native_name_obj = p_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL); + MonoObject *native_name_obj = p_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(nullptr); StringName *ptr = GDMonoMarshal::unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(native_name_obj)); return ptr ? *ptr : StringName(); } diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index fd02907d87..e3011ade5d 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -41,7 +41,7 @@ #include "core/reference.h" #define UNHANDLED_EXCEPTION(m_exc) \ - if (unlikely(m_exc != NULL)) { \ + if (unlikely(m_exc != nullptr)) { \ GDMonoUtils::debug_unhandled_exception(m_exc); \ GD_UNREACHABLE(); \ } @@ -52,22 +52,18 @@ namespace Marshal { bool type_is_generic_array(MonoReflectionType *p_reftype); bool type_is_generic_dictionary(MonoReflectionType *p_reftype); +bool type_is_system_generic_list(MonoReflectionType *p_reftype); +bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype); +bool type_is_generic_ienumerable(MonoReflectionType *p_reftype); +bool type_is_generic_icollection(MonoReflectionType *p_reftype); +bool type_is_generic_idictionary(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); -bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype); -bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype); -bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype); -bool 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 _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) { @@ -77,7 +73,7 @@ _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) /** * If the object has a csharp script, returns the target of the gchandle stored in the script instance * Otherwise returns a newly constructed MonoObject* which is attached to the object - * Returns NULL on error + * Returns nullptr on error */ MonoObject *unmanaged_get_managed(Object *unmanaged); @@ -89,7 +85,7 @@ MonoThread *get_current_thread(); bool is_thread_attached(); _FORCE_INLINE_ bool is_main_thread() { - return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current(); + return mono_domain_get() != nullptr && mono_thread_get_main() == mono_thread_current(); } uint32_t new_strong_gchandle(MonoObject *p_object); @@ -97,7 +93,7 @@ uint32_t new_strong_gchandle_pinned(MonoObject *p_object); uint32_t new_weak_gchandle(MonoObject *p_object); void free_gchandle(uint32_t p_gchandle); -void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = NULL); +void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = nullptr); bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b); @@ -115,6 +111,9 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class); MonoDomain *create_domain(const String &p_friendly_name); +String get_type_desc(MonoType *p_type); +String get_type_desc(MonoReflectionType *p_reftype); + String get_exception_name_and_message(MonoException *p_exc); void set_exception_message(MonoException *p_exc, String message); diff --git a/modules/mono/mono_gd/managed_type.h b/modules/mono/mono_gd/managed_type.h index 11b832d0cc..84d1837853 100644 --- a/modules/mono/mono_gd/managed_type.h +++ b/modules/mono/mono_gd/managed_type.h @@ -46,7 +46,7 @@ struct ManagedType { ManagedType() : type_encoding(0), - type_class(NULL) { + type_class(nullptr) { } ManagedType(int p_type_encoding, GDMonoClass *p_type_class) : diff --git a/modules/mono/mono_gd/gd_mono_android.cpp b/modules/mono/mono_gd/support/android_support.cpp index 761368878f..8bcdeec9dd 100644..100755 --- a/modules/mono/mono_gd/gd_mono_android.cpp +++ b/modules/mono/mono_gd/support/android_support.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gd_mono_android.cpp */ +/* android_support.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gd_mono_android.h" +#include "android_support.h" #if defined(ANDROID_ENABLED) @@ -49,14 +49,16 @@ #include "platform/android/os_android.h" #include "platform/android/thread_jandroid.h" -#include "../utils/path_utils.h" -#include "../utils/string_utils.h" -#include "gd_mono_cache.h" -#include "gd_mono_marshal.h" +#include "../../utils/path_utils.h" +#include "../../utils/string_utils.h" +#include "../gd_mono_cache.h" +#include "../gd_mono_marshal.h" // Warning: JNI boilerplate ahead... continue at your own risk -namespace GDMonoAndroid { +namespace gdmono { +namespace android { +namespace support { template <typename T> struct ScopedLocalRef { @@ -67,7 +69,7 @@ struct ScopedLocalRef { _FORCE_INLINE_ operator T() const { return local_ref; } _FORCE_INLINE_ operator jvalue() const { return (jvalue)local_ref; } - _FORCE_INLINE_ operator bool() const { return local_ref != NULL; } + _FORCE_INLINE_ operator bool() const { return local_ref != nullptr; } _FORCE_INLINE_ bool operator==(std::nullptr_t) const { return local_ref == nullptr; @@ -122,7 +124,7 @@ String determine_app_native_lib_dir() { String result; - const char *const nativeLibraryDirUtf8 = env->GetStringUTFChars(nativeLibraryDir, NULL); + const char *const nativeLibraryDirUtf8 = env->GetStringUTFChars(nativeLibraryDir, nullptr); if (nativeLibraryDirUtf8) { result.parse_utf8(nativeLibraryDirUtf8); env->ReleaseStringUTFChars(nativeLibraryDir, nativeLibraryDirUtf8); @@ -150,21 +152,21 @@ int gd_mono_convert_dl_flags(int flags) { return lflags; } -#ifndef GD_MONO_ANDROID_SO_NAME -#define GD_MONO_ANDROID_SO_NAME "libmonosgen-2.0.so" +#ifndef GD_MONO_SO_NAME +#define GD_MONO_SO_NAME "libmonosgen-2.0.so" #endif -const char *mono_so_name = GD_MONO_ANDROID_SO_NAME; +const char *mono_so_name = GD_MONO_SO_NAME; const char *godot_so_name = "libgodot_android.so"; -void *mono_dl_handle = NULL; -void *godot_dl_handle = NULL; +void *mono_dl_handle = nullptr; +void *godot_dl_handle = nullptr; void *try_dlopen(const String &p_so_path, int p_flags) { if (!FileAccess::exists(p_so_path)) { if (OS::get_singleton()->is_stdout_verbose()) OS::get_singleton()->print("Cannot find shared library: '%s'\n", p_so_path.utf8().get_data()); - return NULL; + return nullptr; } int lflags = gd_mono_convert_dl_flags(p_flags); @@ -174,7 +176,7 @@ void *try_dlopen(const String &p_so_path, int p_flags) { if (!handle) { if (OS::get_singleton()->is_stdout_verbose()) OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", p_so_path.utf8().get_data(), dlerror()); - return NULL; + return nullptr; } if (OS::get_singleton()->is_stdout_verbose()) @@ -184,7 +186,7 @@ void *try_dlopen(const String &p_so_path, int p_flags) { } void *gd_mono_android_dlopen(const char *p_name, int p_flags, char **r_err, void *p_user_data) { - if (p_name == NULL) { + if (p_name == nullptr) { // __Internal if (!mono_dl_handle) { @@ -209,7 +211,7 @@ void *gd_mono_android_dlopen(const char *p_name, int p_flags, char **r_err, void return try_dlopen(so_path, p_flags); } - return NULL; + return nullptr; } void *gd_mono_android_dlsym(void *p_handle, const char *p_name, char **r_err, void *p_user_data) { @@ -230,7 +232,7 @@ void *gd_mono_android_dlsym(void *p_handle, const char *p_name, char **r_err, vo if (r_err) *r_err = str_format_new("%s\n", dlerror()); - return NULL; + return nullptr; } void *gd_mono_android_dlclose(void *p_handle, void *p_user_data) { @@ -238,9 +240,9 @@ void *gd_mono_android_dlclose(void *p_handle, void *p_user_data) { // Not sure if this ever happens. Does Mono close the handle for the main module? if (p_handle == mono_dl_handle) - mono_dl_handle = NULL; + mono_dl_handle = nullptr; - return NULL; + return nullptr; } int32_t build_version_sdk_int = 0; @@ -265,7 +267,7 @@ int32_t get_build_version_sdk_int() { return build_version_sdk_int; } -jobject certStore = NULL; // KeyStore +jobject certStore = nullptr; // KeyStore MonoBoolean _gd_mono_init_cert_store() { // The JNI code is the equivalent of: @@ -293,7 +295,7 @@ MonoBoolean _gd_mono_init_cert_store() { if (jni_exception_check(env)) return 0; - env->CallVoidMethod(certStoreLocal, load, NULL); + env->CallVoidMethod(certStoreLocal, load, nullptr); if (jni_exception_check(env)) return 0; @@ -317,7 +319,7 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) { if (!mono_error_ok(&mono_error)) { ERR_PRINT(String() + "Failed to convert MonoString* to UTF-8: '" + mono_error_get_message(&mono_error) + "'."); mono_error_cleanup(&mono_error); - return NULL; + return nullptr; } JNIEnv *env = ThreadAndroid::get_env(); @@ -326,20 +328,20 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) { mono_free(alias_utf8); ScopedLocalRef<jclass> keyStoreClass(env, env->FindClass("java/security/KeyStore")); - ERR_FAIL_NULL_V(keyStoreClass, NULL); + ERR_FAIL_NULL_V(keyStoreClass, nullptr); ScopedLocalRef<jclass> certificateClass(env, env->FindClass("java/security/cert/Certificate")); - ERR_FAIL_NULL_V(certificateClass, NULL); + ERR_FAIL_NULL_V(certificateClass, nullptr); jmethodID getCertificate = env->GetMethodID(keyStoreClass, "getCertificate", "(Ljava/lang/String;)Ljava/security/cert/Certificate;"); - ERR_FAIL_NULL_V(getCertificate, NULL); + ERR_FAIL_NULL_V(getCertificate, nullptr); jmethodID getEncoded = env->GetMethodID(certificateClass, "getEncoded", "()[B"); - ERR_FAIL_NULL_V(getEncoded, NULL); + ERR_FAIL_NULL_V(getEncoded, nullptr); ScopedLocalRef<jobject> certificate(env, env->CallObjectMethod(certStore, getCertificate, js_alias.get())); if (!certificate) - return NULL; + return nullptr; ScopedLocalRef<jbyteArray> encoded(env, (jbyteArray)env->CallObjectMethod(certificate, getEncoded)); jsize encodedLength = env->GetArrayLength(encoded); @@ -352,11 +354,16 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) { return encoded_ret; } +void register_internal_calls() { + mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", (void *)_gd_mono_init_cert_store); + mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", (void *)_gd_mono_android_cert_store_lookup); +} + void initialize() { // We need to set this environment variable to make the monodroid BCL use btls instead of legacy as the default provider OS::get_singleton()->set_environment("XA_TLS_PROVIDER", "btls"); - mono_dl_fallback_register(gd_mono_android_dlopen, gd_mono_android_dlsym, gd_mono_android_dlclose, NULL); + mono_dl_fallback_register(gd_mono_android_dlopen, gd_mono_android_dlsym, gd_mono_android_dlclose, nullptr); String app_native_lib_dir = get_app_native_lib_dir(); String so_path = path::join(app_native_lib_dir, godot_so_name); @@ -364,31 +371,28 @@ void initialize() { godot_dl_handle = try_dlopen(so_path, gd_mono_convert_dl_flags(MONO_DL_LAZY)); } -void register_internal_calls() { - mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", (void *)_gd_mono_init_cert_store); - mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", (void *)_gd_mono_android_cert_store_lookup); -} - void cleanup() { // This is called after shutting down the Mono runtime if (mono_dl_handle) - gd_mono_android_dlclose(mono_dl_handle, NULL); + gd_mono_android_dlclose(mono_dl_handle, nullptr); if (godot_dl_handle) - gd_mono_android_dlclose(godot_dl_handle, NULL); + gd_mono_android_dlclose(godot_dl_handle, nullptr); JNIEnv *env = ThreadAndroid::get_env(); if (certStore) { env->DeleteGlobalRef(certStore); - certStore = NULL; + certStore = nullptr; } } -} // namespace GDMonoAndroid +} // namespace support +} // namespace android +} // namespace gdmono -using namespace GDMonoAndroid; +using namespace gdmono::android::support; // The following are P/Invoke functions required by the monodroid profile of the BCL. // These are P/Invoke functions and not internal calls, hence why they use @@ -417,7 +421,7 @@ GD_PINVOKE_EXPORT int32_t monodroid_get_system_property(const char *p_name, char memcpy(*r_value, prop_value_str, len); (*r_value)[len] = '\0'; } else { - *r_value = NULL; + *r_value = nullptr; } } @@ -604,7 +608,7 @@ GD_PINVOKE_EXPORT int32_t _monodroid_get_dns_servers(void **r_dns_servers_array) if (!r_dns_servers_array) return -1; - *r_dns_servers_array = NULL; + *r_dns_servers_array = nullptr; char *dns_servers[dns_servers_len]; int dns_servers_count = 0; @@ -648,23 +652,23 @@ GD_PINVOKE_EXPORT const char *_monodroid_timezone_get_default_id() { JNIEnv *env = ThreadAndroid::get_env(); ScopedLocalRef<jclass> timeZoneClass(env, env->FindClass("java/util/TimeZone")); - ERR_FAIL_NULL_V(timeZoneClass, NULL); + ERR_FAIL_NULL_V(timeZoneClass, nullptr); jmethodID getDefault = env->GetStaticMethodID(timeZoneClass, "getDefault", "()Ljava/util/TimeZone;"); - ERR_FAIL_NULL_V(getDefault, NULL); + ERR_FAIL_NULL_V(getDefault, nullptr); jmethodID getID = env->GetMethodID(timeZoneClass, "getID", "()Ljava/lang/String;"); - ERR_FAIL_NULL_V(getID, NULL); + ERR_FAIL_NULL_V(getID, nullptr); ScopedLocalRef<jobject> defaultTimeZone(env, env->CallStaticObjectMethod(timeZoneClass, getDefault)); if (!defaultTimeZone) - return NULL; + return nullptr; ScopedLocalRef<jstring> defaultTimeZoneID(env, (jstring)env->CallObjectMethod(defaultTimeZone, getID)); if (!defaultTimeZoneID) - return NULL; + return nullptr; const char *default_time_zone_id = env->GetStringUTFChars(defaultTimeZoneID, 0); diff --git a/modules/mono/mono_gd/gd_mono_android.h b/modules/mono/mono_gd/support/android_support.h index 0e04847924..dc2e6c95ed 100644..100755 --- a/modules/mono/mono_gd/gd_mono_android.h +++ b/modules/mono/mono_gd/support/android_support.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gd_mono_android.h */ +/* android_support.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,25 +28,28 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GD_MONO_ANDROID_H -#define GD_MONO_ANDROID_H +#ifndef ANDROID_SUPPORT_H +#define ANDROID_SUPPORT_H #if defined(ANDROID_ENABLED) #include "core/ustring.h" -namespace GDMonoAndroid { +namespace gdmono { +namespace android { +namespace support { String get_app_native_lib_dir(); void initialize(); +void cleanup(); void register_internal_calls(); -void cleanup(); - -} // namespace GDMonoAndroid +} // namespace support +} // namespace android +} // namespace gdmono #endif // ANDROID_ENABLED -#endif // GD_MONO_ANDROID_H +#endif // ANDROID_SUPPORT_H diff --git a/modules/mono/mono_gd/support/ios_support.h b/modules/mono/mono_gd/support/ios_support.h new file mode 100755 index 0000000000..e28af120e3 --- /dev/null +++ b/modules/mono/mono_gd/support/ios_support.h @@ -0,0 +1,51 @@ +/*************************************************************************/ +/* ios_support.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 IOS_SUPPORT_H +#define IOS_SUPPORT_H + +#if defined(IPHONE_ENABLED) + +#include "core/ustring.h" + +namespace gdmono { +namespace ios { +namespace support { + +void initialize(); +void cleanup(); + +} // namespace support +} // namespace ios +} // namespace gdmono + +#endif // IPHONE_ENABLED + +#endif // IOS_SUPPORT_H diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm new file mode 100755 index 0000000000..e3d1a647fd --- /dev/null +++ b/modules/mono/mono_gd/support/ios_support.mm @@ -0,0 +1,151 @@ +/*************************************************************************/ +/* ios_support.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "ios_support.h" + +#if defined(IPHONE_ENABLED) + +#import <Foundation/Foundation.h> +#include <os/log.h> + +#include "core/ustring.h" + +#include "../gd_mono_marshal.h" + +// Implemented mostly following: https://github.com/mono/mono/blob/master/sdks/ios/app/runtime.m + +// Definition generated by the Godot exporter +extern "C" void gd_mono_setup_aot(); + +namespace gdmono { +namespace ios { +namespace support { + +void ios_mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) { + os_log_info(OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message); + if (fatal) { + os_log_info(OS_LOG_DEFAULT, "Exit code: %d.", 1); + exit(1); + } +} + +void initialize() { + mono_dllmap_insert(NULL, "System.Native", NULL, "__Internal", NULL); + mono_dllmap_insert(NULL, "System.IO.Compression.Native", NULL, "__Internal", NULL); + mono_dllmap_insert(NULL, "System.Security.Cryptography.Native.Apple", NULL, "__Internal", NULL); + +#ifdef IOS_DEVICE + // This function is defined in an auto-generated source file + gd_mono_setup_aot(); +#endif + + mono_set_signal_chaining(true); + mono_set_crash_chaining(true); +} + +void cleanup() { +} + +} // namespace support +} // namespace ios +} // namespace gdmono + +// The following are P/Invoke functions required by the monotouch profile of the BCL. +// These are P/Invoke functions and not internal calls, hence why they use +// 'mono_bool' and 'const char*' instead of 'MonoBoolean' and 'MonoString*'. + +#define GD_PINVOKE_EXPORT extern "C" __attribute__((visibility("default"))) + +GD_PINVOKE_EXPORT const char *xamarin_get_locale_country_code() { + NSLocale *locale = [NSLocale currentLocale]; + NSString *countryCode = [locale objectForKey:NSLocaleCountryCode]; + if (countryCode == NULL) { + return strdup("US"); + } + return strdup([countryCode UTF8String]); +} + +GD_PINVOKE_EXPORT void xamarin_log(const uint16_t *p_unicode_message) { + int length = 0; + const uint16_t *ptr = p_unicode_message; + while (*ptr++) + length += sizeof(uint16_t); + NSString *msg = [[NSString alloc] initWithBytes:p_unicode_message length:length encoding:NSUTF16LittleEndianStringEncoding]; + + os_log_info(OS_LOG_DEFAULT, "%{public}@", msg); +} + +GD_PINVOKE_EXPORT const char *xamarin_GetFolderPath(int p_folder) { + NSSearchPathDirectory dd = (NSSearchPathDirectory)p_folder; + NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:dd inDomains:NSUserDomainMask] lastObject]; + NSString *path = [url path]; + return strdup([path UTF8String]); +} + +GD_PINVOKE_EXPORT char *xamarin_timezone_get_local_name() { + NSTimeZone *tz = nil; + tz = [NSTimeZone localTimeZone]; + NSString *name = [tz name]; + return (name != nil) ? strdup([name UTF8String]) : strdup("Local"); +} + +GD_PINVOKE_EXPORT char **xamarin_timezone_get_names(uint32_t *p_count) { + NSArray *array = [NSTimeZone knownTimeZoneNames]; + *p_count = array.count; + char **result = (char **)malloc(sizeof(char *) * (*p_count)); + for (uint32_t i = 0; i < *p_count; i++) { + NSString *s = [array objectAtIndex:i]; + result[i] = strdup(s.UTF8String); + } + return result; +} + +GD_PINVOKE_EXPORT void *xamarin_timezone_get_data(const char *p_name, uint32_t *p_size) { // FIXME: uint32_t since Dec 2019, unsigned long before + NSTimeZone *tz = nil; + if (p_name) { + NSString *n = [[NSString alloc] initWithUTF8String:p_name]; + tz = [[[NSTimeZone alloc] initWithName:n] autorelease]; + [n release]; + } else { + tz = [NSTimeZone localTimeZone]; + } + NSData *data = [tz data]; + *p_size = [data length]; + void *result = malloc(*p_size); + memcpy(result, data.bytes, *p_size); + return result; +} + +GD_PINVOKE_EXPORT void xamarin_start_wwan(const char *p_uri) { + // FIXME: What's this for? No idea how to implement. + os_log_error(OS_LOG_DEFAULT, "Not implemented: 'xamarin_start_wwan'"); +} + +#endif // IPHONE_ENABLED |