summaryrefslogtreecommitdiff
path: root/modules/mono/mono_gd/gd_mono.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/mono_gd/gd_mono.cpp')
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp151
1 files changed, 97 insertions, 54 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 39c3bd8934..cf5ac33d20 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -144,8 +144,9 @@ void gd_mono_debug_init() {
if (Engine::get_singleton()->is_editor_hint() ||
ProjectSettings::get_singleton()->get_resource_path().empty() ||
Main::is_project_manager()) {
- if (da_args.size() == 0)
+ if (da_args.size() == 0) {
return;
+ }
}
if (da_args.length() == 0) {
@@ -423,24 +424,27 @@ void GDMono::initialize_load_assemblies() {
bool tool_assemblies_loaded = _load_tools_assemblies();
CRASH_COND_MSG(!tool_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies.");
- if (Main::is_project_manager())
+ if (Main::is_project_manager()) {
return;
+ }
#endif
// Load the project's main assembly. This doesn't necessarily need to succeed.
// The game may not be using .NET at all, or if the project does use .NET and
// we're running in the editor, it may just happen to be it wasn't built yet.
if (!_load_project_assembly()) {
- if (OS::get_singleton()->is_stdout_verbose())
+ if (OS::get_singleton()->is_stdout_verbose()) {
print_error("Mono: Failed to load project assembly");
+ }
}
}
bool GDMono::_are_api_assemblies_out_of_sync() {
bool out_of_sync = core_api_assembly.assembly && (core_api_assembly.out_of_sync || !GDMonoCache::cached_data.godot_api_cache_updated);
#ifdef TOOLS_ENABLED
- if (!out_of_sync)
+ if (!out_of_sync) {
out_of_sync = editor_api_assembly.assembly && editor_api_assembly.out_of_sync;
+ }
#endif
return out_of_sync;
}
@@ -512,16 +516,17 @@ void GDMono::_init_exception_policy() {
}
}
-void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) {
+void GDMono::add_assembly(int32_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) {
- if (p_name == "mscorlib" && corlib_assembly)
+ if (p_name == "mscorlib" && corlib_assembly) {
return corlib_assembly;
+ }
MonoDomain *domain = mono_domain_get();
- uint32_t domain_id = domain ? mono_domain_get_id(domain) : 0;
+ int32_t domain_id = domain ? mono_domain_get_id(domain) : 0;
GDMonoAssembly **result = assemblies[domain_id].getptr(p_name);
return result ? *result : nullptr;
}
@@ -556,8 +561,9 @@ bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMo
GDMonoAssembly *assembly = GDMonoAssembly::load(p_name, p_aname, p_refonly, p_search_dirs);
- if (!assembly)
+ if (!assembly) {
return false;
+ }
*r_assembly = assembly;
@@ -573,8 +579,9 @@ bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMo
GDMonoAssembly *assembly = GDMonoAssembly::load_from(p_name, p_path, p_refonly);
- if (!assembly)
+ if (!assembly) {
return false;
+ }
*r_assembly = assembly;
@@ -594,16 +601,19 @@ 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)
+ if (api_hash_field) {
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)
+ if (binds_ver_field) {
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)
+ if (cs_glue_ver_field) {
api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(nullptr));
+ }
}
return api_assembly_version;
@@ -614,13 +624,15 @@ String ApiAssemblyInfo::to_string(ApiAssemblyInfo::Type p_type) {
}
bool GDMono::_load_corlib_assembly() {
- if (corlib_assembly)
+ if (corlib_assembly) {
return true;
+ }
bool success = load_assembly("mscorlib", &corlib_assembly);
- if (success)
+ if (success) {
GDMonoCache::update_corlib_cache();
+ }
return success;
}
@@ -647,12 +659,14 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
String xml_file = assembly_name + ".xml";
- if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK)
+ if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) {
WARN_PRINT("Failed to copy '" + xml_file + "'.");
+ }
String pdb_file = assembly_name + ".pdb";
- if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK)
+ if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK) {
WARN_PRINT("Failed to copy '" + pdb_file + "'.");
+ }
String assembly_file = assembly_name + ".dll";
if (da->copy(src_dir.plus_file(assembly_file), dst_dir.plus_file(assembly_file)) != OK) {
@@ -667,13 +681,15 @@ static bool try_get_cached_api_hash_for(const String &p_api_assemblies_dir, bool
String core_api_assembly_path = p_api_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
String editor_api_assembly_path = p_api_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
- if (!FileAccess::exists(core_api_assembly_path) || !FileAccess::exists(editor_api_assembly_path))
+ if (!FileAccess::exists(core_api_assembly_path) || !FileAccess::exists(editor_api_assembly_path)) {
return false;
+ }
String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg");
- if (!FileAccess::exists(cached_api_hash_path))
+ if (!FileAccess::exists(cached_api_hash_path)) {
return false;
+ }
Ref<ConfigFile> cfg;
cfg.instance();
@@ -766,8 +782,9 @@ String GDMono::update_api_assemblies_from_prebuilt(const String &p_config, const
// Note: Even if only one of the assemblies if missing or out of sync, we update both
- if (!api_assemblies_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path))
+ if (!api_assemblies_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) {
return String(); // No update needed
+ }
print_verbose("Updating '" + p_config + "' API assemblies");
@@ -795,8 +812,9 @@ String GDMono::update_api_assemblies_from_prebuilt(const String &p_config, const
#endif
bool GDMono::_load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
- if (r_loaded_api_assembly.assembly)
+ if (r_loaded_api_assembly.assembly) {
return true;
+ }
#ifdef TOOLS_ENABLED
// For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date
@@ -828,8 +846,9 @@ bool GDMono::_load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, c
#ifdef TOOLS_ENABLED
bool GDMono::_load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
- if (r_loaded_api_assembly.assembly)
+ if (r_loaded_api_assembly.assembly) {
return true;
+ }
// For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date
@@ -859,30 +878,35 @@ bool GDMono::_load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly,
bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly,
const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback) {
if (!_load_core_api_assembly(r_core_api_assembly, p_config, p_refonly)) {
- if (OS::get_singleton()->is_stdout_verbose())
+ if (OS::get_singleton()->is_stdout_verbose()) {
print_error("Mono: Failed to load Core API assembly");
+ }
return false;
}
#ifdef TOOLS_ENABLED
if (!_load_editor_api_assembly(r_editor_api_assembly, p_config, p_refonly)) {
- if (OS::get_singleton()->is_stdout_verbose())
+ if (OS::get_singleton()->is_stdout_verbose()) {
print_error("Mono: Failed to load Editor API assembly");
+ }
return false;
}
- if (r_editor_api_assembly.out_of_sync)
+ if (r_editor_api_assembly.out_of_sync) {
return false;
+ }
#endif
// Check if the core API assembly is out of sync only after trying to load the
// editor API assembly. Otherwise, if both assemblies are out of sync, we would
// only update the former as we won't know the latter also needs to be updated.
- if (r_core_api_assembly.out_of_sync)
+ if (r_core_api_assembly.out_of_sync) {
return false;
+ }
- if (p_callback)
+ if (p_callback) {
return p_callback();
+ }
return true;
}
@@ -890,8 +914,9 @@ bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, Lo
bool GDMono::_on_core_api_assembly_loaded() {
GDMonoCache::update_godot_api_cache();
- if (!GDMonoCache::cached_data.godot_api_cache_updated)
+ if (!GDMonoCache::cached_data.godot_api_cache_updated) {
return false;
+ }
get_singleton()->_install_trace_listener();
@@ -956,8 +981,9 @@ void GDMono::_load_api_assemblies() {
#ifdef TOOLS_ENABLED
bool GDMono::_load_tools_assemblies() {
- if (tools_assembly && tools_project_editor_assembly)
+ if (tools_assembly && tools_project_editor_assembly) {
return true;
+ }
bool success = load_assembly(TOOLS_ASM_NAME, &tools_assembly) &&
load_assembly(TOOLS_PROJECT_EDITOR_ASM_NAME, &tools_project_editor_assembly);
@@ -967,8 +993,9 @@ bool GDMono::_load_tools_assemblies() {
#endif
bool GDMono::_load_project_assembly() {
- if (project_assembly)
+ if (project_assembly) {
return true;
+ }
String appname = ProjectSettings::get_singleton()->get("application/config/name");
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
@@ -1020,8 +1047,9 @@ Error GDMono::_unload_scripts_domain() {
print_verbose("Mono: Finalizing scripts domain...");
- if (mono_domain_get() != root_domain)
+ if (mono_domain_get() != root_domain) {
mono_domain_set(root_domain, true);
+ }
finalizing_scripts_domain = true;
@@ -1111,8 +1139,9 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
print_verbose("Mono: Unloading domain '" + domain_name + "'...");
- if (mono_domain_get() == p_domain)
+ if (mono_domain_get() == p_domain) {
mono_domain_set(root_domain, true);
+ }
if (!mono_domain_finalize(p_domain, 2000)) {
ERR_PRINT("Mono: Domain finalization timeout.");
@@ -1138,10 +1167,11 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
MonoImage *image = mono_class_get_image(p_raw_class);
- if (image == corlib_assembly->get_image())
+ if (image == corlib_assembly->get_image()) {
return corlib_assembly->get_class(p_raw_class);
+ }
- uint32_t domain_id = mono_domain_get_id(mono_domain_get());
+ int32_t domain_id = mono_domain_get_id(mono_domain_get());
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
const String *k = nullptr;
@@ -1149,9 +1179,9 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
GDMonoAssembly *assembly = domain_assemblies.get(*k);
if (assembly->get_image() == image) {
GDMonoClass *klass = assembly->get_class(p_raw_class);
-
- if (klass)
+ if (klass) {
return klass;
+ }
}
}
@@ -1160,24 +1190,26 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &p_name) {
GDMonoClass *klass = corlib_assembly->get_class(p_namespace, p_name);
- if (klass)
+ if (klass) {
return klass;
+ }
- uint32_t domain_id = mono_domain_get_id(mono_domain_get());
+ int32_t domain_id = mono_domain_get_id(mono_domain_get());
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
const String *k = nullptr;
while ((k = domain_assemblies.next(k))) {
GDMonoAssembly *assembly = domain_assemblies.get(*k);
klass = assembly->get_class(p_namespace, p_name);
- if (klass)
+ if (klass) {
return klass;
+ }
}
return nullptr;
}
-void GDMono::_domain_assemblies_cleanup(uint32_t p_domain_id) {
+void GDMono::_domain_assemblies_cleanup(int32_t p_domain_id) {
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
const String *k = nullptr;
@@ -1195,8 +1227,9 @@ void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) {
#ifdef DEBUG_ENABLED
GDMonoUtils::debug_send_unhandled_exception_error((MonoException *)p_exc);
- if (EngineDebugger::is_active())
+ if (EngineDebugger::is_active()) {
EngineDebugger::get_singleton()->poll_events(false);
+ }
#endif
exit(mono_environment_exitcode_get());
@@ -1271,7 +1304,7 @@ GDMono::~GDMono() {
// Leave the rest to 'mono_jit_cleanup'
#endif
- const uint32_t *k = nullptr;
+ const int32_t *k = nullptr;
while ((k = assemblies.next(k))) {
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies.get(*k);
@@ -1295,8 +1328,9 @@ GDMono::~GDMono() {
gdmono::android::support::cleanup();
#endif
- if (gdmono_log)
+ if (gdmono_log) {
memdelete(gdmono_log);
+ }
singleton = nullptr;
}
@@ -1313,37 +1347,44 @@ void _GodotSharp::detach_thread() {
int32_t _GodotSharp::get_domain_id() {
MonoDomain *domain = mono_domain_get();
- CRASH_COND(!domain); // User must check if runtime is initialized before calling this method
+ ERR_FAIL_NULL_V(domain, -1);
return mono_domain_get_id(domain);
}
int32_t _GodotSharp::get_scripts_domain_id() {
+ ERR_FAIL_NULL_V_MSG(GDMono::get_singleton(),
+ -1, "The Mono runtime is not initialized");
MonoDomain *domain = GDMono::get_singleton()->get_scripts_domain();
- CRASH_COND(!domain); // User must check if scripts domain is loaded before calling this method
+ ERR_FAIL_NULL_V(domain, -1);
return mono_domain_get_id(domain);
}
bool _GodotSharp::is_scripts_domain_loaded() {
- return GDMono::get_singleton()->is_runtime_initialized() && GDMono::get_singleton()->get_scripts_domain() != nullptr;
+ return GDMono::get_singleton() != nullptr &&
+ 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) {
return is_domain_finalizing_for_unload(p_domain_id);
}
-bool _GodotSharp::is_domain_finalizing_for_unload() {
- return is_domain_finalizing_for_unload(mono_domain_get());
-}
-
bool _GodotSharp::is_domain_finalizing_for_unload(int32_t p_domain_id) {
return is_domain_finalizing_for_unload(mono_domain_get_by_id(p_domain_id));
}
bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
- if (!p_domain)
- return true;
- if (p_domain == GDMono::get_singleton()->get_scripts_domain() && GDMono::get_singleton()->is_finalizing_scripts_domain())
+ GDMono *gd_mono = GDMono::get_singleton();
+
+ ERR_FAIL_COND_V_MSG(!gd_mono || !gd_mono->is_runtime_initialized(),
+ false, "The Mono runtime is not initialized");
+
+ ERR_FAIL_NULL_V(p_domain, true);
+
+ if (p_domain == gd_mono->get_scripts_domain() && gd_mono->is_finalizing_scripts_domain()) {
return true;
+ }
+
return mono_domain_is_unloading(p_domain);
}
@@ -1352,15 +1393,17 @@ bool _GodotSharp::is_runtime_shutting_down() {
}
bool _GodotSharp::is_runtime_initialized() {
- return GDMono::get_singleton()->is_runtime_initialized();
+ return GDMono::get_singleton() != nullptr && GDMono::get_singleton()->is_runtime_initialized();
}
void _GodotSharp::_reload_assemblies(bool p_soft_reload) {
#ifdef GD_MONO_HOT_RELOAD
+ CRASH_COND(CSharpLanguage::get_singleton() == nullptr);
// 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())
+ if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) {
CSharpLanguage::get_singleton()->reload_assemblies(p_soft_reload);
+ }
#endif
}