summaryrefslogtreecommitdiff
path: root/modules/mono/mono_gd
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/mono_gd')
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp233
-rw-r--r--modules/mono/mono_gd/gd_mono.h27
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp22
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp17
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h1
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp28
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp7
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp36
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp114
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h24
10 files changed, 318 insertions, 191 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index c90da31f3a..7ae991eeaa 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -52,7 +52,6 @@
#include "gd_mono_utils.h"
#ifdef TOOLS_ENABLED
-#include "../editor/godotsharp_editor.h"
#include "main/main.h"
#endif
@@ -99,7 +98,7 @@ void gdmono_profiler_init() {
#ifdef DEBUG_ENABLED
-static bool _wait_for_debugger_msecs(uint32_t p_msecs) {
+bool _wait_for_debugger_msecs(uint32_t p_msecs) {
do {
if (mono_is_debugger_attached())
@@ -129,16 +128,17 @@ void gdmono_debug_init() {
bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false);
int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000);
+ CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8();
+
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint() ||
ProjectSettings::get_singleton()->get_resource_path().empty() ||
Main::is_project_manager()) {
- return;
+ if (da_args.size() == 0)
+ return;
}
#endif
- CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8();
-
if (da_args.length() == 0) {
da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) +
",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n"))
@@ -207,6 +207,10 @@ void GDMono::initialize() {
print_verbose("Mono: Initializing module...");
+ char *runtime_build_info = mono_get_runtime_build_info();
+ print_verbose("Mono JIT compiler version " + String(runtime_build_info));
+ mono_free(runtime_build_info);
+
#ifdef DEBUG_METHODS_ENABLED
_initialize_and_check_api_hashes();
#endif
@@ -339,18 +343,6 @@ void GDMono::initialize() {
ERR_EXPLAIN("Mono: Failed to load mscorlib assembly");
ERR_FAIL_COND(!_load_corlib_assembly());
-#ifdef TOOLS_ENABLED
- // The tools domain must be loaded here, before the scripts domain.
- // Otherwise domain unload on the scripts domain will hang indefinitely.
-
- ERR_EXPLAIN("Mono: Failed to load tools domain");
- ERR_FAIL_COND(_load_tools_domain() != OK);
-
- // TODO move to editor init callback, and do it lazily when required before editor init (e.g.: bindings generation)
- ERR_EXPLAIN("Mono: Failed to load Editor Tools assembly");
- ERR_FAIL_COND(!_load_editor_tools_assembly());
-#endif
-
ERR_EXPLAIN("Mono: Failed to load scripts domain");
ERR_FAIL_COND(_load_scripts_domain() != OK);
@@ -365,8 +357,15 @@ void GDMono::initialize() {
// The following assemblies are not required at initialization
#ifdef MONO_GLUE_ENABLED
if (_load_api_assemblies()) {
- // Everything is fine with the api assemblies, load the project assembly
+ // Everything is fine with the api assemblies, load the tools and project assemblies
+
+#if defined(TOOLS_ENABLED)
+ ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies");
+ ERR_FAIL_COND(!_load_tools_assemblies());
+#endif
+
_load_project_assembly();
+
} else {
if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated))
#ifdef TOOLS_ENABLED
@@ -427,10 +426,6 @@ void GDMono::_register_internal_calls() {
#ifdef MONO_GLUE_ENABLED
GodotSharpBindings::register_generated_icalls();
#endif
-
-#ifdef TOOLS_ENABLED
- GodotSharpEditor::register_internal_calls();
-#endif
}
void GDMono::_initialize_and_check_api_hashes() {
@@ -569,6 +564,50 @@ bool GDMono::_load_corlib_assembly() {
return success;
}
+static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type) {
+
+ // Create destination directory if needed
+ if (!DirAccess::exists(p_dst_dir)) {
+ DirAccess *da = DirAccess::create_for_path(p_dst_dir);
+ Error err = da->make_dir_recursive(p_dst_dir);
+ memdelete(da);
+
+ if (err != OK) {
+ ERR_PRINTS("Failed to create destination directory for the API assemblies. Error: " + itos(err));
+ return false;
+ }
+ }
+
+ String assembly_file = p_assembly_name + ".dll";
+ String assembly_src = p_src_dir.plus_file(assembly_file);
+ String assembly_dst = p_dst_dir.plus_file(assembly_file);
+
+ if (!FileAccess::exists(assembly_dst) ||
+ FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst) ||
+ GDMono::get_singleton()->metadata_is_api_assembly_invalidated(p_api_type)) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ String xml_file = p_assembly_name + ".xml";
+ if (da->copy(p_src_dir.plus_file(xml_file), p_dst_dir.plus_file(xml_file)) != OK)
+ WARN_PRINTS("Failed to copy " + xml_file);
+
+ String pdb_file = p_assembly_name + ".pdb";
+ if (da->copy(p_src_dir.plus_file(pdb_file), p_dst_dir.plus_file(pdb_file)) != OK)
+ WARN_PRINTS("Failed to copy " + pdb_file);
+
+ Error err = da->copy(assembly_src, assembly_dst);
+
+ if (err != OK) {
+ ERR_PRINTS("Failed to copy " + assembly_file);
+ return false;
+ }
+
+ GDMono::get_singleton()->metadata_set_api_assembly_invalidated(p_api_type, false);
+ }
+
+ return true;
+}
+
bool GDMono::_load_core_api_assembly() {
if (core_api_assembly)
@@ -576,19 +615,31 @@ bool GDMono::_load_core_api_assembly() {
#ifdef TOOLS_ENABLED
if (metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) {
- print_verbose("Mono: Skipping loading of Core API assembly because it was invalidated");
- return false;
+ String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug");
+ String prebuilt_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
+ String invalidated_dll_path = get_invalidated_api_assembly_path(APIAssembly::API_CORE);
+
+ if (!FileAccess::exists(prebuilt_dll_path) ||
+ FileAccess::get_modified_time(invalidated_dll_path) == FileAccess::get_modified_time(prebuilt_dll_path)) {
+ print_verbose("Mono: Skipping loading of Core API assembly because it was invalidated");
+ return false;
+ } else {
+ // Copy the prebuilt Api
+ String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
+ if (!copy_api_assembly(prebuilt_api_dir, res_assemblies_dir, CORE_API_ASSEMBLY_NAME, APIAssembly::API_CORE) ||
+ !copy_api_assembly(prebuilt_api_dir, res_assemblies_dir, EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) {
+ print_verbose("Mono: Failed to copy prebuilt API. Skipping loading of Core API assembly because it was invalidated");
+ return false;
+ }
+ }
}
#endif
String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- if (!FileAccess::exists(assembly_path))
- return false;
-
- bool success = load_assembly_from(CORE_API_ASSEMBLY_NAME,
- assembly_path,
- &core_api_assembly);
+ bool success = (FileAccess::exists(assembly_path) &&
+ load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &core_api_assembly)) ||
+ load_assembly(CORE_API_ASSEMBLY_NAME, &core_api_assembly);
if (success) {
#ifdef MONO_GLUE_ENABLED
@@ -616,18 +667,29 @@ bool GDMono::_load_editor_api_assembly() {
return true;
if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) {
- print_verbose("Mono: Skipping loading of Editor API assembly because it was invalidated");
- return false;
+ String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug");
+ String prebuilt_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
+ String invalidated_dll_path = get_invalidated_api_assembly_path(APIAssembly::API_EDITOR);
+
+ if (!FileAccess::exists(prebuilt_dll_path) ||
+ FileAccess::get_modified_time(invalidated_dll_path) == FileAccess::get_modified_time(prebuilt_dll_path)) {
+ print_verbose("Mono: Skipping loading of Editor API assembly because it was invalidated");
+ return false;
+ } else {
+ // Copy the prebuilt editor Api (no need to copy the core api if we got to this point)
+ String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
+ if (!copy_api_assembly(prebuilt_api_dir, res_assemblies_dir, EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) {
+ print_verbose("Mono: Failed to copy prebuilt API. Skipping loading of Editor API assembly because it was invalidated");
+ return false;
+ }
+ }
}
String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
- if (!FileAccess::exists(assembly_path))
- return false;
-
- bool success = load_assembly_from(EDITOR_API_ASSEMBLY_NAME,
- assembly_path,
- &editor_api_assembly);
+ bool success = (FileAccess::exists(assembly_path) &&
+ load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &editor_api_assembly)) ||
+ load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
if (success) {
#ifdef MONO_GLUE_ENABLED
@@ -643,14 +705,15 @@ bool GDMono::_load_editor_api_assembly() {
#endif
#ifdef TOOLS_ENABLED
-bool GDMono::_load_editor_tools_assembly() {
+bool GDMono::_load_tools_assemblies() {
- if (editor_tools_assembly)
+ if (tools_assembly && tools_project_editor_assembly)
return true;
- _GDMONO_SCOPE_DOMAIN_(tools_domain)
+ bool success = load_assembly(TOOLS_ASSEMBLY_NAME, &tools_assembly) &&
+ load_assembly(TOOLS_PROJECT_EDITOR_ASSEMBLY_NAME, &tools_project_editor_assembly);
- return load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly);
+ return success;
}
#endif
@@ -781,6 +844,14 @@ bool GDMono::metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type)
return metadata->get_value(section, "invalidated", false) && modified_time <= stored_modified_time;
}
+
+String GDMono::get_invalidated_api_assembly_path(APIAssembly::Type p_api_type) {
+
+ return GodotSharpDirs::get_res_assemblies_dir()
+ .plus_file(p_api_type == APIAssembly::API_CORE ?
+ CORE_API_ASSEMBLY_NAME ".dll" :
+ EDITOR_API_ASSEMBLY_NAME ".dll");
+}
#endif
Error GDMono::_load_scripts_domain() {
@@ -826,6 +897,8 @@ Error GDMono::_unload_scripts_domain() {
project_assembly = NULL;
#ifdef TOOLS_ENABLED
editor_api_assembly = NULL;
+ tools_assembly = NULL;
+ tools_project_editor_assembly = NULL;
#endif
core_api_assembly_out_of_sync = false;
@@ -848,22 +921,6 @@ Error GDMono::_unload_scripts_domain() {
return OK;
}
-#ifdef TOOLS_ENABLED
-Error GDMono::_load_tools_domain() {
-
- ERR_FAIL_COND_V(tools_domain != NULL, ERR_BUG);
-
- print_verbose("Mono: Loading tools domain...");
-
- tools_domain = GDMonoUtils::create_domain("GodotEngine.ToolsDomain");
-
- ERR_EXPLAIN("Mono: Could not create tools app domain");
- ERR_FAIL_NULL_V(tools_domain, ERR_CANT_CREATE);
-
- return OK;
-}
-#endif
-
#ifdef GD_MONO_HOT_RELOAD
Error GDMono::reload_scripts_domain() {
@@ -925,6 +982,11 @@ Error GDMono::reload_scripts_domain() {
}
}
+#ifdef TOOLS_ENABLED
+ ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies");
+ ERR_FAIL_COND_V(!_load_tools_assemblies(), ERR_CANT_OPEN);
+#endif
+
if (!_load_project_assembly()) {
return ERR_CANT_OPEN;
}
@@ -939,7 +1001,7 @@ Error GDMono::reload_scripts_domain() {
Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
CRASH_COND(p_domain == NULL);
- CRASH_COND(p_domain == SCRIPTS_DOMAIN); // Should use _unload_scripts_domain() instead
+ 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);
@@ -956,18 +1018,12 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
_domain_assemblies_cleanup(mono_domain_get_id(p_domain));
-#ifdef TOOLS_ENABLED
- if (p_domain == tools_domain) {
- editor_tools_assembly = NULL;
- }
-#endif
-
MonoException *exc = NULL;
mono_domain_try_unload(p_domain, (MonoObject **)&exc);
if (exc) {
ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`");
- GDMonoUtils::debug_unhandled_exception(exc);
+ GDMonoUtils::debug_print_unhandled_exception(exc);
return FAILED;
}
@@ -998,6 +1054,22 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
return NULL;
}
+GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &p_name) {
+
+ uint32_t domain_id = mono_domain_get_id(mono_domain_get());
+ HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
+
+ const String *k = NULL;
+ while ((k = domain_assemblies.next(k))) {
+ GDMonoAssembly *assembly = domain_assemblies.get(*k);
+ GDMonoClass *klass = assembly->get_class(p_namespace, p_name);
+ if (klass)
+ return klass;
+ }
+
+ return NULL;
+}
+
void GDMono::_domain_assemblies_cleanup(uint32_t p_domain_id) {
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
@@ -1038,9 +1110,6 @@ GDMono::GDMono() {
root_domain = NULL;
scripts_domain = NULL;
-#ifdef TOOLS_ENABLED
- tools_domain = NULL;
-#endif
core_api_assembly_out_of_sync = false;
#ifdef TOOLS_ENABLED
@@ -1052,7 +1121,8 @@ GDMono::GDMono() {
project_assembly = NULL;
#ifdef TOOLS_ENABLED
editor_api_assembly = NULL;
- editor_tools_assembly = NULL;
+ tools_assembly = NULL;
+ tools_project_editor_assembly = NULL;
#endif
api_core_hash = 0;
@@ -1064,16 +1134,6 @@ GDMono::GDMono() {
GDMono::~GDMono() {
if (is_runtime_initialized()) {
-
-#ifdef TOOLS_ENABLED
- if (tools_domain) {
- Error err = finalize_and_unload_domain(tools_domain);
- if (err != OK) {
- ERR_PRINT("Mono: Failed to unload tools domain");
- }
- }
-#endif
-
if (scripts_domain) {
Error err = _unload_scripts_domain();
if (err != OK) {
@@ -1128,14 +1188,14 @@ int32_t _GodotSharp::get_domain_id() {
int32_t _GodotSharp::get_scripts_domain_id() {
- MonoDomain *domain = SCRIPTS_DOMAIN;
+ MonoDomain *domain = GDMono::get_singleton()->get_scripts_domain();
CRASH_COND(!domain); // User must check if scripts domain is loaded before calling this method
return mono_domain_get_id(domain);
}
bool _GodotSharp::is_scripts_domain_loaded() {
- return GDMono::get_singleton()->is_runtime_initialized() && SCRIPTS_DOMAIN != NULL;
+ return GDMono::get_singleton()->is_runtime_initialized() && GDMono::get_singleton()->get_scripts_domain() != NULL;
}
bool _GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) {
@@ -1157,7 +1217,7 @@ bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
if (!p_domain)
return true;
- if (p_domain == SCRIPTS_DOMAIN && GDMono::get_singleton()->is_finalizing_scripts_domain())
+ if (p_domain == GDMono::get_singleton()->get_scripts_domain() && GDMono::get_singleton()->is_finalizing_scripts_domain())
return true;
return mono_domain_is_unloading(p_domain);
}
@@ -1172,6 +1232,12 @@ bool _GodotSharp::is_runtime_initialized() {
return GDMono::get_singleton()->is_runtime_initialized();
}
+void _GodotSharp::_reload_assemblies(bool p_soft_reload) {
+#ifdef GD_MONO_HOT_RELOAD
+ CSharpLanguage::get_singleton()->reload_assemblies(p_soft_reload);
+#endif
+}
+
void _GodotSharp::_bind_methods() {
ClassDB::bind_method(D_METHOD("attach_thread"), &_GodotSharp::attach_thread);
@@ -1184,6 +1250,7 @@ void _GodotSharp::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_runtime_shutting_down"), &_GodotSharp::is_runtime_shutting_down);
ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &_GodotSharp::is_runtime_initialized);
+ ClassDB::bind_method(D_METHOD("_reload_assemblies"), &_GodotSharp::_reload_assemblies);
}
_GodotSharp::_GodotSharp() {
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 95340edcca..a926bf4126 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -78,11 +78,6 @@ struct Version {
String to_string(Type p_type);
} // namespace APIAssembly
-#define SCRIPTS_DOMAIN GDMono::get_singleton()->get_scripts_domain()
-#ifdef TOOLS_ENABLED
-#define TOOLS_DOMAIN GDMono::get_singleton()->get_tools_domain()
-#endif
-
class GDMono {
bool runtime_initialized;
@@ -90,9 +85,6 @@ class GDMono {
MonoDomain *root_domain;
MonoDomain *scripts_domain;
-#ifdef TOOLS_ENABLED
- MonoDomain *tools_domain;
-#endif
bool core_api_assembly_out_of_sync;
#ifdef TOOLS_ENABLED
@@ -104,7 +96,8 @@ class GDMono {
GDMonoAssembly *project_assembly;
#ifdef TOOLS_ENABLED
GDMonoAssembly *editor_api_assembly;
- GDMonoAssembly *editor_tools_assembly;
+ GDMonoAssembly *tools_assembly;
+ GDMonoAssembly *tools_project_editor_assembly;
#endif
HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies;
@@ -115,7 +108,7 @@ class GDMono {
bool _load_core_api_assembly();
#ifdef TOOLS_ENABLED
bool _load_editor_api_assembly();
- bool _load_editor_tools_assembly();
+ bool _load_tools_assemblies();
#endif
bool _load_project_assembly();
@@ -132,10 +125,6 @@ class GDMono {
Error _load_scripts_domain();
Error _unload_scripts_domain();
-#ifdef TOOLS_ENABLED
- Error _load_tools_domain();
-#endif
-
uint64_t api_core_hash;
#ifdef TOOLS_ENABLED
uint64_t api_editor_hash;
@@ -170,6 +159,7 @@ public:
#ifdef TOOLS_ENABLED
void metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type, bool p_invalidated);
bool metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type);
+ String get_invalidated_api_assembly_path(APIAssembly::Type p_api_type);
#endif
static GDMono *get_singleton() { return singleton; }
@@ -185,16 +175,14 @@ public:
_FORCE_INLINE_ bool is_finalizing_scripts_domain() { return finalizing_scripts_domain; }
_FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
-#ifdef TOOLS_ENABLED
- _FORCE_INLINE_ MonoDomain *get_tools_domain() { return tools_domain; }
-#endif
_FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
_FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly; }
_FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
#ifdef TOOLS_ENABLED
_FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_editor_tools_assembly() const { return editor_tools_assembly; }
+ _FORCE_INLINE_ GDMonoAssembly *get_tools_assembly() const { return tools_assembly; }
+ _FORCE_INLINE_ GDMonoAssembly *get_tools_project_editor_assembly() const { return tools_project_editor_assembly; }
#endif
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
@@ -202,6 +190,7 @@ public:
#endif
GDMonoClass *get_class(MonoClass *p_raw_class);
+ GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name);
#ifdef GD_MONO_HOT_RELOAD
Error reload_scripts_domain();
@@ -276,6 +265,8 @@ class _GodotSharp : public Object {
List<NodePath *> np_delete_queue;
List<RID *> rid_delete_queue;
+ void _reload_assemblies(bool p_soft_reload);
+
protected:
static _GodotSharp *singleton;
static void _bind_methods();
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 1b765a09ff..8e63ef3563 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -46,6 +46,20 @@ bool GDMonoAssembly::in_preload = false;
Vector<String> GDMonoAssembly::search_dirs;
+static String _get_expected_api_build_config() {
+#ifdef TOOLS_ENABLED
+ return "Debug";
+#else
+
+#ifdef DEBUG_ENABLED
+ return "Debug";
+#else
+ return "Release";
+#endif
+
+#endif
+}
+
void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config, const String &p_custom_bcl_dir) {
String framework_dir;
@@ -67,11 +81,19 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin
r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
}
+ String api_config = p_custom_config.empty() ? _get_expected_api_build_config() :
+ (p_custom_config == "Release" ? "Release" : "Debug");
+ r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_base_dir().plus_file(api_config));
+
r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
r_search_dirs.push_back(OS::get_singleton()->get_resource_dir());
r_search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
+
#ifdef TOOLS_ENABLED
r_search_dirs.push_back(GodotSharpDirs::get_data_editor_tools_dir());
+
+ // For GodotTools to find the api assemblies
+ r_search_dirs.push_back(GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"));
#endif
}
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 4342f46109..1c10d3c8eb 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -41,7 +41,7 @@ String GDMonoClass::get_full_name(MonoClass *p_mono_class) {
MonoException *exc = NULL;
MonoString *str = GDMonoUtils::object_to_string((MonoObject *)type_obj, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return GDMonoMarshal::mono_string_to_godot(str);
}
@@ -74,16 +74,13 @@ 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;
+}
- if (assembly) {
- MonoClass *parent_mono_class = mono_class_get_parent(mono_class);
-
- if (parent_mono_class) {
- return GDMono::get_singleton()->get_class(parent_mono_class);
- }
- }
-
- return NULL;
+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;
}
#ifdef TOOLS_ENABLED
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index 249422b844..40e1574927 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -121,6 +121,7 @@ public:
_FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
GDMonoClass *get_parent_class();
+ GDMonoClass *get_nesting_class();
#ifdef TOOLS_ENABLED
Vector<MonoClassField *> get_enum_fields();
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 2e79f87625..3999658f93 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -315,7 +315,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
// The order in which we check the following interfaces is very important (dictionaries and generics first)
- MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type());
+ MonoReflectionType *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)) {
@@ -340,9 +340,15 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
}
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
- mono_field_set_value(p_object, mono_field, managed);
- break;
+ if (GDMonoUtils::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_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
@@ -450,7 +456,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
} break;
case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type());
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class);
@@ -489,9 +495,15 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
}
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
- mono_field_set_value(p_object, mono_field, managed);
- break;
+ if (GDMonoUtils::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;
+ }
}
} break;
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
index cb28efb4e5..a84332d4cd 100644
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -74,15 +74,14 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
script_binding.type_name = NATIVE_GDMONOCLASS_NAME(klass);
script_binding.wrapper_class = klass;
script_binding.gchandle = MonoGCHandle::create_strong(managed);
+ script_binding.owner = unmanaged;
- Reference *kref = Object::cast_to<Reference>(unmanaged);
- if (kref) {
+ if (ref) {
// Unsafe refcount increment. The managed instance also counts as a reference.
// This way if the unmanaged world has no references to our owner
// but the managed instance is alive, the refcount will be 1 instead of 0.
// See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
-
- kref->reference();
+ ref->reference();
}
// The object was just created, no script instance binding should have been attached
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 87157ed233..42102ed835 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -159,7 +159,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
// The order in which we check the following interfaces is very important (dictionaries and generics first)
- MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type());
+ MonoReflectionType *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;
@@ -179,7 +179,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
} break;
case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
return Variant::DICTIONARY;
@@ -217,7 +217,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) {
switch (p_array_type.type_encoding) {
case MONO_TYPE_GENERICINST: {
- MonoReflectionType *array_reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_array_type.type_class->get_mono_type());
+ 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)) {
MonoReflectionType *elem_reftype;
@@ -244,7 +244,7 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_
bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, ManagedType &r_key_type, ManagedType &r_value_type) {
switch (p_dictionary_type.type_encoding) {
case MONO_TYPE_GENERICINST: {
- MonoReflectionType *dict_reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_dictionary_type.type_class->get_mono_type());
+ 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)) {
MonoReflectionType *key_reftype;
@@ -539,7 +539,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
// The order in which we check the following interfaces is very important (dictionaries and generics first)
- MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type());
+ MonoReflectionType *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)) {
@@ -558,7 +558,11 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
- return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+ if (GDMonoUtils::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: {
@@ -652,7 +656,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
break;
case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class);
@@ -681,7 +685,11 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
- return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+ if (GDMonoUtils::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;
} break;
@@ -831,20 +839,20 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
if (CACHED_CLASS(Array) == type_class) {
MonoException *exc = NULL;
Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
if (CACHED_CLASS(Dictionary) == type_class) {
MonoException *exc = NULL;
Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(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(SCRIPTS_DOMAIN, type_class->get_mono_type());
+ 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);
@@ -864,19 +872,19 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
} break;
case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type());
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type());
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
MonoException *exc = NULL;
MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return *unbox<Dictionary *>(ret);
}
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
MonoException *exc = NULL;
MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return *unbox<Array *>(ret);
}
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 1b32f1126e..5987fa8ebb 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -125,6 +125,7 @@ void MonoCache::clear_godot_api_cache() {
class_Array = NULL;
class_Dictionary = NULL;
class_MarshalUtils = NULL;
+ class_ISerializationListener = NULL;
#ifdef DEBUG_ENABLED
class_DebuggingUtils = NULL;
@@ -242,6 +243,7 @@ void update_godot_api_cache() {
CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array));
CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary));
CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
+ CACHE_CLASS_AND_CHECK(ISerializationListener, GODOT_API_CLASS(ISerializationListener));
#ifdef DEBUG_ENABLED
CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils));
@@ -302,7 +304,7 @@ void update_godot_api_cache() {
#endif
// TODO Move to CSharpLanguage::init() and do handle disposal
- MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
+ MonoObject *task_scheduler = mono_object_new(mono_domain_get(), GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler));
mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
@@ -371,7 +373,6 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
// This way if the unmanaged world has no references to our owner
// but the managed instance is alive, the refcount will be 1 instead of 0.
// See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
-
ref->reference();
}
@@ -384,7 +385,7 @@ void set_main_thread(MonoThread *p_thread) {
void attach_current_thread() {
ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
- MonoThread *mono_thread = mono_thread_attach(SCRIPTS_DOMAIN);
+ MonoThread *mono_thread = mono_thread_attach(mono_domain_get());
ERR_FAIL_NULL(mono_thread);
}
@@ -448,17 +449,12 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class) {
}
MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) {
- String object_type = p_object->get_class_name();
-
- if (object_type[0] == '_')
- object_type = object_type.substr(1, object_type.length());
-
- if (!ClassDB::is_parent_class(object_type, p_native)) {
+ if (!ClassDB::is_parent_class(p_object->get_class_name(), p_native)) {
ERR_EXPLAIN("Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'");
ERR_FAIL_V(NULL);
}
- MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
+ MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
ERR_FAIL_NULL_V(mono_object, NULL);
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
@@ -470,7 +466,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
}
MonoObject *create_managed_from(const NodePath &p_from) {
- MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(NodePath));
+ MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(NodePath));
ERR_FAIL_NULL_V(mono_object, NULL);
// Construct
@@ -482,7 +478,7 @@ MonoObject *create_managed_from(const NodePath &p_from) {
}
MonoObject *create_managed_from(const RID &p_from) {
- MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(RID));
+ MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(RID));
ERR_FAIL_NULL_V(mono_object, NULL);
// Construct
@@ -494,7 +490,7 @@ 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(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
+ MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
ERR_FAIL_NULL_V(mono_object, NULL);
// Search constructor that takes a pointer as parameter
@@ -518,13 +514,13 @@ MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) {
MonoException *exc = NULL;
GDMonoUtils::runtime_invoke(m, mono_object, args, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return mono_object;
}
MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) {
- MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
+ MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
ERR_FAIL_NULL_V(mono_object, NULL);
// Search constructor that takes a pointer as parameter
@@ -548,7 +544,7 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class)
MonoException *exc = NULL;
GDMonoUtils::runtime_invoke(m, mono_object, args, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return mono_object;
}
@@ -667,7 +663,10 @@ void print_unhandled_exception(MonoException *p_exc) {
}
void set_pending_exception(MonoException *p_exc) {
-#ifdef HAS_PENDING_EXCEPTIONS
+#ifdef NO_PENDING_EXCEPTIONS
+ debug_unhandled_exception(p_exc);
+ GD_UNREACHABLE();
+#else
if (get_runtime_invoke_count() == 0) {
debug_unhandled_exception(p_exc);
GD_UNREACHABLE();
@@ -677,9 +676,6 @@ void set_pending_exception(MonoException *p_exc) {
ERR_PRINTS("Exception thrown from managed code, but it could not be set as pending:");
GDMonoUtils::debug_print_unhandled_exception(p_exc);
}
-#else
- debug_unhandled_exception(p_exc);
- GD_UNREACHABLE();
#endif
}
@@ -755,113 +751,137 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
namespace Marshal {
-MonoBoolean type_is_generic_array(MonoReflectionType *p_reftype) {
+#ifdef MONO_GLUE_ENABLED
+#ifdef TOOLS_ENABLED
+#define NO_GLUE_RET(m_ret) \
+ { \
+ if (!mono_cache.godot_api_cache_updated) return m_ret; \
+ }
+#else
+#define NO_GLUE_RET(m_ret) \
+ {}
+#endif
+#else
+#define NO_GLUE_RET(m_ret) \
+ { return m_ret; }
+#endif
+
+bool type_is_generic_array(MonoReflectionType *p_reftype) {
+ NO_GLUE_RET(false);
TypeIsGenericArray thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
MonoException *exc = NULL;
MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return res;
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
}
-MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype) {
+bool type_is_generic_dictionary(MonoReflectionType *p_reftype) {
+ NO_GLUE_RET(false);
TypeIsGenericDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
MonoException *exc = NULL;
MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return res;
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
}
void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
ArrayGetElementType thunk = CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType);
MonoException *exc = NULL;
invoke_method_thunk(thunk, p_array_reftype, r_elem_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
}
void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
DictionaryGetKeyValueTypes thunk = CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes);
MonoException *exc = NULL;
invoke_method_thunk(thunk, p_dict_reftype, r_key_reftype, r_value_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
}
-MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) {
+bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) {
+ NO_GLUE_RET(false);
GenericIEnumerableIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType);
MonoException *exc = NULL;
MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return res;
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
}
-MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) {
+bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) {
+ NO_GLUE_RET(false);
GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType);
MonoException *exc = NULL;
MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return res;
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
}
-MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) {
+bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) {
+ NO_GLUE_RET(false);
GenericIEnumerableIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info);
MonoException *exc = NULL;
MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_elem_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return res;
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
}
-MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
+bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
+ NO_GLUE_RET(false);
GenericIDictionaryIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info);
MonoException *exc = NULL;
MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_key_reftype, r_value_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
- return res;
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
}
Array enumerable_to_array(MonoObject *p_enumerable) {
+ NO_GLUE_RET(Array());
Array result;
EnumerableToArray thunk = CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray);
MonoException *exc = NULL;
invoke_method_thunk(thunk, p_enumerable, &result, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return result;
}
Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) {
+ NO_GLUE_RET(Dictionary());
Dictionary result;
IDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary);
MonoException *exc = NULL;
invoke_method_thunk(thunk, p_idictionary, &result, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return result;
}
Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) {
+ NO_GLUE_RET(Dictionary());
Dictionary result;
GenericIDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary);
MonoException *exc = NULL;
invoke_method_thunk(thunk, p_generic_idictionary, &result, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return result;
}
GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) {
+ NO_GLUE_RET(NULL);
MakeGenericArrayType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType);
MonoException *exc = NULL;
MonoReflectionType *reftype = invoke_method_thunk(thunk, p_elem_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(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);
MakeGenericDictionaryType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType);
MonoException *exc = NULL;
MonoReflectionType *reftype = invoke_method_thunk(thunk, p_key_reftype, p_value_reftype, &exc);
- UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ UNHANDLED_EXCEPTION(exc);
return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
}
} // namespace Marshal
-// namespace Marshal
-
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 00e1ffdd31..f535fbb6d0 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/object.h"
#include "core/reference.h"
-#define UNLIKELY_UNHANDLED_EXCEPTION(m_exc) \
+#define UNHANDLED_EXCEPTION(m_exc) \
if (unlikely(m_exc != NULL)) { \
GDMonoUtils::debug_unhandled_exception(m_exc); \
GD_UNREACHABLE(); \
@@ -78,16 +78,16 @@ typedef void (*GenericIDictionaryToDictionary)(MonoObject *, Dictionary *, MonoE
namespace Marshal {
-MonoBoolean type_is_generic_array(MonoReflectionType *p_reftype);
-MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype);
+bool type_is_generic_array(MonoReflectionType *p_reftype);
+bool type_is_generic_dictionary(MonoReflectionType *p_reftype);
void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype);
void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);
-MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype);
-MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype);
-MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype);
-MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);
+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);
@@ -157,6 +157,7 @@ struct MonoCache {
GDMonoClass *class_Array;
GDMonoClass *class_Dictionary;
GDMonoClass *class_MarshalUtils;
+ GDMonoClass *class_ISerializationListener;
#ifdef DEBUG_ENABLED
GDMonoClass *class_DebuggingUtils;
@@ -235,10 +236,19 @@ void update_godot_api_cache();
inline void clear_corlib_cache() {
mono_cache.clear_corlib_cache();
}
+
inline void clear_godot_api_cache() {
mono_cache.clear_godot_api_cache();
}
+_FORCE_INLINE_ bool tools_godot_api_check() {
+#ifdef TOOLS_ENABLED
+ return mono_cache.godot_api_cache_updated;
+#else
+ return true; // Assume it's updated if this was called, otherwise it's a bug
+#endif
+}
+
_FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2);
}