123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- #include "gd_mono_assembly.h"
- #include <mono/metadata/mono-debug.h>
- #include <mono/metadata/tokentype.h>
- #include "core/list.h"
- #include "core/os/file_access.h"
- #include "core/os/os.h"
- #include "core/project_settings.h"
- #include "../godotsharp_dirs.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 char *rootdir = mono_assembly_getrootdir();
- if (rootdir) {
- String framework_dir = String(rootdir).plus_file("mono").plus_file("4.5");
- r_search_dirs.push_back(framework_dir);
- r_search_dirs.push_back(framework_dir.plus_file("Facades"));
- }
- if (p_custom_config.length()) {
- r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(p_custom_config));
- } else {
- r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
- }
- 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());
- #endif
- }
- void GDMonoAssembly::assembly_load_hook(MonoAssembly *assembly, void *user_data) {
- if (no_search)
- return;
-
-
-
-
-
-
-
- _wrap_mono_assembly(assembly);
- }
- 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;
- String name = 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);
- if (loaded_asm)
- return (*loaded_asm)->get_assembly();
- no_search = true;
- GDMonoAssembly *res = _load_assembly_search(name, search_dirs, refonly);
- no_search = false;
- return res ? res->get_assembly() : NULL;
- }
- static _THREAD_LOCAL_(MonoImage *) image_corlib_loading = NULL;
- MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, void *user_data, bool refonly) {
- (void)user_data;
- if (search_dirs.empty()) {
- fill_search_dirs(search_dirs);
- }
- {
-
-
-
-
-
-
-
-
-
-
- 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 = 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;
- }
- GDMonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly) {
- GDMonoAssembly *res = NULL;
- String path;
- bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe");
- for (int i = 0; i < p_search_dirs.size(); i++) {
- const String &search_dir = p_search_dirs[i];
- 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)
- 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)
- 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)
- return res;
- }
- }
- }
- return NULL;
- }
- 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 = 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() {
- 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);
- }
- 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);
- ERR_FAIL_COND_V(data.empty(), ERR_FILE_CANT_READ);
- String image_filename = ProjectSettings::get_singleton()->globalize_path(path);
- MonoImageOpenStatus status = MONO_IMAGE_OK;
- image = mono_image_open_from_data_with_name(
- (char *)&data[0], data.size(),
- true, &status, refonly,
- image_filename.utf8().get_data());
- ERR_FAIL_COND_V(status != MONO_IMAGE_OK, ERR_FILE_CANT_OPEN);
- ERR_FAIL_NULL_V(image, ERR_FILE_CANT_OPEN);
- #ifdef DEBUG_ENABLED
- String pdb_path(path + ".pdb");
- if (!FileAccess::exists(pdb_path)) {
- pdb_path = path.get_basename() + ".pdb";
- if (!FileAccess::exists(pdb_path))
- goto no_pdb;
- }
- pdb_data.clear();
- pdb_data = FileAccess::get_file_as_array(pdb_path);
- mono_debug_open_image_from_memory(image, &pdb_data[0], pdb_data.size());
- no_pdb:
- #endif
- bool is_corlib_preload = in_preload && name == "mscorlib";
- if (is_corlib_preload)
- image_corlib_loading = image;
- assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, refonly);
- if (is_corlib_preload)
- image_corlib_loading = NULL;
- ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
- 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;
- mono_image_addref(image);
- loaded = true;
- return OK;
- }
- void GDMonoAssembly::unload() {
- ERR_FAIL_COND(!loaded);
- #ifdef DEBUG_ENABLED
- if (pdb_data.size()) {
- mono_debug_close_image(image);
- pdb_data.clear();
- }
- #endif
- for (Map<MonoClass *, GDMonoClass *>::Element *E = cached_raw.front(); E; E = E->next()) {
- memdelete(E->value());
- }
- cached_classes.clear();
- cached_raw.clear();
- mono_image_close(image);
- assembly = NULL;
- image = NULL;
- loaded = false;
- }
- GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const StringName &p_name) {
- ERR_FAIL_COND_V(!loaded, NULL);
- ClassKey key(p_namespace, p_name);
- GDMonoClass **match = cached_classes.getptr(key);
- if (match)
- return *match;
- MonoClass *mono_class = mono_class_from_name(image, String(p_namespace).utf8(), String(p_name).utf8());
- if (!mono_class)
- return NULL;
- GDMonoClass *wrapped_class = memnew(GDMonoClass(p_namespace, p_name, mono_class, this));
- cached_classes[key] = wrapped_class;
- cached_raw[mono_class] = wrapped_class;
- return wrapped_class;
- }
- GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
- ERR_FAIL_COND_V(!loaded, NULL);
- Map<MonoClass *, GDMonoClass *>::Element *match = cached_raw.find(p_mono_class);
- if (match)
- return match->value();
- StringName namespace_name = mono_class_get_namespace(p_mono_class);
- StringName class_name = mono_class_get_name(p_mono_class);
- GDMonoClass *wrapped_class = memnew(GDMonoClass(namespace_name, class_name, p_mono_class, this));
- cached_classes[ClassKey(namespace_name, class_name)] = wrapped_class;
- cached_raw[p_mono_class] = wrapped_class;
- return wrapped_class;
- }
- GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) {
- GDMonoClass *match = NULL;
- if (gdobject_class_cache_updated) {
- Map<StringName, GDMonoClass *>::Element *result = gdobject_class_cache.find(p_class);
- if (result)
- match = result->get();
- } else {
- List<GDMonoClass *> nested_classes;
- int rows = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF);
- for (int i = 1; i < rows; i++) {
- MonoClass *mono_class = mono_class_get(image, (i + 1) | MONO_TOKEN_TYPE_DEF);
- if (!mono_class_is_assignable_from(CACHED_CLASS_RAW(GodotObject), mono_class))
- continue;
- GDMonoClass *current = get_class(mono_class);
- if (!current)
- continue;
- nested_classes.push_back(current);
- if (!match && current->get_name() == p_class)
- match = current;
- while (!nested_classes.empty()) {
- GDMonoClass *current_nested = nested_classes.front()->get();
- nested_classes.pop_back();
- void *iter = NULL;
- while (true) {
- MonoClass *raw_nested = mono_class_get_nested_types(current_nested->get_mono_ptr(), &iter);
- if (!raw_nested)
- break;
- GDMonoClass *nested_class = get_class(raw_nested);
- if (nested_class) {
- gdobject_class_cache.insert(nested_class->get_name(), nested_class);
- nested_classes.push_back(nested_class);
- }
- }
- }
- gdobject_class_cache.insert(current->get_name(), current);
- }
- gdobject_class_cache_updated = true;
- }
- 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;
- #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;
- }
- 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;
- }
- GDMonoAssembly::~GDMonoAssembly() {
- if (loaded)
- unload();
- }
|