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.cpp68
-rw-r--r--modules/mono/mono_gd/gd_mono.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp92
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h17
4 files changed, 134 insertions, 49 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 39474f8cbc..519c30045a 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -271,33 +271,44 @@ GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) {
return assemblies[domain_id].getptr(p_name);
}
-bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) {
+bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) {
+
+ CRASH_COND(!r_assembly);
+
+ MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
+ bool result = load_assembly(p_name, aname, r_assembly, p_refonly);
+ mono_assembly_name_free(aname);
+ mono_free(aname);
+
+ return result;
+}
+
+bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
CRASH_COND(!r_assembly);
if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + "...\n").utf8());
+ OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...\n").utf8());
MonoImageOpenStatus status = MONO_IMAGE_OK;
- MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
- MonoAssembly *assembly = mono_assembly_load_full(aname, NULL, &status, false);
- mono_assembly_name_free(aname);
+ MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly);
if (!assembly)
return false;
+ ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);
+
uint32_t domain_id = mono_domain_get_id(mono_domain_get());
GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name);
- ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);
ERR_FAIL_COND_V(stored_assembly == NULL, false);
-
ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false);
+
*r_assembly = *stored_assembly;
if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print(String("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8());
+ OS::get_singleton()->print(String("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8());
return true;
}
@@ -307,7 +318,7 @@ bool GDMono::_load_corlib_assembly() {
if (corlib_assembly)
return true;
- bool success = _load_assembly("mscorlib", &corlib_assembly);
+ bool success = load_assembly("mscorlib", &corlib_assembly);
if (success)
GDMonoUtils::update_corlib_cache();
@@ -320,7 +331,7 @@ bool GDMono::_load_core_api_assembly() {
if (api_assembly)
return true;
- bool success = _load_assembly(API_ASSEMBLY_NAME, &api_assembly);
+ bool success = load_assembly(API_ASSEMBLY_NAME, &api_assembly);
if (success)
GDMonoUtils::update_godot_api_cache();
@@ -334,7 +345,7 @@ bool GDMono::_load_editor_api_assembly() {
if (editor_api_assembly)
return true;
- return _load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
+ return load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
}
#endif
@@ -346,7 +357,7 @@ bool GDMono::_load_editor_tools_assembly() {
_GDMONO_SCOPE_DOMAIN_(tools_domain)
- return _load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly);
+ return load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly);
}
#endif
@@ -360,7 +371,7 @@ bool GDMono::_load_project_assembly() {
name = "UnnamedProject";
}
- bool success = _load_assembly(name, &project_assembly);
+ bool success = load_assembly(name, &project_assembly);
if (success)
mono_assembly_set_main(project_assembly->get_assembly());
@@ -511,6 +522,37 @@ Error GDMono::reload_scripts_domain() {
}
#endif
+Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
+
+ CRASH_COND(p_domain == NULL);
+
+ String domain_name = mono_domain_get_friendly_name(p_domain);
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print(String("Mono: Unloading domain `" + domain_name + "`...\n").utf8());
+ }
+
+ if (mono_domain_get() != root_domain)
+ mono_domain_set(root_domain, true);
+
+ mono_gc_collect(mono_gc_max_generation());
+ mono_domain_finalize(p_domain, 2000);
+ mono_gc_collect(mono_gc_max_generation());
+
+ _domain_assemblies_cleanup(mono_domain_get_id(p_domain));
+
+ MonoObject *ex = NULL;
+ mono_domain_try_unload(p_domain, &ex);
+
+ if (ex) {
+ ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`:");
+ mono_print_unhandled_exception(ex);
+ return FAILED;
+ }
+
+ return OK;
+}
+
GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
MonoImage *image = mono_class_get_image(p_raw_class);
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 67251778c6..07f649c442 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -94,8 +94,6 @@ class GDMono {
void _initialize_and_check_api_hashes();
#endif
- bool _load_assembly(const String &p_name, GDMonoAssembly **r_assembly);
-
GDMonoLog *gdmono_log;
#ifdef WINDOWS_ENABLED
@@ -145,6 +143,10 @@ public:
Error reload_scripts_domain();
#endif
+ bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly = false);
+ bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false);
+ Error finalize_and_unload_domain(MonoDomain *p_domain);
+
void initialize();
GDMono();
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index ef39b8549d..e0743346aa 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -43,7 +43,23 @@
bool GDMonoAssembly::no_search = false;
Vector<String> GDMonoAssembly::search_dirs;
-MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data) {
+MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) {
+ return GDMonoAssembly::_search_hook(aname, user_data, false);
+}
+
+MonoAssembly *GDMonoAssembly::assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data) {
+ return GDMonoAssembly::_search_hook(aname, user_data, true);
+}
+
+MonoAssembly *GDMonoAssembly::assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
+ return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, false);
+}
+
+MonoAssembly *GDMonoAssembly::assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
+ return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, true);
+}
+
+MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly) {
(void)user_data; // UNUSED
@@ -60,7 +76,7 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
no_search = true; // Avoid the recursion madness
String path;
- MonoAssembly *res = NULL;
+ GDMonoAssembly *res = NULL;
for (int i = 0; i < search_dirs.size(); i++) {
const String &search_dir = search_dirs[i];
@@ -68,19 +84,19 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
if (has_extension) {
path = search_dir.plus_file(name);
if (FileAccess::exists(path)) {
- res = _load_assembly_from(name.get_basename(), path);
+ res = _load_assembly_from(name.get_basename(), path, refonly);
break;
}
} else {
path = search_dir.plus_file(name + ".dll");
if (FileAccess::exists(path)) {
- res = _load_assembly_from(name, path);
+ res = _load_assembly_from(name, path, refonly);
break;
}
path = search_dir.plus_file(name + ".exe");
if (FileAccess::exists(path)) {
- res = _load_assembly_from(name, path);
+ res = _load_assembly_from(name, path, refonly);
break;
}
}
@@ -88,17 +104,15 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
no_search = false;
- return res;
+ return res ? res->get_assembly() : NULL;
}
-MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
+MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly) {
(void)user_data; // UNUSED
if (search_dirs.empty()) {
-#ifdef TOOLS_DOMAIN
search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
-#endif
search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
search_dirs.push_back(OS::get_singleton()->get_resource_dir());
search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
@@ -121,10 +135,11 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse
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();
+ if (stored_assembly)
+ return (*stored_assembly)->get_assembly();
String path;
- MonoAssembly *res = NULL;
+ GDMonoAssembly *res = NULL;
for (int i = 0; i < search_dirs.size(); i++) {
const String &search_dir = search_dirs[i];
@@ -132,53 +147,61 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse
if (has_extension) {
path = search_dir.plus_file(name);
if (FileAccess::exists(path)) {
- res = _load_assembly_from(name.get_basename(), path);
+ res = _load_assembly_from(name.get_basename(), path, refonly);
break;
}
} else {
path = search_dir.plus_file(name + ".dll");
if (FileAccess::exists(path)) {
- res = _load_assembly_from(name, path);
+ res = _load_assembly_from(name, path, refonly);
+ break;
+ }
+
+ path = search_dir.plus_file(name + ".exe");
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name, path, refonly);
break;
}
}
}
- if (res) return res;
+ return res ? res->get_assembly() : NULL;
}
return NULL;
}
-MonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path) {
+GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) {
GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path));
- MonoDomain *domain = mono_domain_get();
-
- Error err = assembly->load(domain);
+ 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->get_assembly();
+ return assembly;
}
void GDMonoAssembly::initialize() {
- // TODO refonly as well?
- mono_install_assembly_preload_hook(&GDMonoAssembly::_preload_hook, NULL);
- mono_install_assembly_search_hook(&GDMonoAssembly::_search_hook, NULL);
+ 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);
}
-Error GDMonoAssembly::load(MonoDomain *p_domain) {
+Error GDMonoAssembly::load(bool p_refonly) {
ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE);
+ refonly = p_refonly;
+
uint64_t last_modified_time = FileAccess::get_modified_time(path);
Vector<uint8_t> data = FileAccess::get_file_as_array(path);
@@ -190,7 +213,7 @@ Error GDMonoAssembly::load(MonoDomain *p_domain) {
image = mono_image_open_from_data_with_name(
(char *)&data[0], data.size(),
- true, &status, false,
+ true, &status, refonly,
image_filename.utf8().get_data());
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || image == NULL, ERR_FILE_CANT_OPEN);
@@ -213,15 +236,10 @@ no_pdb:
#endif
- assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, false);
+ assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, refonly);
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
- if (p_domain && mono_image_get_entry_point(image)) {
- // TODO should this be removed? do we want to call main? what other effects does this have?
- mono_jit_exec(p_domain, assembly, 0, NULL);
- }
-
loaded = true;
modified_time = last_modified_time;
@@ -373,12 +391,26 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class)
return match;
}
+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;
+
+ no_search = true;
+ GDMonoAssembly *res = _load_assembly_from(p_name, p_path, p_refonly);
+ no_search = false;
+
+ return res;
+}
+
GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) {
loaded = false;
gdobject_class_cache_updated = false;
name = p_name;
path = p_path;
+ refonly = false;
modified_time = 0;
assembly = NULL;
image = NULL;
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 8a5fa19626..5cf744a5a2 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -71,6 +71,7 @@ class GDMonoAssembly {
MonoAssembly *assembly;
MonoImage *image;
+ bool refonly;
bool loaded;
String name;
@@ -90,19 +91,25 @@ class GDMonoAssembly {
static bool no_search;
static Vector<String> search_dirs;
- static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data);
- static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
+ static MonoAssembly *assembly_search_hook(MonoAssemblyName *aname, void *user_data);
+ static MonoAssembly *assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data);
+ static MonoAssembly *assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
+ static MonoAssembly *assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
- static MonoAssembly *_load_assembly_from(const String &p_name, const String &p_path);
+ 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);
friend class GDMono;
static void initialize();
public:
- Error load(MonoDomain *p_domain);
+ 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; }
@@ -115,6 +122,8 @@ public:
GDMonoClass *get_object_derived_class(const StringName &p_class);
+ 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();
};