diff options
author | RĂ©mi Verschelde <remi@verschelde.fr> | 2022-08-22 10:07:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-22 10:07:21 +0200 |
commit | 8a1e5980116355024cd7a7ce0c15db7d4ecb200a (patch) | |
tree | fc40366fb5ad00f6b01e0b796ef85495433bd26f /modules/mono/mono_gd | |
parent | 847183093d2948601cdd82f50a333bdee2d6eef0 (diff) | |
parent | 9c34a02191bc6c560cc2a1bceea943f9bd8aebfa (diff) |
Merge pull request #64089 from neikeq/dotnet6
Diffstat (limited to 'modules/mono/mono_gd')
30 files changed, 536 insertions, 9139 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index d3d3bb2bef..f746d63ce5 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -30,13 +30,6 @@ #include "gd_mono.h" -#include <mono/metadata/environment.h> -#include <mono/metadata/exception.h> -#include <mono/metadata/mono-config.h> -#include <mono/metadata/mono-debug.h> -#include <mono/metadata/mono-gc.h> -#include <mono/metadata/profiler.h> - #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/io/dir_access.h" @@ -45,1077 +38,515 @@ #include "core/os/thread.h" #include "../csharp_script.h" +#include "../glue/runtime_interop.h" #include "../godotsharp_dirs.h" #include "../utils/path_utils.h" #include "gd_mono_cache.h" -#include "gd_mono_class.h" -#include "gd_mono_marshal.h" -#include "gd_mono_utils.h" +#ifdef TOOLS_ENABLED +#include <nethost.h> +#endif + +#include <coreclr_delegates.h> +#include <hostfxr.h> +#ifdef UNIX_ENABLED +#include <dlfcn.h> +#endif + +// TODO mobile +#if 0 #ifdef ANDROID_ENABLED -#include "android_mono_config.h" #include "support/android_support.h" #elif defined(IOS_ENABLED) #include "support/ios_support.h" #endif - -#if defined(TOOL_ENABLED) && defined(GD_MONO_SINGLE_APPDOMAIN) -// This will no longer be the case if we replace appdomains with AssemblyLoadContext -#error "Editor build requires support for multiple appdomains" -#endif - -#if defined(GD_MONO_HOT_RELOAD) && defined(GD_MONO_SINGLE_APPDOMAIN) -#error "Hot reloading requires multiple appdomains" #endif -// TODO: -// This has turned into a gigantic mess. There's too much going on here. Too much #ifdef as well. -// It's just painful to read... It needs to be re-structured. Please, clean this up, future me. - GDMono *GDMono::singleton = nullptr; namespace { - -#if defined(JAVASCRIPT_ENABLED) -extern "C" { -void mono_wasm_load_runtime(const char *managed_path, int enable_debugging); -} -#endif - -#if !defined(JAVASCRIPT_ENABLED) - -void gd_mono_setup_runtime_main_args() { - CharString execpath = OS::get_singleton()->get_executable_path().utf8(); - - List<String> cmdline_args = OS::get_singleton()->get_cmdline_args(); - - List<CharString> cmdline_args_utf8; - Vector<char *> main_args; - main_args.resize(cmdline_args.size() + 1); - - main_args.write[0] = execpath.ptrw(); - - int i = 1; - for (const String &E : cmdline_args) { - CharString &stored = cmdline_args_utf8.push_back(E.utf8())->get(); - main_args.write[i] = stored.ptrw(); - i++; - } - - mono_runtime_set_main_args(main_args.size(), main_args.ptrw()); -} - -void gd_mono_profiler_init() { - String profiler_args = GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd"); - bool profiler_enabled = GLOBAL_DEF("mono/profiler/enabled", false); - if (profiler_enabled) { - mono_profiler_load(profiler_args.utf8()); - return; - } - - const String env_var_name = "MONO_ENV_OPTIONS"; - if (OS::get_singleton()->has_environment(env_var_name)) { - const String mono_env_ops = OS::get_singleton()->get_environment(env_var_name); - // Usually MONO_ENV_OPTIONS looks like: --profile=jb:prof=timeline,ctl=remote,host=127.0.0.1:55467 - const String prefix = "--profile="; - if (mono_env_ops.begins_with(prefix)) { - const String ops = mono_env_ops.substr(prefix.length(), mono_env_ops.length()); - mono_profiler_load(ops.utf8()); - } - } -} - -void gd_mono_debug_init() { - CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8(); - - if (da_args.length()) { - OS::get_singleton()->set_environment("GODOT_MONO_DEBUGGER_AGENT", String()); - } - -#ifdef TOOLS_ENABLED - int da_port = GLOBAL_DEF("mono/debugger_agent/port", 23685); - bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false); - int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000); - - if (Engine::get_singleton()->is_editor_hint() || - ProjectSettings::get_singleton()->get_resource_path().is_empty() || - Engine::get_singleton()->is_project_manager_hint()) { - if (da_args.size() == 0) { - return; - } - } - - 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")) - .utf8(); - } +hostfxr_initialize_for_dotnet_command_line_fn hostfxr_initialize_for_dotnet_command_line = nullptr; +hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config = nullptr; +hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate = nullptr; +hostfxr_close_fn hostfxr_close = nullptr; + +#ifdef _WIN32 +static_assert(sizeof(char_t) == sizeof(char16_t)); +using HostFxrCharString = Char16String; +#define HOSTFXR_STR(m_str) L##m_str #else - if (da_args.length() == 0) { - return; // Exported games don't use the project settings to setup the debugger agent - } +static_assert(sizeof(char_t) == sizeof(char)); +using HostFxrCharString = CharString; +#define HOSTFXR_STR(m_str) m_str #endif - // Debugging enabled - - mono_debug_init(MONO_DEBUG_FORMAT_MONO); - - // --debugger-agent=help - const char *options[] = { - "--soft-breakpoints", - da_args.get_data() - }; - mono_jit_parse_options(2, (char **)options); -} - -#endif // !defined(JAVASCRIPT_ENABLED) - -#if defined(JAVASCRIPT_ENABLED) -MonoDomain *gd_initialize_mono_runtime() { - const char *vfs_prefix = "managed"; - int enable_debugging = 0; - - // TODO: Provide a way to enable debugging on WASM release builds. -#ifdef DEBUG_ENABLED - enable_debugging = 1; +HostFxrCharString str_to_hostfxr(const String &p_str) { +#ifdef _WIN32 + return p_str.utf16(); +#else + return p_str.utf8(); #endif - - mono_wasm_load_runtime(vfs_prefix, enable_debugging); - - return mono_get_root_domain(); } -#else -MonoDomain *gd_initialize_mono_runtime() { - gd_mono_debug_init(); -#if defined(IOS_ENABLED) || defined(ANDROID_ENABLED) - // I don't know whether this actually matters or not - const char *runtime_version = "mobile"; +#ifdef TOOLS_ENABLED +String str_from_hostfxr(const char_t *p_buffer) { +#ifdef _WIN32 + return String::utf16((const char16_t *)p_buffer); #else - const char *runtime_version = "v4.0.30319"; + return String::utf8((const char *)p_buffer); #endif - - return mono_jit_init_version("GodotEngine.RootDomain", runtime_version); } #endif -} // namespace - -void GDMono::add_mono_shared_libs_dir_to_path() { - // TODO: Replace this with a mono_dl_fallback - - // By default Mono seems to search shared libraries in the following directories: - // Current working directory, @executable_path@ and PATH - // The parent directory of the image file (assembly where the dllimport method is declared) - // @executable_path@/../lib - // @executable_path@/../Libraries (__MACH__ only) - // This does not work when embedding Mono unless we use the same directory structure. - // To fix this we append the directory containing our shared libraries to PATH. - -#if defined(WINDOWS_ENABLED) || defined(UNIX_ENABLED) - String path_var("PATH"); - String path_value = OS::get_singleton()->get_environment(path_var); - -#ifdef WINDOWS_ENABLED - path_value += ';'; +const char_t *get_data(const HostFxrCharString &p_char_str) { + return (const char_t *)p_char_str.get_data(); +} - String bundled_bin_dir = GodotSharpDirs::get_data_mono_bin_dir(); #ifdef TOOLS_ENABLED - if (DirAccess::exists(bundled_bin_dir)) { - path_value += bundled_bin_dir; - } else { - path_value += mono_reg_info.bin_dir; - } -#else - if (DirAccess::exists(bundled_bin_dir)) { - path_value += bundled_bin_dir; - } -#endif // TOOLS_ENABLED +String find_hostfxr(size_t p_known_buffet_size, get_hostfxr_parameters *p_get_hostfxr_params) { + // Pre-allocate a large buffer for the path to hostfxr + Vector<char_t> buffer; + buffer.resize(p_known_buffet_size); -#else - path_value += ':'; + int rc = get_hostfxr_path(buffer.ptrw(), &p_known_buffet_size, p_get_hostfxr_params); - String bundled_lib_dir = GodotSharpDirs::get_data_mono_lib_dir(); - if (DirAccess::exists(bundled_lib_dir)) { - path_value += bundled_lib_dir; - } else { - // TODO: Do we need to add the lib dir when using the system installed Mono on Unix platforms? - } -#endif // WINDOWS_ENABLED + ERR_FAIL_COND_V_MSG(rc != 0, String(), "get_hostfxr_path failed with code: " + itos(rc)); - OS::get_singleton()->set_environment(path_var, path_value); -#endif // WINDOWS_ENABLED || UNIX_ENABLED + return str_from_hostfxr(buffer.ptr()); } +#endif -void GDMono::determine_mono_dirs(String &r_assembly_rootdir, String &r_config_dir) { - String bundled_assembly_rootdir = GodotSharpDirs::get_data_mono_lib_dir(); - String bundled_config_dir = GodotSharpDirs::get_data_mono_etc_dir(); - +String find_hostfxr() { #ifdef TOOLS_ENABLED - -#if defined(WINDOWS_ENABLED) - mono_reg_info = MonoRegUtils::find_mono(); - - if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) { - r_assembly_rootdir = mono_reg_info.assembly_dir; - } - - if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) { - r_config_dir = mono_reg_info.config_dir; - } -#elif defined(MACOS_ENABLED) - const char *c_assembly_rootdir = mono_assembly_getrootdir(); - const char *c_config_dir = mono_get_config_dir(); - - if (!c_assembly_rootdir || !c_config_dir || !DirAccess::exists(c_assembly_rootdir) || !DirAccess::exists(c_config_dir)) { - Vector<const char *> locations; - locations.push_back("/Library/Frameworks/Mono.framework/Versions/Current/"); - locations.push_back("/usr/local/var/homebrew/linked/mono/"); - - for (int i = 0; i < locations.size(); i++) { - String hint_assembly_rootdir = path::join(locations[i], "lib"); - String hint_mscorlib_path = path::join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll"); - String hint_config_dir = path::join(locations[i], "etc"); - - if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) { - r_assembly_rootdir = hint_assembly_rootdir; - r_config_dir = hint_config_dir; - break; + const int CoreHostLibMissingFailure = 0x80008083; + const int HostApiBufferTooSmall = 0x80008098; + + size_t buffer_size = 0; + int rc = get_hostfxr_path(nullptr, &buffer_size, nullptr); + + if (rc == HostApiBufferTooSmall) { + return find_hostfxr(buffer_size, nullptr); + } + + if (rc == CoreHostLibMissingFailure) { + // Apparently `get_hostfxr_path` doesn't look for dotnet in `PATH`? (I suppose it needs the + // `DOTNET_ROOT` environment variable). If it fails, we try to find the dotnet executable + // in `PATH` ourselves and pass its location as `dotnet_root` to `get_hostfxr_path`. + String dotnet_exe = path::find_executable("dotnet"); + + if (!dotnet_exe.is_empty()) { + // The file found in PATH may be a symlink + dotnet_exe = path::abspath(path::realpath(dotnet_exe)); + + // TODO: + // Sometimes, the symlink may not point to the dotnet executable in the dotnet root. + // That's the case with snaps. The snap install should have been found with the + // previous `get_hostfxr_path`, but it would still be better to do this properly + // and use something like `dotnet --list-sdks/runtimes` to find the actual location. + // This way we could also check if the proper sdk or runtime is installed. This would + // allow us to fail gracefully and show some helpful information in the editor. + + HostFxrCharString dotnet_root = str_to_hostfxr(dotnet_exe.get_base_dir()); + + get_hostfxr_parameters get_hostfxr_parameters = { + sizeof(get_hostfxr_parameters), + nullptr, + get_data(dotnet_root) + }; + + buffer_size = 0; + rc = get_hostfxr_path(nullptr, &buffer_size, &get_hostfxr_parameters); + if (rc == HostApiBufferTooSmall) { + return find_hostfxr(buffer_size, &get_hostfxr_parameters); } } } -#endif - if (DirAccess::exists(bundled_assembly_rootdir)) { - r_assembly_rootdir = bundled_assembly_rootdir; + if (rc == CoreHostLibMissingFailure) { + ERR_PRINT(String() + ".NET: One of the dependent libraries is missing. " + + "Typically when the `hostfxr`, `hostpolicy` or `coreclr` dynamic " + + "libraries are not present in the expected locations."); } - if (DirAccess::exists(bundled_config_dir)) { - r_config_dir = bundled_config_dir; - } - -#ifdef WINDOWS_ENABLED - if (r_assembly_rootdir.is_empty() || r_config_dir.is_empty()) { - ERR_PRINT("Cannot find Mono in the registry."); - // Assertion: if they are not set, then they weren't found in the registry - CRASH_COND(mono_reg_info.assembly_dir.length() > 0 || mono_reg_info.config_dir.length() > 0); - } -#endif // WINDOWS_ENABLED - + return String(); #else - // Export templates always use the bundled directories - r_assembly_rootdir = bundled_assembly_rootdir; - r_config_dir = bundled_config_dir; -#endif -} - -void GDMono::initialize() { - ERR_FAIL_NULL(Engine::get_singleton()); - - 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); - - _init_godot_api_hashes(); - _init_exception_policy(); - - GDMonoLog::get_singleton()->initialize(); - -#if !defined(JAVASCRIPT_ENABLED) - String assembly_rootdir; - String config_dir; - determine_mono_dirs(assembly_rootdir, config_dir); - - // Leak if we call mono_set_dirs more than once - mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : nullptr, - config_dir.length() ? config_dir.utf8().get_data() : nullptr); - add_mono_shared_libs_dir_to_path(); -#endif - -#ifdef ANDROID_ENABLED - mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data()); +#if defined(WINDOWS_ENABLED) + String probe_path = GodotSharpDirs::get_api_assemblies_dir() + .plus_file("hostfxr.dll"); +#elif defined(MACOS_ENABLED) + String probe_path = GodotSharpDirs::get_api_assemblies_dir() + .plus_file("libhostfxr.dylib"); +#elif defined(UNIX_ENABLED) + String probe_path = GodotSharpDirs::get_api_assemblies_dir() + .plus_file("libhostfxr.so"); #else - mono_config_parse(nullptr); +#error "Platform not supported (yet?)" #endif -#if defined(ANDROID_ENABLED) - gdmono::android::support::initialize(); -#elif defined(IOS_ENABLED) - gdmono::ios::support::initialize(); -#endif + if (FileAccess::exists(probe_path)) { + return probe_path; + } - GDMonoAssembly::initialize(); + return String(); -#if !defined(JAVASCRIPT_ENABLED) - gd_mono_profiler_init(); #endif +} - mono_install_unhandled_exception_hook(&unhandled_exception_hook, nullptr); - -#ifndef TOOLS_ENABLED - // Exported games that don't use C# must still work. They likely don't ship with mscorlib. - // We only initialize the Mono runtime if we can find mscorlib. Otherwise it would crash. - if (GDMonoAssembly::find_assembly("mscorlib.dll").is_empty()) { - print_verbose("Mono: Skipping runtime initialization because 'mscorlib.dll' could not be found"); - return; - } -#endif +bool load_hostfxr(void *&r_hostfxr_dll_handle) { + String hostfxr_path = find_hostfxr(); -#if !defined(NO_MONO_THREADS_SUSPEND_WORKAROUND) - // FIXME: Temporary workaround. See: https://github.com/godotengine/godot/issues/29812 - if (!OS::get_singleton()->has_environment("MONO_THREADS_SUSPEND")) { - OS::get_singleton()->set_environment("MONO_THREADS_SUSPEND", "preemptive"); + if (hostfxr_path.is_empty()) { + return false; } -#endif - // NOTE: Internal calls must be registered after the Mono runtime initialization. - // Otherwise registration fails with the error: 'assertion 'hash != nullptr' failed'. + print_verbose("Found hostfxr: " + hostfxr_path); - root_domain = gd_initialize_mono_runtime(); - ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime."); + Error err = OS::get_singleton()->open_dynamic_library(hostfxr_path, r_hostfxr_dll_handle); - GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread()); - -#if !defined(JAVASCRIPT_ENABLED) - gd_mono_setup_runtime_main_args(); // Required for System.Environment.GetCommandLineArgs -#endif + if (err != OK) { + return false; + } - runtime_initialized = true; + void *lib = r_hostfxr_dll_handle; - print_verbose("Mono: Runtime initialized"); + void *symbol = nullptr; -#if defined(ANDROID_ENABLED) - gdmono::android::support::register_internal_calls(); -#endif + err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_initialize_for_dotnet_command_line", symbol); + ERR_FAIL_COND_V(err != OK, false); + hostfxr_initialize_for_dotnet_command_line = (hostfxr_initialize_for_dotnet_command_line_fn)symbol; - // mscorlib assembly MUST be present at initialization - bool corlib_loaded = _load_corlib_assembly(); - ERR_FAIL_COND_MSG(!corlib_loaded, "Mono: Failed to load mscorlib assembly."); + err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_initialize_for_runtime_config", symbol); + ERR_FAIL_COND_V(err != OK, false); + hostfxr_initialize_for_runtime_config = (hostfxr_initialize_for_runtime_config_fn)symbol; -#ifndef GD_MONO_SINGLE_APPDOMAIN - Error domain_load_err = _load_scripts_domain(); - ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain."); -#else - scripts_domain = root_domain; -#endif + err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_get_runtime_delegate", symbol); + ERR_FAIL_COND_V(err != OK, false); + hostfxr_get_runtime_delegate = (hostfxr_get_runtime_delegate_fn)symbol; - _register_internal_calls(); + err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_close", symbol); + ERR_FAIL_COND_V(err != OK, false); + hostfxr_close = (hostfxr_close_fn)symbol; - print_verbose("Mono: INITIALIZED"); + return (hostfxr_initialize_for_runtime_config && + hostfxr_get_runtime_delegate && + hostfxr_close); } -void GDMono::initialize_load_assemblies() { -#ifndef MONO_GLUE_ENABLED - CRASH_NOW_MSG("Mono: This binary was built with 'mono_glue=no'; cannot load assemblies."); -#endif - - // Load assemblies. The API and tools assemblies are required, - // the application is aborted if these assemblies cannot be loaded. - - _load_api_assemblies(); - -#if defined(TOOLS_ENABLED) - bool tool_assemblies_loaded = _load_tools_assemblies(); - CRASH_COND_MSG(!tool_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies."); - - if (Engine::get_singleton()->is_project_manager_hint()) { - 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()) { - 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) { - out_of_sync = editor_api_assembly.assembly && editor_api_assembly.out_of_sync; +load_assembly_and_get_function_pointer_fn initialize_hostfxr_for_config(const char_t *p_config_path) { + hostfxr_handle cxt = nullptr; + int rc = hostfxr_initialize_for_runtime_config(p_config_path, nullptr, &cxt); + if (rc != 0 || cxt == nullptr) { + hostfxr_close(cxt); + ERR_FAIL_V_MSG(nullptr, "hostfxr_initialize_for_runtime_config failed with code: " + itos(rc)); } -#endif - return out_of_sync; -} -namespace GodotSharpBindings { -#ifdef MONO_GLUE_ENABLED + void *load_assembly_and_get_function_pointer = nullptr; -uint64_t get_core_api_hash(); -#ifdef TOOLS_ENABLED -uint64_t get_editor_api_hash(); -#endif -uint32_t get_bindings_version(); -uint32_t get_cs_glue_version(); - -void register_generated_icalls(); + rc = hostfxr_get_runtime_delegate(cxt, + hdt_load_assembly_and_get_function_pointer, &load_assembly_and_get_function_pointer); + if (rc != 0 || load_assembly_and_get_function_pointer == nullptr) { + ERR_FAIL_V_MSG(nullptr, "hostfxr_get_runtime_delegate failed with code: " + itos(rc)); + } -#else + hostfxr_close(cxt); -uint64_t get_core_api_hash() { - GD_UNREACHABLE(); -} -#ifdef TOOLS_ENABLED -uint64_t get_editor_api_hash() { - GD_UNREACHABLE(); -} -#endif -uint32_t get_bindings_version() { - GD_UNREACHABLE(); -} - -uint32_t get_cs_glue_version() { - GD_UNREACHABLE(); + return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer; } +#else +load_assembly_and_get_function_pointer_fn initialize_hostfxr_self_contained( + const char_t *p_main_assembly_path) { + hostfxr_handle cxt = nullptr; -void register_generated_icalls() { - /* Fine, just do nothing */ -} + List<String> cmdline_args = OS::get_singleton()->get_cmdline_args(); -#endif // MONO_GLUE_ENABLED -} // namespace GodotSharpBindings + List<HostFxrCharString> argv_store; + Vector<const char_t *> argv; + argv.resize(cmdline_args.size() + 1); -void GDMono::_register_internal_calls() { - GodotSharpBindings::register_generated_icalls(); -} + argv.write[0] = p_main_assembly_path; -void GDMono::_init_godot_api_hashes() { -#if defined(MONO_GLUE_ENABLED) && defined(DEBUG_METHODS_ENABLED) - if (get_api_core_hash() != GodotSharpBindings::get_core_api_hash()) { - ERR_PRINT("Mono: Core API hash mismatch."); + int i = 1; + for (const String &E : cmdline_args) { + HostFxrCharString &stored = argv_store.push_back(str_to_hostfxr(E))->get(); + argv.write[i] = stored.ptr(); + i++; } -#ifdef TOOLS_ENABLED - if (get_api_editor_hash() != GodotSharpBindings::get_editor_api_hash()) { - ERR_PRINT("Mono: Editor API hash mismatch."); + int rc = hostfxr_initialize_for_dotnet_command_line(argv.size(), argv.ptrw(), nullptr, &cxt); + if (rc != 0 || cxt == nullptr) { + hostfxr_close(cxt); + ERR_FAIL_V_MSG(nullptr, "hostfxr_initialize_for_dotnet_command_line failed with code: " + itos(rc)); } -#endif // TOOLS_ENABLED -#endif // MONO_GLUE_ENABLED && DEBUG_METHODS_ENABLED -} -void GDMono::_init_exception_policy() { - PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/runtime/unhandled_exception_policy", PROPERTY_HINT_ENUM, - vformat("Terminate Application:%s,Log Error:%s", (int)POLICY_TERMINATE_APP, (int)POLICY_LOG_ERROR)); - unhandled_exception_policy = (UnhandledExceptionPolicy)(int)GLOBAL_DEF(exc_policy_prop.name, (int)POLICY_TERMINATE_APP); - ProjectSettings::get_singleton()->set_custom_property_info(exc_policy_prop.name, exc_policy_prop); + void *load_assembly_and_get_function_pointer = nullptr; - if (Engine::get_singleton()->is_editor_hint()) { - // Unhandled exceptions should not terminate the editor - unhandled_exception_policy = POLICY_LOG_ERROR; + rc = hostfxr_get_runtime_delegate(cxt, + hdt_load_assembly_and_get_function_pointer, &load_assembly_and_get_function_pointer); + if (rc != 0 || load_assembly_and_get_function_pointer == nullptr) { + ERR_FAIL_V_MSG(nullptr, "hostfxr_get_runtime_delegate failed with code: " + itos(rc)); } -} - -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) { - return corlib_assembly; - } + hostfxr_close(cxt); - MonoDomain *domain = mono_domain_get(); - int32_t domain_id = domain ? mono_domain_get_id(domain) : 0; - GDMonoAssembly **result = assemblies[domain_id].getptr(p_name); - return result ? *result : nullptr; + return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer; } - -bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) { -#ifdef DEBUG_ENABLED - CRASH_COND(!r_assembly); #endif - 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) { -#ifdef DEBUG_ENABLED - CRASH_COND(!r_assembly); +#ifdef TOOLS_ENABLED +using godot_plugins_initialize_fn = bool (*)(void *, bool, gdmono::PluginCallbacks *, GDMonoCache::ManagedCallbacks *, const void **, int32_t); +#else +using godot_plugins_initialize_fn = bool (*)(void *, GDMonoCache::ManagedCallbacks *, const void **, int32_t); #endif - return load_assembly(p_name, p_aname, r_assembly, p_refonly, GDMonoAssembly::get_default_search_dirs()); -} +#ifdef TOOLS_ENABLED +godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) { + godot_plugins_initialize_fn godot_plugins_initialize = nullptr; -bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly, const Vector<String> &p_search_dirs) { -#ifdef DEBUG_ENABLED - CRASH_COND(!r_assembly); -#endif + HostFxrCharString godot_plugins_path = str_to_hostfxr( + GodotSharpDirs::get_api_assemblies_dir().plus_file("GodotPlugins.dll")); - print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "..."); + HostFxrCharString config_path = str_to_hostfxr( + GodotSharpDirs::get_api_assemblies_dir().plus_file("GodotPlugins.runtimeconfig.json")); - GDMonoAssembly *assembly = GDMonoAssembly::load(p_name, p_aname, p_refonly, p_search_dirs); + load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer = + initialize_hostfxr_for_config(get_data(config_path)); + ERR_FAIL_NULL_V(load_assembly_and_get_function_pointer, nullptr); - if (!assembly) { - return false; - } + r_runtime_initialized = true; - *r_assembly = assembly; + print_verbose(".NET: hostfxr initialized"); - print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path()); + int rc = load_assembly_and_get_function_pointer(get_data(godot_plugins_path), + HOSTFXR_STR("GodotPlugins.Main, GodotPlugins"), + HOSTFXR_STR("InitializeFromEngine"), + UNMANAGEDCALLERSONLY_METHOD, + nullptr, + (void **)&godot_plugins_initialize); + ERR_FAIL_COND_V_MSG(rc != 0, nullptr, ".NET: Failed to get GodotPlugins initialization function pointer"); - return true; + return godot_plugins_initialize; } +#else +static String get_assembly_name() { + String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name"); -bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly, bool p_refonly) { - CRASH_COND(!r_assembly); - - print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "..."); - - GDMonoAssembly *assembly = GDMonoAssembly::load_from(p_name, p_path, p_refonly); - - if (!assembly) { - return false; + if (assembly_name.is_empty()) { + assembly_name = ProjectSettings::get_singleton()->get_safe_project_name(); } - *r_assembly = assembly; - - print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path()); - - return true; + return assembly_name; } -ApiAssemblyInfo::Version ApiAssemblyInfo::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, ApiAssemblyInfo::Type p_api_type) { - ApiAssemblyInfo::Version api_assembly_version; +godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) { + godot_plugins_initialize_fn godot_plugins_initialize = nullptr; - const char *nativecalls_name = p_api_type == ApiAssemblyInfo::API_CORE - ? BINDINGS_CLASS_NATIVECALLS - : BINDINGS_CLASS_NATIVECALLS_EDITOR; + String assembly_name = get_assembly_name(); - GDMonoClass *nativecalls_klass = p_api_assembly->get_class(BINDINGS_NAMESPACE, nativecalls_name); + HostFxrCharString assembly_path = str_to_hostfxr(GodotSharpDirs::get_api_assemblies_dir() + .plus_file(assembly_name + ".dll")); - if (nativecalls_klass) { - GDMonoField *api_hash_field = nativecalls_klass->get_field("godot_api_hash"); - if (api_hash_field) { - api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(nullptr)); - } + load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer = + initialize_hostfxr_self_contained(get_data(assembly_path)); + ERR_FAIL_NULL_V(load_assembly_and_get_function_pointer, nullptr); - GDMonoField *binds_ver_field = nativecalls_klass->get_field("bindings_version"); - if (binds_ver_field) { - api_assembly_version.bindings_version = GDMonoMarshal::unbox<uint32_t>(binds_ver_field->get_value(nullptr)); - } + r_runtime_initialized = true; - GDMonoField *cs_glue_ver_field = nativecalls_klass->get_field("cs_glue_version"); - if (cs_glue_ver_field) { - api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(nullptr)); - } - } + print_verbose(".NET: hostfxr initialized"); - return api_assembly_version; -} + int rc = load_assembly_and_get_function_pointer(get_data(assembly_path), + str_to_hostfxr("GodotPlugins.Game.Main, " + assembly_name), + HOSTFXR_STR("InitializeFromGameProject"), + UNMANAGEDCALLERSONLY_METHOD, + nullptr, + (void **)&godot_plugins_initialize); + ERR_FAIL_COND_V_MSG(rc != 0, nullptr, ".NET: Failed to get GodotPlugins initialization function pointer"); -String ApiAssemblyInfo::to_string(ApiAssemblyInfo::Type p_type) { - return p_type == ApiAssemblyInfo::API_CORE ? "API_CORE" : "API_EDITOR"; + return godot_plugins_initialize; } -bool GDMono::_load_corlib_assembly() { - if (corlib_assembly) { - return true; - } - - bool success = load_assembly("mscorlib", &corlib_assembly); - - if (success) { - GDMonoCache::update_corlib_cache(); - } - - return success; -} +godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle) { + String assembly_name = get_assembly_name(); -#ifdef TOOLS_ENABLED -bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config) { - String src_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config); - String dst_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config); - - String assembly_name = p_api_type == ApiAssemblyInfo::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME; +#if defined(WINDOWS_ENABLED) + String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".dll"); +#elif defined(MACOS_ENABLED) + String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".dylib"); +#elif defined(UNIX_ENABLED) + String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".so"); +#else +#error "Platform not supported (yet?)" +#endif - // Create destination directory if needed - if (!DirAccess::exists(dst_dir)) { - Ref<DirAccess> da = DirAccess::create_for_path(dst_dir); - Error err = da->make_dir_recursive(dst_dir); + if (FileAccess::exists(native_aot_so_path)) { + Error err = OS::get_singleton()->open_dynamic_library(native_aot_so_path, r_aot_dll_handle); if (err != OK) { - ERR_PRINT("Failed to create destination directory for the API assemblies. Error: " + itos(err) + "."); - return false; + return nullptr; } - } - Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + void *lib = r_aot_dll_handle; - String xml_file = assembly_name + ".xml"; - if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) { - WARN_PRINT("Failed to copy '" + xml_file + "'."); - } + void *symbol = nullptr; - String pdb_file = assembly_name + ".pdb"; - if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK) { - WARN_PRINT("Failed to copy '" + pdb_file + "'."); + err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "godotsharp_game_main_init", symbol); + ERR_FAIL_COND_V(err != OK, nullptr); + return (godot_plugins_initialize_fn)symbol; } - String assembly_file = assembly_name + ".dll"; - if (da->copy(src_dir.plus_file(assembly_file), dst_dir.plus_file(assembly_file)) != OK) { - ERR_PRINT("Failed to copy '" + assembly_file + "'."); - return false; - } - - return true; + return nullptr; } +#endif -static bool try_get_cached_api_hash_for(const String &p_api_assemblies_dir, bool &r_out_of_sync) { - 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)) { - return false; - } - - String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg"); +} // namespace - if (!FileAccess::exists(cached_api_hash_path)) { +static bool _on_core_api_assembly_loaded() { + if (!GDMonoCache::godot_api_cache_updated) { return false; } - Ref<ConfigFile> cfg; - cfg.instantiate(); - Error cfg_err = cfg->load(cached_api_hash_path); - ERR_FAIL_COND_V(cfg_err != OK, false); - - // Checking the modified time is good enough - if (FileAccess::get_modified_time(core_api_assembly_path) != (uint64_t)cfg->get_value("core", "modified_time") || - FileAccess::get_modified_time(editor_api_assembly_path) != (uint64_t)cfg->get_value("editor", "modified_time")) { - return false; - } + bool debug; +#ifdef DEBUG_ENABLED + debug = true; +#else + debug = false; +#endif - r_out_of_sync = GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("core", "bindings_version") || - GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("core", "cs_glue_version") || - GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("editor", "bindings_version") || - GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("editor", "cs_glue_version") || - GodotSharpBindings::get_core_api_hash() != (uint64_t)cfg->get_value("core", "api_hash") || - GodotSharpBindings::get_editor_api_hash() != (uint64_t)cfg->get_value("editor", "api_hash"); + GDMonoCache::managed_callbacks.GD_OnCoreApiAssemblyLoaded(debug); return true; } -static void create_cached_api_hash_for(const String &p_api_assemblies_dir) { - 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"); - String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg"); - - Ref<ConfigFile> cfg; - cfg.instantiate(); - - cfg->set_value("core", "modified_time", FileAccess::get_modified_time(core_api_assembly_path)); - cfg->set_value("editor", "modified_time", FileAccess::get_modified_time(editor_api_assembly_path)); - - cfg->set_value("core", "bindings_version", GodotSharpBindings::get_bindings_version()); - cfg->set_value("core", "cs_glue_version", GodotSharpBindings::get_cs_glue_version()); - cfg->set_value("editor", "bindings_version", GodotSharpBindings::get_bindings_version()); - cfg->set_value("editor", "cs_glue_version", GodotSharpBindings::get_cs_glue_version()); - - // This assumes the prebuilt api assemblies we copied to the project are not out of sync - cfg->set_value("core", "api_hash", GodotSharpBindings::get_core_api_hash()); - cfg->set_value("editor", "api_hash", GodotSharpBindings::get_editor_api_hash()); - - Error err = cfg->save(cached_api_hash_path); - ERR_FAIL_COND(err != OK); -} - -bool GDMono::_temp_domain_load_are_assemblies_out_of_sync(const String &p_config) { - MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.Domain.CheckApiAssemblies"); - ERR_FAIL_NULL_V(temp_domain, "Failed to create temporary domain to check API assemblies"); - _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(temp_domain); - - _GDMONO_SCOPE_DOMAIN_(temp_domain); - - GDMono::LoadedApiAssembly temp_core_api_assembly; - GDMono::LoadedApiAssembly temp_editor_api_assembly; - - if (!_try_load_api_assemblies(temp_core_api_assembly, temp_editor_api_assembly, - p_config, /* refonly: */ true, /* loaded_callback: */ nullptr)) { - return temp_core_api_assembly.out_of_sync || temp_editor_api_assembly.out_of_sync; - } - - return true; // Failed to load, assume they're outdated assemblies -} - -String GDMono::update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync, const bool *p_editor_api_out_of_sync) { -#define FAIL_REASON(m_out_of_sync, m_prebuilt_exists) \ - ( \ - (m_out_of_sync ? String("The assembly is invalidated ") : String("The assembly was not found ")) + \ - (m_prebuilt_exists ? String("and the prebuilt assemblies are missing.") : String("and we failed to copy the prebuilt assemblies."))) +void GDMono::initialize() { + print_verbose(".NET: Initializing module..."); - String dst_assemblies_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config); + _init_godot_api_hashes(); - String core_assembly_path = dst_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll"); - String editor_assembly_path = dst_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); + godot_plugins_initialize_fn godot_plugins_initialize = nullptr; - bool api_assemblies_out_of_sync = false; + if (!load_hostfxr(hostfxr_dll_handle)) { +#if !defined(TOOLS_ENABLED) + godot_plugins_initialize = try_load_native_aot_library(hostfxr_dll_handle); - if (p_core_api_out_of_sync && p_editor_api_out_of_sync) { - api_assemblies_out_of_sync = p_core_api_out_of_sync || p_editor_api_out_of_sync; - } else if (FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) { - // Determine if they're out of sync - if (!try_get_cached_api_hash_for(dst_assemblies_dir, api_assemblies_out_of_sync)) { - api_assemblies_out_of_sync = _temp_domain_load_are_assemblies_out_of_sync(p_config); + if (godot_plugins_initialize != nullptr) { + is_native_aot = true; + } else { + ERR_FAIL_MSG(".NET: Failed to load hostfxr"); } +#else + ERR_FAIL_MSG(".NET: Failed to load hostfxr"); +#endif } - // 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)) { - return String(); // No update needed - } - - print_verbose("Updating '" + p_config + "' API assemblies"); - - String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config); - String prebuilt_core_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll"); - String prebuilt_editor_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); - - if (!FileAccess::exists(prebuilt_core_dll_path) || !FileAccess::exists(prebuilt_editor_dll_path)) { - return FAIL_REASON(api_assemblies_out_of_sync, /* prebuilt_exists: */ false); + if (!is_native_aot) { + godot_plugins_initialize = initialize_hostfxr_and_godot_plugins(runtime_initialized); + ERR_FAIL_NULL(godot_plugins_initialize); } - // Copy the prebuilt Api - if (!copy_prebuilt_api_assembly(ApiAssemblyInfo::API_CORE, p_config) || - !copy_prebuilt_api_assembly(ApiAssemblyInfo::API_EDITOR, p_config)) { - return FAIL_REASON(api_assemblies_out_of_sync, /* prebuilt_exists: */ true); - } + int32_t interop_funcs_size = 0; + const void **interop_funcs = godotsharp::get_runtime_interop_funcs(interop_funcs_size); - // Cache the api hash of the assemblies we just copied - create_cached_api_hash_for(dst_assemblies_dir); + GDMonoCache::ManagedCallbacks managed_callbacks{}; - return String(); // Updated successfully + void *godot_dll_handle = nullptr; -#undef FAIL_REASON -} +#if defined(UNIX_ENABLED) && !defined(MACOS_ENABLED) && !defined(IOS_ENABLED) + // Managed code can access it on its own on other platforms + godot_dll_handle = dlopen(nullptr, RTLD_NOW); #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) { - 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 - - // If running the project manager, load it from the prebuilt API directory - String assembly_dir = !Engine::get_singleton()->is_project_manager_hint() - ? GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) - : GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config); - - String assembly_path = assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll"); - - bool success = FileAccess::exists(assembly_path) && - load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly); + gdmono::PluginCallbacks plugin_callbacks_res; + bool init_ok = godot_plugins_initialize(godot_dll_handle, + Engine::get_singleton()->is_editor_hint(), + &plugin_callbacks_res, &managed_callbacks, + interop_funcs, interop_funcs_size); + ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed"); + + plugin_callbacks = plugin_callbacks_res; #else - bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &r_loaded_api_assembly.assembly, p_refonly); + bool init_ok = godot_plugins_initialize(godot_dll_handle, &managed_callbacks, + interop_funcs, interop_funcs_size); + ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed"); #endif - if (success) { - ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_CORE); - r_loaded_api_assembly.out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash || - GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version || - GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version; - } else { - r_loaded_api_assembly.out_of_sync = false; - } + GDMonoCache::update_godot_api_cache(managed_callbacks); - return success; -} + print_verbose(".NET: GodotPlugins initialized"); -#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) { - 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 - - // If running the project manager, load it from the prebuilt API directory - String assembly_dir = !Engine::get_singleton()->is_project_manager_hint() - ? GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) - : GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config); - - String assembly_path = assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); - - bool success = FileAccess::exists(assembly_path) && - load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly); - - if (success) { - ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_EDITOR); - r_loaded_api_assembly.out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash || - GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version || - GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version; - } else { - r_loaded_api_assembly.out_of_sync = false; - } - - return success; + _on_core_api_assembly_loaded(); } -#endif -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()) { - print_error("Mono: Failed to load Core API assembly"); - } - return false; +#ifdef TOOLS_ENABLED +void GDMono::initialize_load_assemblies() { + if (Engine::get_singleton()->is_project_manager_hint()) { + return; } -#ifdef TOOLS_ENABLED - if (!_load_editor_api_assembly(r_editor_api_assembly, p_config, p_refonly)) { + // 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()) { - print_error("Mono: Failed to load Editor API assembly"); + print_error(".NET: Failed to load project assembly"); } - return false; } - - 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) { - return false; - } - - if (p_callback) { - return p_callback(); - } - - return true; } - -bool GDMono::_on_core_api_assembly_loaded() { - GDMonoCache::update_godot_api_cache(); - - if (!GDMonoCache::cached_data.godot_api_cache_updated) { - return false; - } - - get_singleton()->_install_trace_listener(); - - return true; -} - -bool GDMono::_try_load_api_assemblies_preset() { - return _try_load_api_assemblies(core_api_assembly, editor_api_assembly, - get_expected_api_build_config(), /* refonly: */ false, _on_core_api_assembly_loaded); -} - -void GDMono::_load_api_assemblies() { - bool api_assemblies_loaded = _try_load_api_assemblies_preset(); - -#if defined(TOOLS_ENABLED) && !defined(GD_MONO_SINGLE_APPDOMAIN) - if (!api_assemblies_loaded) { - // The API assemblies are out of sync or some other error happened. Fine, try one more time, but - // this time update them from the prebuilt assemblies directory before trying to load them again. - - // Shouldn't happen. The project manager loads the prebuilt API assemblies - CRASH_COND_MSG(Engine::get_singleton()->is_project_manager_hint(), "Failed to load one of the prebuilt API assemblies."); - - // 1. Unload the scripts domain - Error domain_unload_err = _unload_scripts_domain(); - CRASH_COND_MSG(domain_unload_err != OK, "Mono: Failed to unload scripts domain."); - - // 2. Update the API assemblies - String update_error = update_api_assemblies_from_prebuilt("Debug", &core_api_assembly.out_of_sync, &editor_api_assembly.out_of_sync); - CRASH_COND_MSG(!update_error.is_empty(), update_error); - - // 3. Load the scripts domain again - Error domain_load_err = _load_scripts_domain(); - CRASH_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain."); - - // 4. Try loading the updated assemblies - api_assemblies_loaded = _try_load_api_assemblies_preset(); - } #endif - if (!api_assemblies_loaded) { - // welp... too bad - - if (_are_api_assemblies_out_of_sync()) { - if (core_api_assembly.out_of_sync) { - ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync."); - } else if (!GDMonoCache::cached_data.godot_api_cache_updated) { - ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed."); - } +void GDMono::_init_godot_api_hashes() { +#ifdef DEBUG_METHODS_ENABLED + get_api_core_hash(); #ifdef TOOLS_ENABLED - if (editor_api_assembly.out_of_sync) { - ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync."); - } -#endif - - CRASH_NOW(); - } else { - CRASH_NOW_MSG("Failed to load one of the API assemblies."); - } - } + get_api_editor_hash(); +#endif // TOOLS_ENABLED +#endif // DEBUG_METHODS_ENABLED } #ifdef TOOLS_ENABLED -bool GDMono::_load_tools_assemblies() { - 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); - - return success; -} -#endif - bool GDMono::_load_project_assembly() { - if (project_assembly) { - return true; - } + String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name"); - String appname = ProjectSettings::get_singleton()->get("application/config/name"); - String appname_safe = OS::get_singleton()->get_safe_dir_name(appname); - if (appname_safe.is_empty()) { - appname_safe = "UnnamedProject"; + if (assembly_name.is_empty()) { + assembly_name = ProjectSettings::get_singleton()->get_safe_project_name(); } - bool success = load_assembly(appname_safe, &project_assembly); + String assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir() + .plus_file(assembly_name + ".dll"); + assembly_path = ProjectSettings::get_singleton()->globalize_path(assembly_path); + + String loaded_assembly_path; + bool success = plugin_callbacks.LoadProjectAssemblyCallback(assembly_path.utf16(), &loaded_assembly_path); if (success) { - mono_assembly_set_main(project_assembly->get_assembly()); - CSharpLanguage::get_singleton()->lookup_scripts_in_assembly(project_assembly); + project_assembly_path = loaded_assembly_path.simplify_path(); + project_assembly_modified_time = FileAccess::get_modified_time(loaded_assembly_path); } return success; } - -void GDMono::_install_trace_listener() { -#ifdef DEBUG_ENABLED - // Install the trace listener now before the project assembly is loaded - GDMonoClass *debug_utils = get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, "DebuggingUtils"); - GDMonoMethod *install_func = debug_utils->get_method("InstallTraceListener"); - - MonoException *exc = nullptr; - install_func->invoke_raw(nullptr, nullptr, &exc); - if (exc) { - GDMonoUtils::debug_print_unhandled_exception(exc); - ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener."); - } -#endif -} - -#ifndef GD_MONO_SINGLE_APPDOMAIN -Error GDMono::_load_scripts_domain() { - ERR_FAIL_COND_V(scripts_domain != nullptr, ERR_BUG); - - print_verbose("Mono: Loading scripts domain..."); - - scripts_domain = GDMonoUtils::create_domain("GodotEngine.Domain.Scripts"); - - ERR_FAIL_NULL_V_MSG(scripts_domain, ERR_CANT_CREATE, "Mono: Could not create scripts app domain."); - - mono_domain_set(scripts_domain, true); - - return OK; -} - -Error GDMono::_unload_scripts_domain() { - ERR_FAIL_NULL_V(scripts_domain, ERR_BUG); - - print_verbose("Mono: Finalizing scripts domain..."); - - if (mono_domain_get() != root_domain) { - mono_domain_set(root_domain, true); - } - - finalizing_scripts_domain = true; - - if (!mono_domain_finalize(scripts_domain, 2000)) { - ERR_PRINT("Mono: Domain finalization timeout."); - } - - finalizing_scripts_domain = false; - - mono_gc_collect(mono_gc_max_generation()); - - GDMonoCache::clear_godot_api_cache(); - - _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain)); - - core_api_assembly.assembly = nullptr; -#ifdef TOOLS_ENABLED - editor_api_assembly.assembly = nullptr; -#endif - - project_assembly = nullptr; -#ifdef TOOLS_ENABLED - tools_assembly = nullptr; - tools_project_editor_assembly = nullptr; -#endif - - MonoDomain *domain = scripts_domain; - scripts_domain = nullptr; - - print_verbose("Mono: Unloading scripts domain..."); - - MonoException *exc = nullptr; - mono_domain_try_unload(domain, (MonoObject **)&exc); - - if (exc) { - ERR_PRINT("Exception thrown when unloading scripts domain."); - GDMonoUtils::debug_unhandled_exception(exc); - return FAILED; - } - - return OK; -} #endif #ifdef GD_MONO_HOT_RELOAD -Error GDMono::reload_scripts_domain() { +Error GDMono::reload_project_assemblies() { ERR_FAIL_COND_V(!runtime_initialized, ERR_BUG); - if (scripts_domain) { - Error domain_unload_err = _unload_scripts_domain(); - ERR_FAIL_COND_V_MSG(domain_unload_err != OK, domain_unload_err, "Mono: Failed to unload scripts domain."); - } - - CSharpLanguage::get_singleton()->_on_scripts_domain_unloaded(); - - Error domain_load_err = _load_scripts_domain(); - ERR_FAIL_COND_V_MSG(domain_load_err != OK, domain_load_err, "Mono: Failed to load scripts domain."); + finalizing_scripts_domain = true; - // Load assemblies. The API and tools assemblies are required, - // the application is aborted if these assemblies cannot be loaded. + CSharpLanguage::get_singleton()->_on_scripts_domain_about_to_unload(); - _load_api_assemblies(); + if (!get_plugin_callbacks().UnloadProjectPluginCallback()) { + ERR_FAIL_V_MSG(Error::FAILED, ".NET: Failed to unload assemblies."); + } -#if defined(TOOLS_ENABLED) - bool tools_assemblies_loaded = _load_tools_assemblies(); - CRASH_COND_MSG(!tools_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies."); -#endif + finalizing_scripts_domain = false; // Load the project's main assembly. Here, during hot-reloading, we do // consider failing to load the project's main assembly to be an error. - // However, unlike the API and tools assemblies, the application can continue working. if (!_load_project_assembly()) { - print_error("Mono: Failed to load project assembly"); + print_error(".NET: Failed to load project assembly."); return ERR_CANT_OPEN; } @@ -1123,204 +554,38 @@ Error GDMono::reload_scripts_domain() { } #endif -#ifndef GD_MONO_SINGLE_APPDOMAIN -Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { - CRASH_COND(p_domain == nullptr); - CRASH_COND(p_domain == GDMono::get_singleton()->get_scripts_domain()); // Should use _unload_scripts_domain() instead - - String domain_name = mono_domain_get_friendly_name(p_domain); - - print_verbose("Mono: Unloading domain '" + domain_name + "'..."); - - 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."); - } - - mono_gc_collect(mono_gc_max_generation()); - - _domain_assemblies_cleanup(mono_domain_get_id(p_domain)); - - MonoException *exc = nullptr; - mono_domain_try_unload(p_domain, (MonoObject **)&exc); - - if (exc) { - ERR_PRINT("Exception thrown when unloading domain '" + domain_name + "'."); - GDMonoUtils::debug_print_unhandled_exception(exc); - return FAILED; - } - - return OK; -} -#endif - -GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) { - MonoImage *image = mono_class_get_image(p_raw_class); - - if (image == corlib_assembly->get_image()) { - return corlib_assembly->get_class(p_raw_class); - } - - int32_t domain_id = mono_domain_get_id(mono_domain_get()); - HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id]; - - for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) { - GDMonoAssembly *assembly = E.value; - if (assembly->get_image() == image) { - GDMonoClass *klass = assembly->get_class(p_raw_class); - if (klass) { - return klass; - } - } - } - - return nullptr; -} - -GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &p_name) { - GDMonoClass *klass = corlib_assembly->get_class(p_namespace, p_name); - if (klass) { - return klass; - } - - int32_t domain_id = mono_domain_get_id(mono_domain_get()); - HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id]; - - for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) { - GDMonoAssembly *assembly = E.value; - klass = assembly->get_class(p_namespace, p_name); - if (klass) { - return klass; - } - } - - return nullptr; -} - -void GDMono::_domain_assemblies_cleanup(int32_t p_domain_id) { - HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id]; - - for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) { - memdelete(E.value); - } - - assemblies.erase(p_domain_id); -} - -void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) { - // This method will be called by the runtime when a thrown exception is not handled. - // It won't be called when we manually treat a thrown exception as unhandled. - // We assume the exception was already printed before calling this hook. - -#ifdef DEBUG_ENABLED - GDMonoUtils::debug_send_unhandled_exception_error((MonoException *)p_exc); - if (EngineDebugger::is_active()) { - EngineDebugger::get_singleton()->poll_events(false); - } -#endif - - exit(mono_environment_exitcode_get()); - - GD_UNREACHABLE(); -} - GDMono::GDMono() { singleton = this; - gdmono_log = memnew(GDMonoLog); - runtime_initialized = false; finalizing_scripts_domain = false; - root_domain = nullptr; - scripts_domain = nullptr; - - corlib_assembly = nullptr; - project_assembly = nullptr; -#ifdef TOOLS_ENABLED - tools_assembly = nullptr; - tools_project_editor_assembly = nullptr; -#endif - api_core_hash = 0; #ifdef TOOLS_ENABLED api_editor_hash = 0; #endif - - unhandled_exception_policy = POLICY_TERMINATE_APP; } GDMono::~GDMono() { - if (is_runtime_initialized()) { -#ifndef GD_MONO_SINGLE_APPDOMAIN - if (scripts_domain) { - Error err = _unload_scripts_domain(); - if (err != OK) { - ERR_PRINT("Mono: Failed to unload scripts domain."); - } - } -#else - CRASH_COND(scripts_domain != root_domain); - - print_verbose("Mono: Finalizing scripts domain..."); - - if (mono_domain_get() != root_domain) { - mono_domain_set(root_domain, true); - } - - finalizing_scripts_domain = true; - - if (!mono_domain_finalize(root_domain, 2000)) { - ERR_PRINT("Mono: Domain finalization timeout."); - } - - finalizing_scripts_domain = false; - - mono_gc_collect(mono_gc_max_generation()); - - GDMonoCache::clear_godot_api_cache(); - - _domain_assemblies_cleanup(mono_domain_get_id(root_domain)); - - core_api_assembly.assembly = nullptr; - - project_assembly = nullptr; - - root_domain = nullptr; - scripts_domain = nullptr; - - // Leave the rest to 'mono_jit_cleanup' -#endif - - for (const KeyValue<int32_t, HashMap<String, GDMonoAssembly *>> &E : assemblies) { - const HashMap<String, GDMonoAssembly *> &domain_assemblies = E.value; + finalizing_scripts_domain = true; - for (const KeyValue<String, GDMonoAssembly *> &F : domain_assemblies) { - memdelete(F.value); - } + if (is_runtime_initialized()) { + if (GDMonoCache::godot_api_cache_updated) { + GDMonoCache::managed_callbacks.DisposablesTracker_OnGodotShuttingDown(); } - assemblies.clear(); - - print_verbose("Mono: Runtime cleanup..."); - - mono_jit_cleanup(root_domain); - - print_verbose("Mono: Finalized"); + } - runtime_initialized = false; + if (hostfxr_dll_handle) { + OS::get_singleton()->close_dynamic_library(hostfxr_dll_handle); } + finalizing_scripts_domain = false; + runtime_initialized = false; + #if defined(ANDROID_ENABLED) gdmono::android::support::cleanup(); #endif - if (gdmono_log) { - memdelete(gdmono_log); - } - singleton = nullptr; } @@ -1328,62 +593,7 @@ namespace mono_bind { GodotSharp *GodotSharp::singleton = nullptr; -void GodotSharp::attach_thread() { - GDMonoUtils::attach_current_thread(); -} - -void GodotSharp::detach_thread() { - GDMonoUtils::detach_current_thread(); -} - -int32_t GodotSharp::get_domain_id() { - MonoDomain *domain = mono_domain_get(); - 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(); - ERR_FAIL_NULL_V(domain, -1); - return mono_domain_get_id(domain); -} - -bool GodotSharp::is_scripts_domain_loaded() { - 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(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) { - 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); -} - -bool GodotSharp::is_runtime_shutting_down() { - return mono_runtime_is_shutting_down(); -} - -bool GodotSharp::is_runtime_initialized() { +bool GodotSharp::_is_runtime_initialized() { return GDMono::get_singleton() != nullptr && GDMono::get_singleton()->is_runtime_initialized(); } @@ -1399,16 +609,7 @@ void GodotSharp::_reload_assemblies(bool p_soft_reload) { } void GodotSharp::_bind_methods() { - ClassDB::bind_method(D_METHOD("attach_thread"), &GodotSharp::attach_thread); - ClassDB::bind_method(D_METHOD("detach_thread"), &GodotSharp::detach_thread); - - ClassDB::bind_method(D_METHOD("get_domain_id"), &GodotSharp::get_domain_id); - ClassDB::bind_method(D_METHOD("get_scripts_domain_id"), &GodotSharp::get_scripts_domain_id); - ClassDB::bind_method(D_METHOD("is_scripts_domain_loaded"), &GodotSharp::is_scripts_domain_loaded); - ClassDB::bind_method(D_METHOD("is_domain_finalizing_for_unload", "domain_id"), &GodotSharp::_is_domain_finalizing_for_unload); - - 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("is_runtime_initialized"), &GodotSharp::_is_runtime_initialized); ClassDB::bind_method(D_METHOD("_reload_assemblies"), &GodotSharp::_reload_assemblies); } diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 51fd0f8483..43811a4325 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -34,131 +34,54 @@ #include "core/io/config_file.h" #include "../godotsharp_defs.h" -#include "gd_mono_assembly.h" -#include "gd_mono_log.h" -#ifdef WINDOWS_ENABLED -#include "../utils/mono_reg_utils.h" +#ifdef WIN32 +#define GD_CLR_STDCALL __stdcall +#else +#define GD_CLR_STDCALL #endif -namespace ApiAssemblyInfo { -enum Type { - API_CORE, - API_EDITOR -}; - -struct Version { - uint64_t godot_api_hash = 0; - uint32_t bindings_version = 0; - uint32_t cs_glue_version = 0; - - bool operator==(const Version &p_other) const { - return godot_api_hash == p_other.godot_api_hash && - bindings_version == p_other.bindings_version && - cs_glue_version == p_other.cs_glue_version; - } - - Version() {} - - Version(uint64_t p_godot_api_hash, - uint32_t p_bindings_version, - uint32_t p_cs_glue_version) : - godot_api_hash(p_godot_api_hash), - bindings_version(p_bindings_version), - cs_glue_version(p_cs_glue_version) { - } +namespace gdmono { - static Version get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, Type p_api_type); +#ifdef TOOLS_ENABLED +struct PluginCallbacks { + using FuncLoadProjectAssemblyCallback = bool(GD_CLR_STDCALL *)(const char16_t *, String *); + using FuncLoadToolsAssemblyCallback = Object *(GD_CLR_STDCALL *)(const char16_t *, const void **, int32_t); + using FuncUnloadProjectPluginCallback = bool(GD_CLR_STDCALL *)(); + FuncLoadProjectAssemblyCallback LoadProjectAssemblyCallback = nullptr; + FuncLoadToolsAssemblyCallback LoadToolsAssemblyCallback = nullptr; + FuncUnloadProjectPluginCallback UnloadProjectPluginCallback = nullptr; }; +#endif -String to_string(Type p_type); -} // namespace ApiAssemblyInfo - -class GDMono { -public: - enum UnhandledExceptionPolicy { - POLICY_TERMINATE_APP, - POLICY_LOG_ERROR - }; - - struct LoadedApiAssembly { - GDMonoAssembly *assembly = nullptr; - bool out_of_sync = false; +} // namespace gdmono - LoadedApiAssembly() {} - }; +#undef GD_CLR_STDCALL -private: +class GDMono { bool runtime_initialized; bool finalizing_scripts_domain; - UnhandledExceptionPolicy unhandled_exception_policy; + void *hostfxr_dll_handle = nullptr; + bool is_native_aot = false; - MonoDomain *root_domain = nullptr; - MonoDomain *scripts_domain = nullptr; + String project_assembly_path; + uint64_t project_assembly_modified_time = 0; - HashMap<int32_t, HashMap<String, GDMonoAssembly *>> assemblies; - - GDMonoAssembly *corlib_assembly = nullptr; - GDMonoAssembly *project_assembly = nullptr; #ifdef TOOLS_ENABLED - GDMonoAssembly *tools_assembly = nullptr; - GDMonoAssembly *tools_project_editor_assembly = nullptr; -#endif - - LoadedApiAssembly core_api_assembly; - LoadedApiAssembly editor_api_assembly; - - typedef bool (*CoreApiAssemblyLoadedCallback)(); - - bool _are_api_assemblies_out_of_sync(); - bool _temp_domain_load_are_assemblies_out_of_sync(const String &p_config); - - bool _load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly); -#ifdef TOOLS_ENABLED - bool _load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly); -#endif - - static bool _on_core_api_assembly_loaded(); - - bool _load_corlib_assembly(); -#ifdef TOOLS_ENABLED - bool _load_tools_assemblies(); -#endif bool _load_project_assembly(); - - bool _try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly, - const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback); - bool _try_load_api_assemblies_preset(); - void _load_api_assemblies(); - - void _install_trace_listener(); - - void _register_internal_calls(); - -#ifndef GD_MONO_SINGLE_APPDOMAIN - Error _load_scripts_domain(); - Error _unload_scripts_domain(); #endif - void _domain_assemblies_cleanup(int32_t p_domain_id); - uint64_t api_core_hash; #ifdef TOOLS_ENABLED uint64_t api_editor_hash; #endif void _init_godot_api_hashes(); - void _init_exception_policy(); - - GDMonoLog *gdmono_log = nullptr; -#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) - MonoRegInfo mono_reg_info; +#ifdef TOOLS_ENABLED + gdmono::PluginCallbacks plugin_callbacks; #endif - void add_mono_shared_libs_dir_to_path(); - void determine_mono_dirs(String &r_assembly_rootdir, String &r_config_dir); - protected: static GDMono *singleton; @@ -192,107 +115,43 @@ public: #endif } -#ifdef TOOLS_ENABLED - bool copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config); - String update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync = nullptr, const bool *p_editor_api_out_of_sync = nullptr); -#endif - - static GDMono *get_singleton() { return singleton; } - - [[noreturn]] static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data); - - UnhandledExceptionPolicy get_unhandled_exception_policy() const { return unhandled_exception_policy; } - - // Do not use these, unless you know what you're doing - void add_assembly(int32_t p_domain_id, GDMonoAssembly *p_assembly); - GDMonoAssembly *get_loaded_assembly(const String &p_name); - - _FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized && !mono_runtime_is_shutting_down() /* stays true after shutdown finished */; } + static GDMono *get_singleton() { + return singleton; + } - _FORCE_INLINE_ bool is_finalizing_scripts_domain() { return finalizing_scripts_domain; } + _FORCE_INLINE_ bool is_runtime_initialized() const { + return runtime_initialized; + } + _FORCE_INLINE_ bool is_finalizing_scripts_domain() { + return finalizing_scripts_domain; + } - _FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; } + _FORCE_INLINE_ const String &get_project_assembly_path() const { + return project_assembly_path; + } + _FORCE_INLINE_ uint64_t get_project_assembly_modified_time() const { + return project_assembly_modified_time; + } - _FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; } - _FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly.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.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) - const MonoRegInfo &get_mono_reg_info() { return mono_reg_info; } + const gdmono::PluginCallbacks &get_plugin_callbacks() { + return plugin_callbacks; + } #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(); + Error reload_project_assemblies(); #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); - bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly, const Vector<String> &p_search_dirs); - bool load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly, bool p_refonly = false); - - Error finalize_and_unload_domain(MonoDomain *p_domain); - void initialize(); +#ifdef TOOLS_ENABLED void initialize_load_assemblies(); +#endif GDMono(); ~GDMono(); }; -namespace gdmono { - -class ScopeDomain { - MonoDomain *prev_domain = nullptr; - -public: - ScopeDomain(MonoDomain *p_domain) { - prev_domain = mono_domain_get(); - if (prev_domain != p_domain) { - mono_domain_set(p_domain, false); - } else { - prev_domain = nullptr; - } - } - - ~ScopeDomain() { - if (prev_domain) { - mono_domain_set(prev_domain, false); - } - } -}; - -class ScopeExitDomainUnload { - MonoDomain *domain = nullptr; - -public: - ScopeExitDomainUnload(MonoDomain *p_domain) : - domain(p_domain) { - } - - ~ScopeExitDomainUnload() { - if (domain) { - GDMono::get_singleton()->finalize_and_unload_domain(domain); - } - } -}; -} // namespace gdmono - -#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \ - gdmono::ScopeDomain __gdmono__scope__domain__(m_mono_domain); \ - (void)__gdmono__scope__domain__; - -#define _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(m_mono_domain) \ - gdmono::ScopeExitDomainUnload __gdmono__scope__exit__domain__unload__(m_mono_domain); \ - (void)__gdmono__scope__exit__domain__unload__; - namespace mono_bind { class GodotSharp : public Object { @@ -300,9 +159,8 @@ class GodotSharp : public Object { friend class GDMono; - bool _is_domain_finalizing_for_unload(int32_t p_domain_id); - void _reload_assemblies(bool p_soft_reload); + bool _is_runtime_initialized(); protected: static GodotSharp *singleton; @@ -311,20 +169,6 @@ protected: public: static GodotSharp *get_singleton() { return singleton; } - void attach_thread(); - void detach_thread(); - - int32_t get_domain_id(); - int32_t get_scripts_domain_id(); - - bool is_scripts_domain_loaded(); - - bool is_domain_finalizing_for_unload(int32_t p_domain_id); - bool is_domain_finalizing_for_unload(MonoDomain *p_domain); - - bool is_runtime_shutting_down(); - bool is_runtime_initialized(); - GodotSharp(); ~GodotSharp(); }; diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp deleted file mode 100644 index 42c6b6305f..0000000000 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ /dev/null @@ -1,482 +0,0 @@ -/*************************************************************************/ -/* gd_mono_assembly.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_assembly.h" - -#include <mono/metadata/mono-debug.h> -#include <mono/metadata/tokentype.h> - -#include "core/config/project_settings.h" -#include "core/io/file_access.h" -#include "core/io/file_access_pack.h" -#include "core/os/os.h" -#include "core/templates/list.h" - -#include "../godotsharp_dirs.h" -#include "gd_mono_cache.h" -#include "gd_mono_class.h" - -Vector<String> GDMonoAssembly::search_dirs; - -void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config, const String &p_custom_bcl_dir) { - String framework_dir; - - if (!p_custom_bcl_dir.is_empty()) { - framework_dir = p_custom_bcl_dir; - } else if (mono_assembly_getrootdir()) { - framework_dir = String::utf8(mono_assembly_getrootdir()).plus_file("mono").plus_file("4.5"); - } - - if (!framework_dir.is_empty()) { - r_search_dirs.push_back(framework_dir); - r_search_dirs.push_back(framework_dir.plus_file("Facades")); - } - -#if !defined(TOOLS_ENABLED) - String data_game_assemblies_dir = GodotSharpDirs::get_data_game_assemblies_dir(); - if (!data_game_assemblies_dir.is_empty()) { - r_search_dirs.push_back(data_game_assemblies_dir); - } -#endif - - 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()); - } - - if (p_custom_config.is_empty()) { - r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir()); - } else { - String api_config = p_custom_config == "ExportRelease" ? "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_base_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 -} - -// This is how these assembly loading hooks work: -// -// - The 'search' hook checks if the assembly has already been loaded, to avoid loading again. -// - The 'preload' hook does the actual loading and is only called if the -// 'search' hook didn't find the assembly in the list of loaded assemblies. -// - The 'load' hook is called after the assembly has been loaded. Its job is to add the -// assembly to the list of loaded assemblies so that the 'search' hook can look it up. - -void GDMonoAssembly::assembly_load_hook(MonoAssembly *assembly, [[maybe_unused]] void *user_data) { - String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly))); - - MonoImage *image = mono_assembly_get_image(assembly); - - GDMonoAssembly *gdassembly = memnew(GDMonoAssembly(name, image, assembly)); - -#ifdef GD_MONO_HOT_RELOAD - String path = String::utf8(mono_image_get_filename(image)); - if (FileAccess::exists(path)) { - gdassembly->modified_time = FileAccess::get_modified_time(path); - } -#endif - - MonoDomain *domain = mono_domain_get(); - GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, gdassembly); -} - -MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) { - 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, [[maybe_unused]] void *user_data, bool refonly) { - String name = String::utf8(mono_assembly_name_get_name(aname)); - bool has_extension = name.ends_with(".dll") || name.ends_with(".exe"); - - GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name); - if (loaded_asm) { - return loaded_asm->get_assembly(); - } - - return nullptr; -} - -MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, [[maybe_unused]] void *user_data, bool refonly) { - String name = String::utf8(mono_assembly_name_get_name(aname)); - return _load_assembly_search(name, aname, refonly, search_dirs); -} - -MonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs) { - MonoAssembly *res = nullptr; - 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 = _real_load_assembly_from(path, p_refonly, p_aname); - if (res != nullptr) { - return res; - } - } - } else { - path = search_dir.plus_file(p_name + ".dll"); - if (FileAccess::exists(path)) { - res = _real_load_assembly_from(path, p_refonly, p_aname); - if (res != nullptr) { - return res; - } - } - - path = search_dir.plus_file(p_name + ".exe"); - if (FileAccess::exists(path)) { - res = _real_load_assembly_from(path, p_refonly, p_aname); - if (res != nullptr) { - return res; - } - } - } - } - - return nullptr; -} - -String GDMonoAssembly::find_assembly(const String &p_name) { - String path; - - bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe"); - - for (int i = 0; i < search_dirs.size(); i++) { - const String &search_dir = search_dirs[i]; - - if (has_extension) { - path = search_dir.plus_file(p_name); - if (FileAccess::exists(path)) { - return path; - } - } else { - path = search_dir.plus_file(p_name + ".dll"); - if (FileAccess::exists(path)) { - return path; - } - - path = search_dir.plus_file(p_name + ".exe"); - if (FileAccess::exists(path)) { - return path; - } - } - } - - return String(); -} - -void GDMonoAssembly::initialize() { - fill_search_dirs(search_dirs); - - mono_install_assembly_search_hook(&assembly_search_hook, nullptr); - mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, nullptr); - mono_install_assembly_preload_hook(&assembly_preload_hook, nullptr); - mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, nullptr); - mono_install_assembly_load_hook(&assembly_load_hook, nullptr); -} - -MonoAssembly *GDMonoAssembly::_real_load_assembly_from(const String &p_path, bool p_refonly, MonoAssemblyName *p_aname) { - Vector<uint8_t> data = FileAccess::get_file_as_array(p_path); - ERR_FAIL_COND_V_MSG(data.is_empty(), nullptr, "Could read the assembly in the specified location"); - - String image_filename; - -#ifdef ANDROID_ENABLED - if (p_path.begins_with("res://")) { - image_filename = p_path.substr(6, p_path.length()); - } else { - image_filename = ProjectSettings::get_singleton()->globalize_path(p_path); - } -#else - // FIXME: globalize_path does not work on exported games - image_filename = ProjectSettings::get_singleton()->globalize_path(p_path); -#endif - - MonoImageOpenStatus status = MONO_IMAGE_OK; - - MonoImage *image = mono_image_open_from_data_with_name( - (char *)&data[0], data.size(), - true, &status, p_refonly, - image_filename.utf8()); - - ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !image, nullptr, "Failed to open assembly image from memory: '" + p_path + "'."); - - if (p_aname != nullptr) { - // Check assembly version - const MonoTableInfo *table = mono_image_get_table_info(image, MONO_TABLE_ASSEMBLY); - - ERR_FAIL_NULL_V(table, nullptr); - - if (mono_table_info_get_rows(table)) { - uint32_t cols[MONO_ASSEMBLY_SIZE]; - mono_metadata_decode_row(table, 0, cols, MONO_ASSEMBLY_SIZE); - - // Not sure about .NET's policy. We will only ensure major and minor are equal, and ignore build and revision. - uint16_t major = cols[MONO_ASSEMBLY_MAJOR_VERSION]; - uint16_t minor = cols[MONO_ASSEMBLY_MINOR_VERSION]; - - uint16_t required_minor; - uint16_t required_major = mono_assembly_name_get_version(p_aname, &required_minor, nullptr, nullptr); - - if (required_major != 0) { - if (major != required_major && minor != required_minor) { - mono_image_close(image); - return nullptr; - } - } - } - } - -#ifdef DEBUG_ENABLED - Vector<uint8_t> pdb_data; - String pdb_path(p_path + ".pdb"); - - if (!FileAccess::exists(pdb_path)) { - pdb_path = p_path.get_basename() + ".pdb"; // without .dll - - if (!FileAccess::exists(pdb_path)) { - goto no_pdb; - } - } - - pdb_data = FileAccess::get_file_as_array(pdb_path); - - // mono_debug_close_image doesn't seem to be needed - mono_debug_open_image_from_memory(image, &pdb_data[0], pdb_data.size()); - -no_pdb: - -#endif - - bool need_manual_load_hook = mono_image_get_assembly(image) != nullptr; // Re-using an existing image with an assembly loaded - - status = MONO_IMAGE_OK; - - MonoAssembly *assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, p_refonly); - - ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !assembly, nullptr, "Failed to load assembly for image"); - - if (need_manual_load_hook) { - // For some reason if an assembly survived domain reloading (maybe because it's referenced somewhere else), - // the mono internal search hook don't detect it, yet mono_image_open_from_data_with_name re-uses the image - // and assembly, and mono_assembly_load_from_full doesn't call the load hook. We need to call it manually. - String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly))); - bool has_extension = name.ends_with(".dll") || name.ends_with(".exe"); - GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name); - if (!loaded_asm) { - assembly_load_hook(assembly, nullptr); - } - } - - // Decrement refcount which was previously incremented by mono_image_open_from_data_with_name - mono_image_close(image); - - return assembly; -} - -void GDMonoAssembly::unload() { - ERR_FAIL_NULL(image); // Should not be called if already unloaded - - for (const KeyValue<MonoClass *, GDMonoClass *> &E : cached_raw) { - memdelete(E.value); - } - - cached_classes.clear(); - cached_raw.clear(); - - assembly = nullptr; - image = nullptr; -} - -String GDMonoAssembly::get_path() const { - return String::utf8(mono_image_get_filename(image)); -} - -bool GDMonoAssembly::has_attribute(GDMonoClass *p_attr_class) { -#ifdef DEBUG_ENABLED - ERR_FAIL_NULL_V(p_attr_class, false); -#endif - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return false; - } - - return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr()); -} - -MonoObject *GDMonoAssembly::get_attribute(GDMonoClass *p_attr_class) { -#ifdef DEBUG_ENABLED - ERR_FAIL_NULL_V(p_attr_class, nullptr); -#endif - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return nullptr; - } - - return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr()); -} - -void GDMonoAssembly::fetch_attributes() { - ERR_FAIL_COND(attributes != nullptr); - - attributes = mono_custom_attrs_from_assembly(assembly); - attrs_fetched = true; -} - -GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const StringName &p_name) { - ERR_FAIL_NULL_V(image, nullptr); - - 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 nullptr; - } - - 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_NULL_V(image, nullptr); - - HashMap<MonoClass *, GDMonoClass *>::Iterator match = cached_raw.find(p_mono_class); - - if (match) { - return match->value; - } - - StringName namespace_name = String::utf8(mono_class_get_namespace(p_mono_class)); - StringName class_name = String::utf8(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; -} - -GDMonoAssembly *GDMonoAssembly::load(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs) { - if (GDMono::get_singleton()->get_corlib_assembly() && (p_name == "mscorlib" || p_name == "mscorlib.dll")) { - return GDMono::get_singleton()->get_corlib_assembly(); - } - - // We need to manually call the search hook in this case, as it won't be called in the next step - MonoAssembly *assembly = mono_assembly_invoke_search_hook(p_aname); - - if (!assembly) { - assembly = _load_assembly_search(p_name, p_aname, p_refonly, p_search_dirs); - if (!assembly) { - return nullptr; - } - } - - GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name); - ERR_FAIL_NULL_V_MSG(loaded_asm, nullptr, "Loaded assembly missing from table. Did we not receive the load hook?"); - ERR_FAIL_COND_V(loaded_asm->get_assembly() != assembly, nullptr); - - return loaded_asm; -} - -GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) { - if (p_name == "mscorlib" || p_name == "mscorlib.dll") { - return GDMono::get_singleton()->get_corlib_assembly(); - } - - // We need to manually call the search hook in this case, as it won't be called in the next step - MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8()); - MonoAssembly *assembly = mono_assembly_invoke_search_hook(aname); - mono_assembly_name_free(aname); - mono_free(aname); - - if (!assembly) { - assembly = _real_load_assembly_from(p_path, p_refonly); - if (!assembly) { - return nullptr; - } - } - - GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name); - ERR_FAIL_NULL_V_MSG(loaded_asm, nullptr, "Loaded assembly missing from table. Did we not receive the load hook?"); - - return loaded_asm; -} - -GDMonoAssembly::~GDMonoAssembly() { - if (image) { - unload(); - } -} diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h deleted file mode 100644 index 0a3ae6c4fe..0000000000 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************/ -/* gd_mono_assembly.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_ASSEMBLY_H -#define GD_MONO_ASSEMBLY_H - -#include <mono/jit/jit.h> -#include <mono/metadata/assembly.h> - -#include "core/string/ustring.h" -#include "core/templates/hash_map.h" -#include "core/templates/rb_map.h" -#include "gd_mono_utils.h" - -class GDMonoAssembly { - struct ClassKey { - struct Hasher { - static _FORCE_INLINE_ uint32_t hash(const ClassKey &p_key) { - uint32_t hash = 0; - - GDMonoUtils::hash_combine(hash, p_key.namespace_name.hash()); - GDMonoUtils::hash_combine(hash, p_key.class_name.hash()); - - return hash; - } - }; - - _FORCE_INLINE_ bool operator==(const ClassKey &p_a) const { - return p_a.class_name == class_name && p_a.namespace_name == namespace_name; - } - - ClassKey() {} - - ClassKey(const StringName &p_namespace_name, const StringName &p_class_name) { - namespace_name = p_namespace_name; - class_name = p_class_name; - } - - StringName namespace_name; - StringName class_name; - }; - - String name; - MonoImage *image = nullptr; - MonoAssembly *assembly = nullptr; - - bool attrs_fetched = false; - MonoCustomAttrInfo *attributes = nullptr; - -#ifdef GD_MONO_HOT_RELOAD - uint64_t modified_time = 0; -#endif - - HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes; - HashMap<MonoClass *, GDMonoClass *> cached_raw; - - static Vector<String> search_dirs; - - static void assembly_load_hook(MonoAssembly *assembly, 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 *_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly); - static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly); - - static MonoAssembly *_real_load_assembly_from(const String &p_path, bool p_refonly, MonoAssemblyName *p_aname = nullptr); - static MonoAssembly *_load_assembly_search(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs); - - friend class GDMono; - static void initialize(); - -public: - void unload(); - - _FORCE_INLINE_ MonoImage *get_image() const { return image; } - _FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; } - _FORCE_INLINE_ String get_name() const { return name; } - -#ifdef GD_MONO_HOT_RELOAD - _FORCE_INLINE_ uint64_t get_modified_time() const { return modified_time; } -#endif - - String get_path() const; - - bool has_attribute(GDMonoClass *p_attr_class); - MonoObject *get_attribute(GDMonoClass *p_attr_class); - - void fetch_attributes(); - - GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name); - GDMonoClass *get_class(MonoClass *p_mono_class); - - static String find_assembly(const String &p_name); - - static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String(), const String &p_custom_bcl_dir = String()); - static const Vector<String> &get_default_search_dirs() { return search_dirs; } - - static GDMonoAssembly *load(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs); - static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly); - - GDMonoAssembly(const String &p_name, MonoImage *p_image, MonoAssembly *p_assembly) : - name(p_name), - image(p_image), - assembly(p_assembly) { - } - ~GDMonoAssembly(); -}; - -#endif // GD_MONO_ASSEMBLY_H diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index 69d8c7edc9..bfd803f326 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -30,310 +30,66 @@ #include "gd_mono_cache.h" -#include "gd_mono.h" -#include "gd_mono_class.h" -#include "gd_mono_marshal.h" -#include "gd_mono_method.h" -#include "gd_mono_utils.h" +#include "core/error/error_macros.h" namespace GDMonoCache { -CachedData cached_data; +ManagedCallbacks managed_callbacks; +bool godot_api_cache_updated = false; -#define CACHE_AND_CHECK(m_var, m_val) \ - { \ - CRASH_COND(m_var != nullptr); \ - m_var = m_val; \ - ERR_FAIL_COND_MSG(m_var == nullptr, "Mono Cache: Member " #m_var " is null."); \ - } - -#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_class, m_val) -#define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_ns##_##m_class, m_val) -#define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.rawclass_##m_class, m_val) -#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(cached_data.field_##m_class##_##m_field, m_val) -#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(cached_data.method_##m_class##_##m_method, m_val) -#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(cached_data.property_##m_class##_##m_property, m_val) +void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) { + int checked_count = 0; -#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \ - { \ - CRASH_COND(!m_var.is_null()); \ - ERR_FAIL_COND_MSG(m_val == nullptr, "Mono Cache: Method for member " #m_var " is null."); \ - m_var.set_from_method(m_val); \ - ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \ +#define CHECK_CALLBACK_NOT_NULL_IMPL(m_var, m_class, m_method) \ + { \ + ERR_FAIL_COND_MSG(m_var == nullptr, \ + "Mono Cache: Managed callback for '" #m_class "_" #m_method "' is null."); \ + checked_count += 1; \ } -#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_METHOD_THUNK_AND_CHECK_IMPL(cached_data.methodthunk_##m_class##_##m_method, m_val) - -void CachedData::clear_corlib_cache() { - corlib_cache_updated = false; - - class_MonoObject = nullptr; - class_bool = nullptr; - class_int8_t = nullptr; - class_int16_t = nullptr; - class_int32_t = nullptr; - class_int64_t = nullptr; - class_uint8_t = nullptr; - class_uint16_t = nullptr; - class_uint32_t = nullptr; - class_uint64_t = nullptr; - class_float = nullptr; - class_double = nullptr; - class_String = nullptr; - class_IntPtr = nullptr; - - class_System_Collections_IEnumerable = nullptr; - class_System_Collections_ICollection = nullptr; - class_System_Collections_IDictionary = nullptr; - -#ifdef DEBUG_ENABLED - class_System_Diagnostics_StackTrace = nullptr; - methodthunk_System_Diagnostics_StackTrace_GetFrames.nullify(); - method_System_Diagnostics_StackTrace_ctor_bool = nullptr; - method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr; -#endif - - class_KeyNotFoundException = nullptr; -} - -void CachedData::clear_godot_api_cache() { - godot_api_cache_updated = false; - - rawclass_Dictionary = nullptr; - - class_Vector2 = nullptr; - class_Vector2i = nullptr; - class_Rect2 = nullptr; - class_Rect2i = nullptr; - class_Transform2D = nullptr; - class_Vector3 = nullptr; - class_Vector3i = nullptr; - class_Vector4 = nullptr; - class_Vector4i = nullptr; - class_Basis = nullptr; - class_Quaternion = nullptr; - class_Transform3D = nullptr; - class_Projection = nullptr; - class_AABB = nullptr; - class_Color = nullptr; - class_Plane = nullptr; - class_StringName = nullptr; - class_NodePath = nullptr; - class_RID = nullptr; - class_GodotObject = nullptr; - class_GodotResource = nullptr; - class_Node = nullptr; - class_Control = nullptr; - class_Node3D = nullptr; - class_WeakRef = nullptr; - class_Callable = nullptr; - class_SignalInfo = nullptr; - class_Array = nullptr; - class_Dictionary = nullptr; - class_MarshalUtils = nullptr; - class_ISerializationListener = nullptr; - -#ifdef DEBUG_ENABLED - class_DebuggingUtils = nullptr; - methodthunk_DebuggingUtils_GetStackFrameInfo.nullify(); -#endif - - class_ExportAttribute = nullptr; - field_ExportAttribute_hint = nullptr; - field_ExportAttribute_hintString = nullptr; - class_SignalAttribute = nullptr; - class_ToolAttribute = nullptr; - class_RPCAttribute = nullptr; - property_RPCAttribute_Mode = nullptr; - property_RPCAttribute_CallLocal = nullptr; - property_RPCAttribute_TransferMode = nullptr; - property_RPCAttribute_TransferChannel = nullptr; - class_GodotMethodAttribute = nullptr; - field_GodotMethodAttribute_methodName = nullptr; - class_ScriptPathAttribute = nullptr; - field_ScriptPathAttribute_path = nullptr; - class_AssemblyHasScriptsAttribute = nullptr; - field_AssemblyHasScriptsAttribute_requiresLookup = nullptr; - field_AssemblyHasScriptsAttribute_scriptTypes = nullptr; - - field_GodotObject_ptr = nullptr; - field_StringName_ptr = nullptr; - field_NodePath_ptr = nullptr; - field_Image_ptr = nullptr; - field_RID_ptr = nullptr; - - methodthunk_GodotObject_Dispose.nullify(); - methodthunk_Array_GetPtr.nullify(); - methodthunk_Dictionary_GetPtr.nullify(); - methodthunk_SignalAwaiter_SignalCallback.nullify(); - methodthunk_GodotTaskScheduler_Activate.nullify(); - - methodthunk_Delegate_Equals.nullify(); - - methodthunk_DelegateUtils_TrySerializeDelegate.nullify(); - methodthunk_DelegateUtils_TryDeserializeDelegate.nullify(); - - // Start of MarshalUtils methods - - methodthunk_MarshalUtils_TypeIsGenericArray.nullify(); - methodthunk_MarshalUtils_TypeIsGenericDictionary.nullify(); - methodthunk_MarshalUtils_TypeIsSystemGenericList.nullify(); - methodthunk_MarshalUtils_TypeIsSystemGenericDictionary.nullify(); - methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify(); - methodthunk_MarshalUtils_TypeIsGenericICollection.nullify(); - methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify(); - methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify(); - - methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify(); - - methodthunk_MarshalUtils_ArrayGetElementType.nullify(); - methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify(); - - methodthunk_MarshalUtils_MakeGenericArrayType.nullify(); - methodthunk_MarshalUtils_MakeGenericDictionaryType.nullify(); - - // End of MarshalUtils methods - - task_scheduler_handle = Ref<MonoGCHandleRef>(); -} - -#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class)) -#define GODOT_API_NS_CLASS(m_ns, m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(m_ns, #m_class)) - -void update_corlib_cache() { - CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class())); - CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class())); - CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class())); - CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class())); - CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class())); - CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class())); - CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class())); - CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class())); - CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class())); - CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class())); - CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class())); - CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class())); - CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class())); - CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class())); - - CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable")); - CACHE_CLASS_AND_CHECK(System_Collections_ICollection, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "ICollection")); - CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary")); - -#ifdef DEBUG_ENABLED - CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace")); - CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method("GetFrames")); - CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true)); - CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true)); -#endif - - CACHE_METHOD_THUNK_AND_CHECK(Delegate, Equals, GDMono::get_singleton()->get_corlib_assembly()->get_class("System", "Delegate")->get_method_with_desc("System.Delegate:Equals(object)", true)); - - CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException")); - - cached_data.corlib_cache_updated = true; -} - -void update_godot_api_cache() { - CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2)); - CACHE_CLASS_AND_CHECK(Vector2i, GODOT_API_CLASS(Vector2i)); - CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2)); - CACHE_CLASS_AND_CHECK(Rect2i, GODOT_API_CLASS(Rect2i)); - CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D)); - CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3)); - CACHE_CLASS_AND_CHECK(Vector3i, GODOT_API_CLASS(Vector3i)); - CACHE_CLASS_AND_CHECK(Vector4, GODOT_API_CLASS(Vector4)); - CACHE_CLASS_AND_CHECK(Vector4i, GODOT_API_CLASS(Vector4i)); - CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis)); - CACHE_CLASS_AND_CHECK(Quaternion, GODOT_API_CLASS(Quaternion)); - CACHE_CLASS_AND_CHECK(Transform3D, GODOT_API_CLASS(Transform3D)); - CACHE_CLASS_AND_CHECK(Projection, GODOT_API_CLASS(Projection)); - CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB)); - CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color)); - CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane)); - CACHE_CLASS_AND_CHECK(StringName, GODOT_API_CLASS(StringName)); - CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath)); - CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID)); - CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object)); - CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource)); - CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node)); - CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control)); - CACHE_CLASS_AND_CHECK(Node3D, GODOT_API_CLASS(Node3D)); - CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef)); - CACHE_CLASS_AND_CHECK(Callable, GODOT_API_CLASS(Callable)); - CACHE_CLASS_AND_CHECK(SignalInfo, GODOT_API_CLASS(SignalInfo)); - CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array)); - CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLASS(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)); -#endif - - // Attributes - CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute)); - CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint")); - CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString")); - CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute)); - CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute)); - CACHE_CLASS_AND_CHECK(RPCAttribute, GODOT_API_CLASS(RPCAttribute)); - CACHE_PROPERTY_AND_CHECK(RPCAttribute, Mode, CACHED_CLASS(RPCAttribute)->get_property("Mode")); - CACHE_PROPERTY_AND_CHECK(RPCAttribute, CallLocal, CACHED_CLASS(RPCAttribute)->get_property("CallLocal")); - CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferMode, CACHED_CLASS(RPCAttribute)->get_property("TransferMode")); - CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferChannel, CACHED_CLASS(RPCAttribute)->get_property("TransferChannel")); - CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute)); - CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName")); - CACHE_CLASS_AND_CHECK(ScriptPathAttribute, GODOT_API_CLASS(ScriptPathAttribute)); - CACHE_FIELD_AND_CHECK(ScriptPathAttribute, path, CACHED_CLASS(ScriptPathAttribute)->get_field("path")); - CACHE_CLASS_AND_CHECK(AssemblyHasScriptsAttribute, GODOT_API_CLASS(AssemblyHasScriptsAttribute)); - CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, requiresLookup, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("requiresLookup")); - CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, scriptTypes, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("scriptTypes")); - - CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD)); - CACHE_FIELD_AND_CHECK(StringName, ptr, CACHED_CLASS(StringName)->get_field(BINDINGS_PTR_FIELD)); - CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD)); - CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD)); - - CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, CACHED_CLASS(GodotObject)->get_method("Dispose", 0)); - CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method("GetPtr", 0)); - CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method("GetPtr", 0)); - CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)); - CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)); - - CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TrySerializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TrySerializeDelegate", 2)); - CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TryDeserializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TryDeserializeDelegate", 2)); - - // Start of MarshalUtils methods - - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericArray", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericDictionary", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericList, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericList", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericDictionary", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIEnumerable, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIEnumerable", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeHasFlagsAttribute, GODOT_API_CLASS(MarshalUtils)->get_method("TypeHasFlagsAttribute", 1)); - - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2)); - - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3)); - - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericArrayType", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericDictionaryType", 2)); - - // End of MarshalUtils methods - -#ifdef DEBUG_ENABLED - CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)); -#endif - - // TODO Move to CSharpLanguage::init() and do handle disposal - 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)); - cached_data.task_scheduler_handle = MonoGCHandleRef::create_strong(task_scheduler); +#define CHECK_CALLBACK_NOT_NULL(m_class, m_method) CHECK_CALLBACK_NOT_NULL_IMPL(p_managed_callbacks.m_class##_##m_method, m_class, m_method) + + CHECK_CALLBACK_NOT_NULL(SignalAwaiter, SignalCallback); + CHECK_CALLBACK_NOT_NULL(DelegateUtils, InvokeWithVariantArgs); + CHECK_CALLBACK_NOT_NULL(DelegateUtils, DelegateEquals); + CHECK_CALLBACK_NOT_NULL(DelegateUtils, TrySerializeDelegateWithGCHandle); + CHECK_CALLBACK_NOT_NULL(DelegateUtils, TryDeserializeDelegateWithGCHandle); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, FrameCallback); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, CreateManagedForGodotObjectBinding); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, CreateManagedForGodotObjectScriptInstance); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetScriptNativeName); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SetGodotObjectPtr); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RaiseEventSignal); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, ScriptIsOrInherits); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, AddScriptBridge); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetOrCreateScriptBridgeForPath); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RemoveScriptBridge); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, TryReloadRegisteredScriptWithClass); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, UpdateScriptClassInfo); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SwapGCHandleForType); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyInfoList); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyDefaultValues); + CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Call); + CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Set); + CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Get); + CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, CallDispose); + CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, CallToString); + CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, HasMethodUnknownParams); + CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, SerializeState); + CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, DeserializeState); + CHECK_CALLBACK_NOT_NULL(GCHandleBridge, FreeGCHandle); + CHECK_CALLBACK_NOT_NULL(DebuggingUtils, GetCurrentStackInfo); + CHECK_CALLBACK_NOT_NULL(DisposablesTracker, OnGodotShuttingDown); + CHECK_CALLBACK_NOT_NULL(GD, OnCoreApiAssemblyLoaded); + + managed_callbacks = p_managed_callbacks; + + // It's easy to forget to add new callbacks here, so this should help + if (checked_count * sizeof(void *) != sizeof(ManagedCallbacks)) { + int missing_count = (sizeof(ManagedCallbacks) / sizeof(void *)) - checked_count; + WARN_PRINT("The presence of " + itos(missing_count) + " callback(s) was not validated"); + } - cached_data.godot_api_cache_updated = true; + godot_api_cache_updated = true; } } // namespace GDMonoCache diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index e9cc26899e..ca3a6c95a7 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -31,174 +31,120 @@ #ifndef GD_MONO_CACHE_H #define GD_MONO_CACHE_H -#include "gd_mono_header.h" -#include "gd_mono_method_thunk.h" +#include <stdint.h> + +#include "../csharp_script.h" +#include "../interop_types.h" +#include "../mono_gc_handle.h" +#include "core/object/object.h" +#include "core/string/string_name.h" +#include "core/string/ustring.h" +#include "core/variant/callable.h" +#include "core/variant/dictionary.h" +#include "core/variant/variant.h" + +class CSharpScript; namespace GDMonoCache { -struct CachedData { - // ----------------------------------------------- - // corlib classes - - // Let's use the no-namespace format for these too - GDMonoClass *class_MonoObject = nullptr; // object - GDMonoClass *class_bool = nullptr; // bool - GDMonoClass *class_int8_t = nullptr; // sbyte - GDMonoClass *class_int16_t = nullptr; // short - GDMonoClass *class_int32_t = nullptr; // int - GDMonoClass *class_int64_t = nullptr; // long - GDMonoClass *class_uint8_t = nullptr; // byte - GDMonoClass *class_uint16_t = nullptr; // ushort - GDMonoClass *class_uint32_t = nullptr; // uint - GDMonoClass *class_uint64_t = nullptr; // ulong - GDMonoClass *class_float = nullptr; // float - GDMonoClass *class_double = nullptr; // double - GDMonoClass *class_String = nullptr; // string - GDMonoClass *class_IntPtr = nullptr; // System.IntPtr - - GDMonoClass *class_System_Collections_IEnumerable = nullptr; - GDMonoClass *class_System_Collections_ICollection = nullptr; - GDMonoClass *class_System_Collections_IDictionary = nullptr; - -#ifdef DEBUG_ENABLED - GDMonoClass *class_System_Diagnostics_StackTrace = nullptr; - GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames; - GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool = nullptr; - GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr; +#ifdef WIN32 +#define GD_CLR_STDCALL __stdcall +#else +#define GD_CLR_STDCALL #endif - GDMonoClass *class_KeyNotFoundException = nullptr; - - MonoClass *rawclass_Dictionary = nullptr; - // ----------------------------------------------- - - GDMonoClass *class_Vector2 = nullptr; - GDMonoClass *class_Vector2i = nullptr; - GDMonoClass *class_Rect2 = nullptr; - GDMonoClass *class_Rect2i = nullptr; - GDMonoClass *class_Transform2D = nullptr; - GDMonoClass *class_Vector3 = nullptr; - GDMonoClass *class_Vector3i = nullptr; - GDMonoClass *class_Vector4 = nullptr; - GDMonoClass *class_Vector4i = nullptr; - GDMonoClass *class_Basis = nullptr; - GDMonoClass *class_Quaternion = nullptr; - GDMonoClass *class_Transform3D = nullptr; - GDMonoClass *class_Projection = nullptr; - GDMonoClass *class_AABB = nullptr; - GDMonoClass *class_Color = nullptr; - GDMonoClass *class_Plane = nullptr; - GDMonoClass *class_StringName = nullptr; - GDMonoClass *class_NodePath = nullptr; - GDMonoClass *class_RID = nullptr; - GDMonoClass *class_GodotObject = nullptr; - GDMonoClass *class_GodotResource = nullptr; - GDMonoClass *class_Node = nullptr; - GDMonoClass *class_Control = nullptr; - GDMonoClass *class_Node3D = nullptr; - GDMonoClass *class_WeakRef = nullptr; - GDMonoClass *class_Callable = nullptr; - GDMonoClass *class_SignalInfo = nullptr; - GDMonoClass *class_Array = nullptr; - GDMonoClass *class_Dictionary = nullptr; - GDMonoClass *class_MarshalUtils = nullptr; - GDMonoClass *class_ISerializationListener = nullptr; - -#ifdef DEBUG_ENABLED - GDMonoClass *class_DebuggingUtils = nullptr; - GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo; -#endif +struct godotsharp_property_info { + godot_string_name name; // Not owned + godot_string hint_string; + Variant::Type type; + PropertyHint hint; + PropertyUsageFlags usage; + bool exported; +}; - GDMonoClass *class_ExportAttribute = nullptr; - GDMonoField *field_ExportAttribute_hint = nullptr; - GDMonoField *field_ExportAttribute_hintString = nullptr; - GDMonoClass *class_SignalAttribute = nullptr; - GDMonoClass *class_ToolAttribute = nullptr; - GDMonoClass *class_RPCAttribute = nullptr; - GDMonoProperty *property_RPCAttribute_Mode = nullptr; - GDMonoProperty *property_RPCAttribute_CallLocal = nullptr; - GDMonoProperty *property_RPCAttribute_TransferMode = nullptr; - GDMonoProperty *property_RPCAttribute_TransferChannel = nullptr; - GDMonoClass *class_GodotMethodAttribute = nullptr; - GDMonoField *field_GodotMethodAttribute_methodName = nullptr; - GDMonoClass *class_ScriptPathAttribute = nullptr; - GDMonoField *field_ScriptPathAttribute_path = nullptr; - GDMonoClass *class_AssemblyHasScriptsAttribute = nullptr; - GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup = nullptr; - GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes = nullptr; - - GDMonoField *field_GodotObject_ptr = nullptr; - GDMonoField *field_StringName_ptr = nullptr; - GDMonoField *field_NodePath_ptr = nullptr; - GDMonoField *field_Image_ptr = nullptr; - GDMonoField *field_RID_ptr = nullptr; - - GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose; - GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr; - GDMonoMethodThunkR<Dictionary *, MonoObject *> methodthunk_Dictionary_GetPtr; - GDMonoMethodThunk<MonoObject *, MonoArray *> methodthunk_SignalAwaiter_SignalCallback; - GDMonoMethodThunk<MonoObject *> methodthunk_GodotTaskScheduler_Activate; - - GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoObject *> methodthunk_Delegate_Equals; - - GDMonoMethodThunkR<MonoBoolean, MonoDelegate *, MonoObject *> methodthunk_DelegateUtils_TrySerializeDelegate; - GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoDelegate **> methodthunk_DelegateUtils_TryDeserializeDelegate; - - // Start of MarshalUtils methods - - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericArray; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericDictionary; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericList; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericDictionary; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary; - GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute; - - GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition; - - GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType; - GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes; - - GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericArrayType; - GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericDictionaryType; - - // End of MarshalUtils methods - - Ref<MonoGCHandleRef> task_scheduler_handle; - - bool corlib_cache_updated; - bool godot_api_cache_updated; - - void clear_corlib_cache(); - void clear_godot_api_cache(); - - CachedData() { - clear_corlib_cache(); - clear_godot_api_cache(); - } +struct godotsharp_property_def_val_pair { + godot_string_name name; // Not owned + godot_variant value; }; -extern CachedData cached_data; +struct ManagedCallbacks { + using Callback_ScriptManagerBridge_GetPropertyInfoList_Add = void(GD_CLR_STDCALL *)(CSharpScript *p_script, const String *, godotsharp_property_info *p_props, int32_t p_count); + using Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add = void(GD_CLR_STDCALL *)(CSharpScript *p_script, godotsharp_property_def_val_pair *p_def_vals, int32_t p_count); + + using FuncSignalAwaiter_SignalCallback = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, int32_t, bool *); + using FuncDelegateUtils_InvokeWithVariantArgs = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, uint32_t, const Variant *); + using FuncDelegateUtils_DelegateEquals = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr); + using FuncDelegateUtils_TrySerializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const Array *); + using FuncDelegateUtils_TryDeserializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(const Array *, GCHandleIntPtr *); + using FuncScriptManagerBridge_FrameCallback = void(GD_CLR_STDCALL *)(); + using FuncScriptManagerBridge_CreateManagedForGodotObjectBinding = GCHandleIntPtr(GD_CLR_STDCALL *)(const StringName *, Object *); + using FuncScriptManagerBridge_CreateManagedForGodotObjectScriptInstance = bool(GD_CLR_STDCALL *)(const CSharpScript *, Object *, const Variant **, int32_t); + using FuncScriptManagerBridge_GetScriptNativeName = void(GD_CLR_STDCALL *)(const CSharpScript *, StringName *); + using FuncScriptManagerBridge_SetGodotObjectPtr = void(GD_CLR_STDCALL *)(GCHandleIntPtr, Object *); + using FuncScriptManagerBridge_RaiseEventSignal = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int32_t, bool *); + using FuncScriptManagerBridge_ScriptIsOrInherits = bool(GD_CLR_STDCALL *)(const CSharpScript *, const CSharpScript *); + using FuncScriptManagerBridge_AddScriptBridge = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *); + using FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath = void(GD_CLR_STDCALL *)(const String *, Ref<CSharpScript> *); + using FuncScriptManagerBridge_RemoveScriptBridge = void(GD_CLR_STDCALL *)(const CSharpScript *); + using FuncScriptManagerBridge_TryReloadRegisteredScriptWithClass = bool(GD_CLR_STDCALL *)(const CSharpScript *); + using FuncScriptManagerBridge_UpdateScriptClassInfo = void(GD_CLR_STDCALL *)(const CSharpScript *, bool *, Array *, Dictionary *, Dictionary *, Ref<CSharpScript> *); + using FuncScriptManagerBridge_SwapGCHandleForType = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr *, bool); + using FuncScriptManagerBridge_GetPropertyInfoList = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyInfoList_Add); + using FuncScriptManagerBridge_GetPropertyDefaultValues = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add); + using FuncCSharpInstanceBridge_Call = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int32_t, Callable::CallError *, Variant *); + using FuncCSharpInstanceBridge_Set = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant *); + using FuncCSharpInstanceBridge_Get = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, Variant *); + using FuncCSharpInstanceBridge_CallDispose = void(GD_CLR_STDCALL *)(GCHandleIntPtr, bool); + using FuncCSharpInstanceBridge_CallToString = void(GD_CLR_STDCALL *)(GCHandleIntPtr, String *, bool *); + using FuncCSharpInstanceBridge_HasMethodUnknownParams = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *); + using FuncCSharpInstanceBridge_SerializeState = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Dictionary *, const Dictionary *); + using FuncCSharpInstanceBridge_DeserializeState = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Dictionary *, const Dictionary *); + using FuncGCHandleBridge_FreeGCHandle = void(GD_CLR_STDCALL *)(GCHandleIntPtr); + using FuncDebuggingUtils_GetCurrentStackInfo = void(GD_CLR_STDCALL *)(Vector<ScriptLanguage::StackInfo> *); + using FuncDisposablesTracker_OnGodotShuttingDown = void(GD_CLR_STDCALL *)(); + using FuncGD_OnCoreApiAssemblyLoaded = void(GD_CLR_STDCALL *)(bool); + + FuncSignalAwaiter_SignalCallback SignalAwaiter_SignalCallback; + FuncDelegateUtils_InvokeWithVariantArgs DelegateUtils_InvokeWithVariantArgs; + FuncDelegateUtils_DelegateEquals DelegateUtils_DelegateEquals; + FuncDelegateUtils_TrySerializeDelegateWithGCHandle DelegateUtils_TrySerializeDelegateWithGCHandle; + FuncDelegateUtils_TryDeserializeDelegateWithGCHandle DelegateUtils_TryDeserializeDelegateWithGCHandle; + FuncScriptManagerBridge_FrameCallback ScriptManagerBridge_FrameCallback; + FuncScriptManagerBridge_CreateManagedForGodotObjectBinding ScriptManagerBridge_CreateManagedForGodotObjectBinding; + FuncScriptManagerBridge_CreateManagedForGodotObjectScriptInstance ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance; + FuncScriptManagerBridge_GetScriptNativeName ScriptManagerBridge_GetScriptNativeName; + FuncScriptManagerBridge_SetGodotObjectPtr ScriptManagerBridge_SetGodotObjectPtr; + FuncScriptManagerBridge_RaiseEventSignal ScriptManagerBridge_RaiseEventSignal; + FuncScriptManagerBridge_ScriptIsOrInherits ScriptManagerBridge_ScriptIsOrInherits; + FuncScriptManagerBridge_AddScriptBridge ScriptManagerBridge_AddScriptBridge; + FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath ScriptManagerBridge_GetOrCreateScriptBridgeForPath; + FuncScriptManagerBridge_RemoveScriptBridge ScriptManagerBridge_RemoveScriptBridge; + FuncScriptManagerBridge_TryReloadRegisteredScriptWithClass ScriptManagerBridge_TryReloadRegisteredScriptWithClass; + FuncScriptManagerBridge_UpdateScriptClassInfo ScriptManagerBridge_UpdateScriptClassInfo; + FuncScriptManagerBridge_SwapGCHandleForType ScriptManagerBridge_SwapGCHandleForType; + FuncScriptManagerBridge_GetPropertyInfoList ScriptManagerBridge_GetPropertyInfoList; + FuncScriptManagerBridge_GetPropertyDefaultValues ScriptManagerBridge_GetPropertyDefaultValues; + FuncCSharpInstanceBridge_Call CSharpInstanceBridge_Call; + FuncCSharpInstanceBridge_Set CSharpInstanceBridge_Set; + FuncCSharpInstanceBridge_Get CSharpInstanceBridge_Get; + FuncCSharpInstanceBridge_CallDispose CSharpInstanceBridge_CallDispose; + FuncCSharpInstanceBridge_CallToString CSharpInstanceBridge_CallToString; + FuncCSharpInstanceBridge_HasMethodUnknownParams CSharpInstanceBridge_HasMethodUnknownParams; + FuncCSharpInstanceBridge_SerializeState CSharpInstanceBridge_SerializeState; + FuncCSharpInstanceBridge_DeserializeState CSharpInstanceBridge_DeserializeState; + FuncGCHandleBridge_FreeGCHandle GCHandleBridge_FreeGCHandle; + FuncDebuggingUtils_GetCurrentStackInfo DebuggingUtils_GetCurrentStackInfo; + FuncDisposablesTracker_OnGodotShuttingDown DisposablesTracker_OnGodotShuttingDown; + FuncGD_OnCoreApiAssemblyLoaded GD_OnCoreApiAssemblyLoaded; +}; -void update_corlib_cache(); -void update_godot_api_cache(); +extern ManagedCallbacks managed_callbacks; +extern bool godot_api_cache_updated; -inline void clear_corlib_cache() { - cached_data.clear_corlib_cache(); -} +void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks); -inline void clear_godot_api_cache() { - cached_data.clear_godot_api_cache(); -} } // namespace GDMonoCache -#define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class) -#define CACHED_CLASS_RAW(m_class) (GDMonoCache::cached_data.class_##m_class->get_mono_ptr()) -#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoCache::cached_data.rawclass_##m_class) -#define CACHED_FIELD(m_class, m_field) (GDMonoCache::cached_data.field_##m_class##_##m_field) -#define CACHED_METHOD(m_class, m_method) (GDMonoCache::cached_data.method_##m_class##_##m_method) -#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoCache::cached_data.methodthunk_##m_class##_##m_method) -#define CACHED_PROPERTY(m_class, m_property) (GDMonoCache::cached_data.property_##m_class##_##m_property) +#undef GD_CLR_STDCALL #endif // GD_MONO_CACHE_H diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp deleted file mode 100644 index 51c5aa3542..0000000000 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/*************************************************************************/ -/* gd_mono_class.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_class.h" - -#include <mono/metadata/attrdefs.h> -#include <mono/metadata/debug-helpers.h> - -#include "gd_mono_assembly.h" -#include "gd_mono_cache.h" -#include "gd_mono_marshal.h" - -String GDMonoClass::get_full_name(MonoClass *p_mono_class) { - // mono_type_get_full_name is not exposed to embedders, but this seems to do the job - MonoReflectionType *type_obj = mono_type_get_object(mono_domain_get(), get_mono_type(p_mono_class)); - - MonoException *exc = nullptr; - MonoString *str = GDMonoUtils::object_to_string((MonoObject *)type_obj, &exc); - UNHANDLED_EXCEPTION(exc); - - return GDMonoMarshal::mono_string_to_godot(str); -} - -MonoType *GDMonoClass::get_mono_type(MonoClass *p_mono_class) { - return mono_class_get_type(p_mono_class); -} - -String GDMonoClass::get_full_name() const { - return get_full_name(mono_class); -} - -String GDMonoClass::get_type_desc() const { - return GDMonoUtils::get_type_desc(get_mono_type()); -} - -MonoType *GDMonoClass::get_mono_type() const { - // Careful, you cannot compare two MonoType*. - // There is mono_metadata_type_equal, how is this different from comparing two MonoClass*? - return get_mono_type(mono_class); -} - -uint32_t GDMonoClass::get_flags() const { - return mono_class_get_flags(mono_class); -} - -bool GDMonoClass::is_static() const { - uint32_t static_class_flags = MONO_TYPE_ATTR_ABSTRACT | MONO_TYPE_ATTR_SEALED; - return (get_flags() & static_class_flags) == static_class_flags; -} - -bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const { - return mono_class_is_assignable_from(mono_class, p_from->mono_class); -} - -StringName GDMonoClass::get_namespace() const { - GDMonoClass *nesting_class = get_nesting_class(); - if (!nesting_class) { - return namespace_name; - } - return nesting_class->get_namespace(); -} - -String GDMonoClass::get_name_for_lookup() const { - GDMonoClass *nesting_class = get_nesting_class(); - if (!nesting_class) { - return class_name; - } - return nesting_class->get_name_for_lookup() + "/" + class_name; -} - -GDMonoClass *GDMonoClass::get_parent_class() const { - MonoClass *parent_mono_class = mono_class_get_parent(mono_class); - return parent_mono_class ? GDMono::get_singleton()->get_class(parent_mono_class) : nullptr; -} - -GDMonoClass *GDMonoClass::get_nesting_class() const { - MonoClass *nesting_type = mono_class_get_nesting_type(mono_class); - return nesting_type ? GDMono::get_singleton()->get_class(nesting_type) : nullptr; -} - -#ifdef TOOLS_ENABLED -Vector<MonoClassField *> GDMonoClass::get_enum_fields() { - bool class_is_enum = mono_class_is_enum(mono_class); - ERR_FAIL_COND_V(!class_is_enum, Vector<MonoClassField *>()); - - Vector<MonoClassField *> enum_fields; - - void *iter = nullptr; - MonoClassField *raw_field = nullptr; - while ((raw_field = mono_class_get_fields(get_mono_ptr(), &iter)) != nullptr) { - uint32_t field_flags = mono_field_get_flags(raw_field); - - // Enums have an instance field named value__ which holds the value of the enum. - // Enum constants are static, so we will use this to ignore the value__ field. - if (field_flags & MONO_FIELD_ATTR_PUBLIC && field_flags & MONO_FIELD_ATTR_STATIC) { - enum_fields.push_back(raw_field); - } - } - - return enum_fields; -} -#endif - -bool GDMonoClass::has_attribute(GDMonoClass *p_attr_class) { -#ifdef DEBUG_ENABLED - ERR_FAIL_NULL_V(p_attr_class, false); -#endif - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return false; - } - - return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr()); -} - -MonoObject *GDMonoClass::get_attribute(GDMonoClass *p_attr_class) { -#ifdef DEBUG_ENABLED - ERR_FAIL_NULL_V(p_attr_class, nullptr); -#endif - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return nullptr; - } - - return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr()); -} - -void GDMonoClass::fetch_attributes() { - ERR_FAIL_COND(attributes != nullptr); - - attributes = mono_custom_attrs_from_class(get_mono_ptr()); - attrs_fetched = true; -} - -void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base) { - CRASH_COND(!CACHED_CLASS(GodotObject)->is_assignable_from(this)); - - if (methods_fetched) { - return; - } - - void *iter = nullptr; - MonoMethod *raw_method = nullptr; - while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) { - StringName name = String::utf8(mono_method_get_name(raw_method)); - - // get_method implicitly fetches methods and adds them to this->methods - GDMonoMethod *method = get_method(raw_method, name); - ERR_CONTINUE(!method); - - if (method->get_name() != name) { -#ifdef DEBUG_ENABLED - String fullname = method->get_ret_type_full_name() + " " + name + "(" + method->get_signature_desc(true) + ")"; - WARN_PRINT("Method '" + fullname + "' is hidden by Godot API method. Should be '" + - method->get_full_name_no_class() + "'. In class '" + namespace_name + "." + class_name + "'."); -#endif - continue; - } - -#ifdef DEBUG_ENABLED - // For debug builds, we also fetched from native base classes as well before if this is not a native base class. - // This allows us to warn the user here if they are using snake_case by mistake. - - if (p_native_base != this) { - GDMonoClass *native_top = p_native_base; - while (native_top) { - GDMonoMethod *m = native_top->get_method(name, method->get_parameters_count()); - - if (m && m->get_name() != name) { - // found - String fullname = m->get_ret_type_full_name() + " " + name + "(" + m->get_signature_desc(true) + ")"; - WARN_PRINT("Method '" + fullname + "' should be '" + m->get_full_name_no_class() + - "'. In class '" + namespace_name + "." + class_name + "'."); - break; - } - - if (native_top == CACHED_CLASS(GodotObject)) { - break; - } - - native_top = native_top->get_parent_class(); - } - } -#endif - - uint32_t flags = mono_method_get_flags(method->mono_method, nullptr); - - if (!(flags & MONO_METHOD_ATTR_VIRTUAL)) { - continue; - } - - // Virtual method of Godot Object derived type, let's try to find GodotMethod attribute - - GDMonoClass *top = p_native_base; - - while (top) { - GDMonoMethod *base_method = top->get_method(name, method->get_parameters_count()); - - if (base_method && base_method->has_attribute(CACHED_CLASS(GodotMethodAttribute))) { - // Found base method with GodotMethod attribute. - // We get the original API method name from this attribute. - // This name must point to the virtual method. - - MonoObject *attr = base_method->get_attribute(CACHED_CLASS(GodotMethodAttribute)); - - StringName godot_method_name = CACHED_FIELD(GodotMethodAttribute, methodName)->get_string_value(attr); -#ifdef DEBUG_ENABLED - CRASH_COND(godot_method_name == StringName()); -#endif - MethodKey key = MethodKey(godot_method_name, method->get_parameters_count()); - GDMonoMethod **existing_method = methods.getptr(key); - if (existing_method) { - memdelete(*existing_method); // Must delete old one - } - methods.insert(key, method); - - break; - } - - if (top == CACHED_CLASS(GodotObject)) { - break; - } - - top = top->get_parent_class(); - } - } - - methods_fetched = true; -} - -GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) { - ERR_FAIL_COND_V(!methods_fetched, nullptr); - - for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) { - if (E.key.name == p_name) { - return E.value; - } - } - - return nullptr; -} - -bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) { - return get_fetched_method_unknown_params(p_name) != nullptr; -} - -bool GDMonoClass::implements_interface(GDMonoClass *p_interface) { - return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr()); -} - -bool GDMonoClass::has_public_parameterless_ctor() { - GDMonoMethod *ctor = get_method(".ctor", 0); - return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC; -} - -GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_params_count) { - MethodKey key = MethodKey(p_name, p_params_count); - - GDMonoMethod **match = methods.getptr(key); - - if (match) { - return *match; - } - - if (methods_fetched) { - return nullptr; - } - - MonoMethod *raw_method = mono_class_get_method_from_name(mono_class, String(p_name).utf8().get_data(), p_params_count); - - if (raw_method) { - GDMonoMethod *method = memnew(GDMonoMethod(p_name, raw_method)); - methods.insert(key, method); - - return method; - } - - return nullptr; -} - -GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method) { - MonoMethodSignature *sig = mono_method_signature(p_raw_method); - - int params_count = mono_signature_get_param_count(sig); - StringName method_name = String::utf8(mono_method_get_name(p_raw_method)); - - return get_method(p_raw_method, method_name, params_count); -} - -GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name) { - MonoMethodSignature *sig = mono_method_signature(p_raw_method); - int params_count = mono_signature_get_param_count(sig); - return get_method(p_raw_method, p_name, params_count); -} - -GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count) { - ERR_FAIL_NULL_V(p_raw_method, nullptr); - - MethodKey key = MethodKey(p_name, p_params_count); - - GDMonoMethod **match = methods.getptr(key); - - if (match) { - return *match; - } - - GDMonoMethod *method = memnew(GDMonoMethod(p_name, p_raw_method)); - methods.insert(key, method); - - return method; -} - -GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, bool p_include_namespace) { - MonoMethodDesc *desc = mono_method_desc_new(p_description.utf8().get_data(), p_include_namespace); - MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class); - mono_method_desc_free(desc); - - if (!method) { - return nullptr; - } - - ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, nullptr); - - return get_method(method); -} - -GDMonoField *GDMonoClass::get_field(const StringName &p_name) { - HashMap<StringName, GDMonoField *>::Iterator result = fields.find(p_name); - - if (result) { - return result->value; - } - - if (fields_fetched) { - return nullptr; - } - - MonoClassField *raw_field = mono_class_get_field_from_name(mono_class, String(p_name).utf8().get_data()); - - if (raw_field) { - GDMonoField *field = memnew(GDMonoField(raw_field, this)); - fields.insert(p_name, field); - - return field; - } - - return nullptr; -} - -const Vector<GDMonoField *> &GDMonoClass::get_all_fields() { - if (fields_fetched) { - return fields_list; - } - - void *iter = nullptr; - MonoClassField *raw_field = nullptr; - while ((raw_field = mono_class_get_fields(mono_class, &iter)) != nullptr) { - StringName name = String::utf8(mono_field_get_name(raw_field)); - - HashMap<StringName, GDMonoField *>::Iterator match = fields.find(name); - - if (match) { - fields_list.push_back(match->value); - } else { - GDMonoField *field = memnew(GDMonoField(raw_field, this)); - fields.insert(name, field); - fields_list.push_back(field); - } - } - - fields_fetched = true; - - return fields_list; -} - -GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) { - HashMap<StringName, GDMonoProperty *>::Iterator result = properties.find(p_name); - - if (result) { - return result->value; - } - - if (properties_fetched) { - return nullptr; - } - - MonoProperty *raw_property = mono_class_get_property_from_name(mono_class, String(p_name).utf8().get_data()); - - if (raw_property) { - GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this)); - properties.insert(p_name, property); - - return property; - } - - return nullptr; -} - -const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() { - if (properties_fetched) { - return properties_list; - } - - void *iter = nullptr; - MonoProperty *raw_property = nullptr; - while ((raw_property = mono_class_get_properties(mono_class, &iter)) != nullptr) { - StringName name = String::utf8(mono_property_get_name(raw_property)); - - HashMap<StringName, GDMonoProperty *>::Iterator match = properties.find(name); - - if (match) { - properties_list.push_back(match->value); - } else { - GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this)); - properties.insert(name, property); - properties_list.push_back(property); - } - } - - properties_fetched = true; - - return properties_list; -} - -const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() { - if (delegates_fetched) { - return delegates_list; - } - - // If the class is generic we must use the generic type definition. - MonoClass *klass = mono_class; - if (mono_type_get_type(get_mono_type()) == MONO_TYPE_GENERICINST) { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), get_mono_type()); - GDMonoUtils::Marshal::get_generic_type_definition(reftype, &reftype); - MonoType *type = mono_reflection_type_get_type(reftype); - klass = mono_class_from_mono_type(type); - } - - void *iter = nullptr; - MonoClass *raw_class = nullptr; - while ((raw_class = mono_class_get_nested_types(klass, &iter)) != nullptr) { - if (mono_class_is_delegate(raw_class)) { - StringName name = String::utf8(mono_class_get_name(raw_class)); - - HashMap<StringName, GDMonoClass *>::Iterator match = delegates.find(name); - - if (match) { - delegates_list.push_back(match->value); - } else { - GDMonoClass *delegate = memnew(GDMonoClass(String::utf8(mono_class_get_namespace(raw_class)), String::utf8(mono_class_get_name(raw_class)), raw_class, assembly)); - delegates.insert(name, delegate); - delegates_list.push_back(delegate); - } - } - } - - delegates_fetched = true; - - return delegates_list; -} - -const Vector<GDMonoMethod *> &GDMonoClass::get_all_methods() { - if (!method_list_fetched) { - void *iter = nullptr; - MonoMethod *raw_method = nullptr; - while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) { - method_list.push_back(memnew(GDMonoMethod(String::utf8(mono_method_get_name(raw_method)), raw_method))); - } - - method_list_fetched = true; - } - - return method_list; -} - -GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly) { - namespace_name = p_namespace; - class_name = p_name; - mono_class = p_class; - assembly = p_assembly; - - attrs_fetched = false; - attributes = nullptr; - - methods_fetched = false; - method_list_fetched = false; - fields_fetched = false; - properties_fetched = false; - delegates_fetched = false; -} - -GDMonoClass::~GDMonoClass() { - if (attributes) { - mono_custom_attrs_free(attributes); - } - - for (const KeyValue<StringName, GDMonoField *> &E : fields) { - memdelete(E.value); - } - - for (const KeyValue<StringName, GDMonoProperty *> &E : properties) { - memdelete(E.value); - } - - { - // Ugly workaround... - // We may have duplicated values, because we redirect snake_case methods to PascalCasel (only Godot API methods). - // This way, we end with both the snake_case name and the PascalCasel name paired with the same method. - // Therefore, we must avoid deleting the same pointer twice. - - int offset = 0; - Vector<GDMonoMethod *> deleted_methods; - deleted_methods.resize(methods.size()); - - for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) { - GDMonoMethod *method = E.value; - - if (method) { - for (int i = 0; i < offset; i++) { - if (deleted_methods[i] == method) { - // Already deleted - goto already_deleted; - } - } - - deleted_methods.write[offset] = method; - ++offset; - - memdelete(method); - } - - already_deleted:; - } - - methods.clear(); - } - - for (int i = 0; i < method_list.size(); ++i) { - memdelete(method_list[i]); - } -} diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h deleted file mode 100644 index 6b35da30f9..0000000000 --- a/modules/mono/mono_gd/gd_mono_class.h +++ /dev/null @@ -1,160 +0,0 @@ -/*************************************************************************/ -/* gd_mono_class.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_CLASS_H -#define GD_MONO_CLASS_H - -#include "core/string/ustring.h" -#include "core/templates/rb_map.h" - -#include "gd_mono_field.h" -#include "gd_mono_header.h" -#include "gd_mono_method.h" -#include "gd_mono_property.h" -#include "gd_mono_utils.h" - -class GDMonoClass { - struct MethodKey { - struct Hasher { - static _FORCE_INLINE_ uint32_t hash(const MethodKey &p_key) { - uint32_t hash = 0; - - GDMonoUtils::hash_combine(hash, p_key.name.hash()); - GDMonoUtils::hash_combine(hash, HashMapHasherDefault::hash(p_key.params_count)); - - return hash; - } - }; - - _FORCE_INLINE_ bool operator==(const MethodKey &p_a) const { - return p_a.params_count == params_count && p_a.name == name; - } - - MethodKey() {} - - MethodKey(const StringName &p_name, uint16_t p_params_count) : - name(p_name), params_count(p_params_count) { - } - - StringName name; - uint16_t params_count = 0; - }; - - StringName namespace_name; - StringName class_name; - - MonoClass *mono_class = nullptr; - GDMonoAssembly *assembly = nullptr; - - bool attrs_fetched; - MonoCustomAttrInfo *attributes = nullptr; - - // This contains both the original method names and remapped method names from the native Godot identifiers to the C# functions. - // Most method-related functions refer to this and it's possible this is unintuitive for outside users; this may be a prime location for refactoring or renaming. - bool methods_fetched; - HashMap<MethodKey, GDMonoMethod *, MethodKey::Hasher> methods; - - bool method_list_fetched; - Vector<GDMonoMethod *> method_list; - - bool fields_fetched; - HashMap<StringName, GDMonoField *> fields; - Vector<GDMonoField *> fields_list; - - bool properties_fetched; - HashMap<StringName, GDMonoProperty *> properties; - Vector<GDMonoProperty *> properties_list; - - bool delegates_fetched; - HashMap<StringName, GDMonoClass *> delegates; - Vector<GDMonoClass *> delegates_list; - - friend class GDMonoAssembly; - GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly); - -public: - static String get_full_name(MonoClass *p_mono_class); - static MonoType *get_mono_type(MonoClass *p_mono_class); - - String get_full_name() const; - String get_type_desc() const; - MonoType *get_mono_type() const; - - uint32_t get_flags() const; - bool is_static() const; - - bool is_assignable_from(GDMonoClass *p_from) const; - - StringName get_namespace() const; - _FORCE_INLINE_ StringName get_name() const { return class_name; } - String get_name_for_lookup() const; - - _FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; } - _FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; } - - GDMonoClass *get_parent_class() const; - GDMonoClass *get_nesting_class() const; - -#ifdef TOOLS_ENABLED - Vector<MonoClassField *> get_enum_fields(); -#endif - - GDMonoMethod *get_fetched_method_unknown_params(const StringName &p_name); - bool has_fetched_method_unknown_params(const StringName &p_name); - - bool has_attribute(GDMonoClass *p_attr_class); - MonoObject *get_attribute(GDMonoClass *p_attr_class); - - void fetch_attributes(); - void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base); - - bool implements_interface(GDMonoClass *p_interface); - bool has_public_parameterless_ctor(); - - GDMonoMethod *get_method(const StringName &p_name, uint16_t p_params_count = 0); - GDMonoMethod *get_method(MonoMethod *p_raw_method); - GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name); - GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count); - GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace); - - GDMonoField *get_field(const StringName &p_name); - const Vector<GDMonoField *> &get_all_fields(); - - GDMonoProperty *get_property(const StringName &p_name); - const Vector<GDMonoProperty *> &get_all_properties(); - - const Vector<GDMonoClass *> &get_all_delegates(); - - const Vector<GDMonoMethod *> &get_all_methods(); - - ~GDMonoClass(); -}; - -#endif // GD_MONO_CLASS_H diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp deleted file mode 100644 index cb025fc67a..0000000000 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ /dev/null @@ -1,556 +0,0 @@ -/*************************************************************************/ -/* gd_mono_field.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_field.h" - -#include <mono/metadata/attrdefs.h> - -#include "gd_mono_cache.h" -#include "gd_mono_class.h" -#include "gd_mono_marshal.h" -#include "gd_mono_utils.h" - -void GDMonoField::set_value(MonoObject *p_object, MonoObject *p_value) { - mono_field_set_value(p_object, mono_field, p_value); -} - -void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) { - mono_field_set_value(p_object, mono_field, &p_ptr); -} - -void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) { - switch (type.type_encoding) { - case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_value.operator bool(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_CHAR: { - int16_t val = p_value.operator unsigned short(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_I1: { - int8_t val = p_value.operator signed char(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_I2: { - int16_t val = p_value.operator signed short(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_I4: { - int32_t val = p_value.operator signed int(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_I8: { - int64_t val = p_value.operator int64_t(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_U1: { - uint8_t val = p_value.operator unsigned char(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_U2: { - uint16_t val = p_value.operator unsigned short(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_U4: { - uint32_t val = p_value.operator unsigned int(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_U8: { - uint64_t val = p_value.operator uint64_t(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_R4: { - float val = p_value.operator float(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_R8: { - double val = p_value.operator double(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case MONO_TYPE_VALUETYPE: { - GDMonoClass *tclass = type.type_class; - - if (tclass == CACHED_CLASS(Vector2)) { - GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Vector2i)) { - GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Rect2)) { - GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Rect2i)) { - GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Transform2D)) { - GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Vector3)) { - GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Vector3i)) { - GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Vector4)) { - GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_value.operator ::Vector4()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Vector4i)) { - GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_value.operator ::Vector4i()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Basis)) { - GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Quaternion)) { - GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Transform3D)) { - GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Projection)) { - GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_value.operator ::Projection()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(AABB)) { - GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Color)) { - GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Plane)) { - GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); - mono_field_set_value(p_object, mono_field, &from); - break; - } - - if (tclass == CACHED_CLASS(Callable)) { - GDMonoMarshal::M_Callable val = GDMonoMarshal::callable_to_managed(p_value.operator Callable()); - mono_field_set_value(p_object, mono_field, &val); - break; - } - - if (tclass == CACHED_CLASS(SignalInfo)) { - GDMonoMarshal::M_SignalInfo val = GDMonoMarshal::signal_info_to_managed(p_value.operator Signal()); - mono_field_set_value(p_object, mono_field, &val); - break; - } - - if (mono_class_is_enum(tclass->get_mono_ptr())) { - MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr()); - switch (mono_type_get_type(enum_basetype)) { - case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_value.operator bool(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - case MONO_TYPE_CHAR: { - uint16_t val = p_value.operator unsigned short(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - case MONO_TYPE_I1: { - int8_t val = p_value.operator signed char(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - case MONO_TYPE_I2: { - int16_t val = p_value.operator signed short(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - case MONO_TYPE_I4: { - int32_t val = p_value.operator signed int(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - case MONO_TYPE_I8: { - int64_t val = p_value.operator int64_t(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - case MONO_TYPE_U1: { - uint8_t val = p_value.operator unsigned char(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - case MONO_TYPE_U2: { - uint16_t val = p_value.operator unsigned short(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - case MONO_TYPE_U4: { - uint32_t val = p_value.operator unsigned int(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - case MONO_TYPE_U8: { - uint64_t val = p_value.operator uint64_t(); - mono_field_set_value(p_object, mono_field, &val); - break; - } - default: { - ERR_FAIL_MSG("Attempted to convert Variant to a managed enum value of unmarshallable base type."); - } - } - - break; - } - - ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + tclass->get_name() + "'."); - } break; - case MONO_TYPE_STRING: { - if (p_value.get_type() == Variant::NIL) { - // Otherwise, Variant -> String would return the string "Null" - MonoString *mono_string = nullptr; - mono_field_set_value(p_object, mono_field, mono_string); - } else { - MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value); - mono_field_set_value(p_object, mono_field, mono_string); - } - } break; - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: { - MonoArray *managed = GDMonoMarshal::variant_to_mono_array(p_value, type.type_class); - if (likely(managed != nullptr)) { - mono_field_set_value(p_object, mono_field, managed); - } - } break; - case MONO_TYPE_CLASS: { - MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_class(p_value, type.type_class); - if (likely(managed != nullptr)) { - mono_field_set_value(p_object, mono_field, managed); - } - } break; - case MONO_TYPE_GENERICINST: { - MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_genericinst(p_value, type.type_class); - if (likely(managed != nullptr)) { - mono_field_set_value(p_object, mono_field, managed); - } - } break; - case MONO_TYPE_OBJECT: { - // Variant - switch (p_value.get_type()) { - case Variant::BOOL: { - MonoBoolean val = p_value.operator bool(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case Variant::INT: { - int32_t val = p_value.operator signed int(); - mono_field_set_value(p_object, mono_field, &val); - } break; - case Variant::FLOAT: { -#ifdef REAL_T_IS_DOUBLE - double val = p_value.operator double(); - mono_field_set_value(p_object, mono_field, &val); -#else - float val = p_value.operator float(); - mono_field_set_value(p_object, mono_field, &val); -#endif - } break; - case Variant::STRING: { - MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value); - mono_field_set_value(p_object, mono_field, mono_string); - } break; - case Variant::VECTOR2: { - GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::VECTOR2I: { - GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::RECT2: { - GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::RECT2I: { - GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::VECTOR3: { - GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::VECTOR3I: { - GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::VECTOR4: { - GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_value.operator ::Vector4()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::VECTOR4I: { - GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_value.operator ::Vector4i()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::TRANSFORM2D: { - GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::PLANE: { - GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::QUATERNION: { - GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::AABB: { - GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::BASIS: { - GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::TRANSFORM3D: { - GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::PROJECTION: { - GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_value.operator ::Projection()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::COLOR: { - GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color()); - mono_field_set_value(p_object, mono_field, &from); - } break; - case Variant::STRING_NAME: { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::NODE_PATH: { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::RID: { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator ::RID()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::OBJECT: { - MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::CALLABLE: { - GDMonoMarshal::M_Callable val = GDMonoMarshal::callable_to_managed(p_value.operator Callable()); - mono_field_set_value(p_object, mono_field, &val); - } break; - case Variant::SIGNAL: { - GDMonoMarshal::M_SignalInfo val = GDMonoMarshal::signal_info_to_managed(p_value.operator Signal()); - mono_field_set_value(p_object, mono_field, &val); - } break; - case Variant::DICTIONARY: { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary)); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::ARRAY: { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::PACKED_BYTE_ARRAY: { - MonoArray *managed = GDMonoMarshal::PackedByteArray_to_mono_array(p_value.operator ::PackedByteArray()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::PACKED_INT32_ARRAY: { - MonoArray *managed = GDMonoMarshal::PackedInt32Array_to_mono_array(p_value.operator ::PackedInt32Array()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::PACKED_INT64_ARRAY: { - MonoArray *managed = GDMonoMarshal::PackedInt64Array_to_mono_array(p_value.operator ::PackedInt64Array()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::PACKED_FLOAT32_ARRAY: { - MonoArray *managed = GDMonoMarshal::PackedFloat32Array_to_mono_array(p_value.operator ::PackedFloat32Array()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::PACKED_FLOAT64_ARRAY: { - MonoArray *managed = GDMonoMarshal::PackedFloat64Array_to_mono_array(p_value.operator ::PackedFloat64Array()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::PACKED_STRING_ARRAY: { - MonoArray *managed = GDMonoMarshal::PackedStringArray_to_mono_array(p_value.operator ::PackedStringArray()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::PACKED_VECTOR2_ARRAY: { - MonoArray *managed = GDMonoMarshal::PackedVector2Array_to_mono_array(p_value.operator ::PackedVector2Array()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::PACKED_VECTOR3_ARRAY: { - MonoArray *managed = GDMonoMarshal::PackedVector3Array_to_mono_array(p_value.operator ::PackedVector3Array()); - mono_field_set_value(p_object, mono_field, managed); - } break; - case Variant::PACKED_COLOR_ARRAY: { - MonoArray *managed = GDMonoMarshal::PackedColorArray_to_mono_array(p_value.operator ::PackedColorArray()); - mono_field_set_value(p_object, mono_field, managed); - } break; - default: - break; - } - } break; - default: { - ERR_PRINT("Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding) + "."); - } break; - } -} - -MonoObject *GDMonoField::get_value(MonoObject *p_object) { - return mono_field_get_value_object(mono_domain_get(), mono_field, p_object); -} - -bool GDMonoField::get_bool_value(MonoObject *p_object) { - return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object)); -} - -int GDMonoField::get_int_value(MonoObject *p_object) { - return GDMonoMarshal::unbox<int32_t>(get_value(p_object)); -} - -String GDMonoField::get_string_value(MonoObject *p_object) { - MonoObject *val = get_value(p_object); - return GDMonoMarshal::mono_string_to_godot((MonoString *)val); -} - -bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) { - ERR_FAIL_NULL_V(p_attr_class, false); - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return false; - } - - return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr()); -} - -MonoObject *GDMonoField::get_attribute(GDMonoClass *p_attr_class) { - ERR_FAIL_NULL_V(p_attr_class, nullptr); - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return nullptr; - } - - return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr()); -} - -void GDMonoField::fetch_attributes() { - ERR_FAIL_COND(attributes != nullptr); - attributes = mono_custom_attrs_from_field(owner->get_mono_ptr(), mono_field); - attrs_fetched = true; -} - -bool GDMonoField::is_static() { - return mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_STATIC; -} - -IMonoClassMember::Visibility GDMonoField::get_visibility() { - switch (mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_FIELD_ACCESS_MASK) { - case MONO_FIELD_ATTR_PRIVATE: - return IMonoClassMember::PRIVATE; - case MONO_FIELD_ATTR_FAM_AND_ASSEM: - return IMonoClassMember::PROTECTED_AND_INTERNAL; - case MONO_FIELD_ATTR_ASSEMBLY: - return IMonoClassMember::INTERNAL; - case MONO_FIELD_ATTR_FAMILY: - return IMonoClassMember::PROTECTED; - case MONO_FIELD_ATTR_PUBLIC: - return IMonoClassMember::PUBLIC; - default: - ERR_FAIL_V(IMonoClassMember::PRIVATE); - } -} - -GDMonoField::GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner) { - owner = p_owner; - mono_field = p_mono_field; - name = String::utf8(mono_field_get_name(mono_field)); - MonoType *field_type = mono_field_get_type(mono_field); - type.type_encoding = mono_type_get_type(field_type); - MonoClass *field_type_class = mono_class_from_mono_type(field_type); - type.type_class = GDMono::get_singleton()->get_class(field_type_class); - - attrs_fetched = false; - attributes = nullptr; -} - -GDMonoField::~GDMonoField() { - if (attributes) { - mono_custom_attrs_free(attributes); - } -} diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h deleted file mode 100644 index 1d30f7a369..0000000000 --- a/modules/mono/mono_gd/gd_mono_field.h +++ /dev/null @@ -1,78 +0,0 @@ -/*************************************************************************/ -/* gd_mono_field.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_FIELD_H -#define GD_MONO_FIELD_H - -#include "gd_mono.h" -#include "gd_mono_header.h" -#include "i_mono_class_member.h" - -class GDMonoField : public IMonoClassMember { - GDMonoClass *owner = nullptr; - MonoClassField *mono_field = nullptr; - - StringName name; - ManagedType type; - - bool attrs_fetched; - MonoCustomAttrInfo *attributes = nullptr; - -public: - virtual GDMonoClass *get_enclosing_class() const final { return owner; } - - virtual MemberType get_member_type() const final { return MEMBER_TYPE_FIELD; } - - virtual StringName get_name() const final { return name; } - - virtual bool is_static() final; - virtual Visibility get_visibility() final; - - virtual bool has_attribute(GDMonoClass *p_attr_class) final; - virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final; - void fetch_attributes(); - - _FORCE_INLINE_ ManagedType get_type() const { return type; } - - void set_value(MonoObject *p_object, MonoObject *p_value); - void set_value_raw(MonoObject *p_object, void *p_ptr); - void set_value_from_variant(MonoObject *p_object, const Variant &p_value); - - MonoObject *get_value(MonoObject *p_object); - - bool get_bool_value(MonoObject *p_object); - int get_int_value(MonoObject *p_object); - String get_string_value(MonoObject *p_object); - - GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner); - ~GDMonoField(); -}; - -#endif // GD_MONO_FIELD_H diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h deleted file mode 100644 index bf21283080..0000000000 --- a/modules/mono/mono_gd/gd_mono_header.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* gd_mono_header.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_HEADER_H -#define GD_MONO_HEADER_H - -#include <cstdint> - -#ifdef WIN32 -#define GD_MONO_STDCALL __stdcall -#else -#define GD_MONO_STDCALL -#endif - -class GDMonoAssembly; -class GDMonoClass; -class GDMonoField; -class GDMonoMethod; -class GDMonoProperty; - -class IMonoClassMember; - -#include "managed_type.h" - -#endif // GD_MONO_HEADER_H diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp deleted file mode 100644 index d206b0dfc3..0000000000 --- a/modules/mono/mono_gd/gd_mono_internals.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/*************************************************************************/ -/* gd_mono_internals.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_internals.h" - -#include "../csharp_script.h" -#include "../mono_gc_handle.h" -#include "../utils/macros.h" -#include "gd_mono_class.h" -#include "gd_mono_marshal.h" -#include "gd_mono_utils.h" - -#include "core/debugger/engine_debugger.h" -#include "core/debugger/script_debugger.h" - -#include <mono/metadata/exception.h> - -namespace GDMonoInternals { -void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { - // This method should not fail - - CRASH_COND(!unmanaged); - - // All mono objects created from the managed world (e.g.: 'new Player()') - // need to have a CSharpScript in order for their methods to be callable from the unmanaged side - - RefCounted *rc = Object::cast_to<RefCounted>(unmanaged); - - GDMonoClass *klass = GDMonoUtils::get_object_class(managed); - - CRASH_COND(!klass); - - GDMonoClass *native = GDMonoUtils::get_class_native_base(klass); - - CRASH_COND(native == nullptr); - - if (native == klass) { - // If it's just a wrapper Godot class and not a custom inheriting class, then attach a - // script binding instead. One of the advantages of this is that if a script is attached - // later and it's not a C# script, then the managed object won't have to be disposed. - // Another reason for doing this is that this instance could outlive CSharpLanguage, which would - // be problematic when using a script. See: https://github.com/godotengine/godot/issues/25621 - - CSharpScriptBinding script_binding; - - script_binding.inited = true; - script_binding.type_name = NATIVE_GDMONOCLASS_NAME(klass); - script_binding.wrapper_class = klass; - script_binding.gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); - script_binding.owner = unmanaged; - - if (rc) { - // 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_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr) - - // May not me referenced yet, so we must use init_ref() instead of reference() - if (rc->init_ref()) { - CSharpLanguage::get_singleton()->post_unsafe_reference(rc); - } - } - - // The object was just created, no script instance binding should have been attached - CRASH_COND(CSharpLanguage::has_instance_binding(unmanaged)); - - void *data; - { - MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex()); - data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(unmanaged, script_binding); - } - - // Should be thread safe because the object was just created and nothing else should be referencing it - CSharpLanguage::set_instance_binding(unmanaged, data); - - return; - } - - MonoGCHandleData gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); - - Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native); - - CRASH_COND(script.is_null()); - - CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle); - - unmanaged->set_script_and_instance(script, csharp_instance); -} - -void unhandled_exception(MonoException *p_exc) { - mono_print_unhandled_exception((MonoObject *)p_exc); - gd_unhandled_exception_event(p_exc); - - if (GDMono::get_singleton()->get_unhandled_exception_policy() == GDMono::POLICY_TERMINATE_APP) { - // Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders - mono_unhandled_exception((MonoObject *)p_exc); - GDMono::unhandled_exception_hook((MonoObject *)p_exc, nullptr); - GD_UNREACHABLE(); - } else { -#ifdef DEBUG_ENABLED - GDMonoUtils::debug_send_unhandled_exception_error(p_exc); - if (EngineDebugger::is_active()) { - EngineDebugger::get_singleton()->poll_events(false); - } -#endif - } -} - -void gd_unhandled_exception_event(MonoException *p_exc) { - MonoImage *mono_image = GDMono::get_singleton()->get_core_api_assembly()->get_image(); - - MonoClass *gd_klass = mono_class_from_name(mono_image, "Godot", "GD"); - MonoMethod *unhandled_exception_method = mono_class_get_method_from_name(gd_klass, "OnUnhandledException", -1); - void *args[1]; - args[0] = p_exc; - mono_runtime_invoke(unhandled_exception_method, nullptr, (void **)args, nullptr); -} -} // namespace GDMonoInternals diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h deleted file mode 100644 index a8f9cfa3ca..0000000000 --- a/modules/mono/mono_gd/gd_mono_internals.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* gd_mono_internals.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_INTERNALS_H -#define GD_MONO_INTERNALS_H - -#include <mono/jit/jit.h> - -#include "../utils/macros.h" - -#include "core/object/class_db.h" - -namespace GDMonoInternals { -void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged); - -/** - * Do not call this function directly. - * Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead. - */ -void unhandled_exception(MonoException *p_exc); - -void gd_unhandled_exception_event(MonoException *p_exc); -} // namespace GDMonoInternals - -#endif // GD_MONO_INTERNALS_H diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp deleted file mode 100644 index 6ea3c5539e..0000000000 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/*************************************************************************/ -/* gd_mono_log.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_log.h" - -#include <stdlib.h> // abort - -#include "core/io/dir_access.h" -#include "core/os/os.h" - -#include "../godotsharp_dirs.h" -#include "../utils/string_utils.h" - -static CharString get_default_log_level() { -#ifdef DEBUG_ENABLED - return String("info").utf8(); -#else - return String("warning").utf8(); -#endif -} - -GDMonoLog *GDMonoLog::singleton = nullptr; - -#ifdef GD_MONO_LOG_ENABLED - -static int get_log_level_id(const char *p_log_level) { - const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", nullptr }; - - int i = 0; - while (valid_log_levels[i]) { - if (!strcmp(valid_log_levels[i], p_log_level)) { - return i; - } - i++; - } - - return -1; -} - -static String make_text(const char *log_domain, const char *log_level, const char *message) { - String text(message); - text += " (in domain "; - text += log_domain; - if (log_level) { - text += ", "; - text += log_level; - } - text += ")"; - return text; -} - -void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) { - if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) { - String text = make_text(log_domain, log_level, message); - text += "\n"; - - GDMonoLog::get_singleton()->log_file->seek_end(); - GDMonoLog::get_singleton()->log_file->store_string(text); - } - - if (fatal) { - String text = make_text(log_domain, log_level, message); - ERR_PRINT("Mono: FATAL ERROR '" + text + "', ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'."); - // Make sure to flush before aborting - GDMonoLog::get_singleton()->log_file->flush(); - GDMonoLog::get_singleton()->log_file.unref(); - - abort(); - } -} - -bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) { - if (!DirAccess::exists(p_logs_dir)) { - Ref<DirAccess> diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(diraccess.is_null(), false); - Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir); - ERR_FAIL_COND_V_MSG(logs_mkdir_err != OK, false, "Failed to create mono logs directory."); - } - - return true; -} - -void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) { - static const uint64_t MAX_SECS = 5 * 86400; // 5 days - - Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND(da.is_null()); - - Error err = da->change_dir(p_logs_dir); - ERR_FAIL_COND_MSG(err != OK, "Cannot change directory to '" + p_logs_dir + "'."); - - ERR_FAIL_COND(da->list_dir_begin() != OK); - - String current = da->get_next(); - while (!current.is_empty()) { - if (da->current_is_dir() || !current.ends_with(".txt")) { - current = da->get_next(); - continue; - } - - uint64_t modified_time = FileAccess::get_modified_time(da->get_current_dir().plus_file(current)); - - if (OS::get_singleton()->get_unix_time() - modified_time > MAX_SECS) { - da->remove(current); - } - current = da->get_next(); - } - - da->list_dir_end(); -} - -void GDMonoLog::initialize() { - CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8(); - - if (log_level.length() != 0 && get_log_level_id(log_level.get_data()) == -1) { - ERR_PRINT(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): '" + log_level.get_data() + "'."); - log_level = CharString(); - } - - if (log_level.length() == 0) { - log_level = get_default_log_level(); - } - - String logs_dir = GodotSharpDirs::get_mono_logs_dir(); - - if (_try_create_logs_dir(logs_dir)) { - _delete_old_log_files(logs_dir); - - OS::Date date_now = OS::get_singleton()->get_date(); - OS::Time time_now = OS::get_singleton()->get_time(); - - String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d", - (int)date_now.year, (int)date_now.month, (int)date_now.day, - (int)time_now.hour, (int)time_now.minute, (int)time_now.second); - - log_file_name += str_format("_%d", OS::get_singleton()->get_process_id()); - - log_file_name += ".log"; - - log_file_path = logs_dir.plus_file(log_file_name); - - log_file = FileAccess::open(log_file_path, FileAccess::WRITE); - if (log_file.is_null()) { - ERR_PRINT("Mono: Cannot create log file at: " + log_file_path); - } - } - - mono_trace_set_level_string(log_level.get_data()); - log_level_id = get_log_level_id(log_level.get_data()); - - if (log_file.is_valid()) { - OS::get_singleton()->print("Mono: Log file is: '%s'\n", log_file_path.utf8().get_data()); - mono_trace_set_log_handler(mono_log_callback, this); - } else { - OS::get_singleton()->printerr("Mono: No log file, using default log handler\n"); - } -} - -GDMonoLog::GDMonoLog() { - singleton = this; -} - -GDMonoLog::~GDMonoLog() { - singleton = nullptr; -} - -#else - -void GDMonoLog::initialize() { - CharString log_level = get_default_log_level(); - mono_trace_set_level_string(log_level.get_data()); -} - -GDMonoLog::GDMonoLog() { - singleton = this; -} - -GDMonoLog::~GDMonoLog() { - singleton = nullptr; -} - -#endif // !defined(JAVASCRIPT_ENABLED) diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h deleted file mode 100644 index 93ba6a410e..0000000000 --- a/modules/mono/mono_gd/gd_mono_log.h +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************/ -/* gd_mono_log.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_LOG_H -#define GD_MONO_LOG_H - -#include <mono/utils/mono-logger.h> - -#include "core/typedefs.h" - -#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED) -// We have custom mono log callbacks for WASM and iOS -#define GD_MONO_LOG_ENABLED -#endif - -#ifdef GD_MONO_LOG_ENABLED -#include "core/io/file_access.h" -#endif - -class GDMonoLog { -#ifdef GD_MONO_LOG_ENABLED - int log_level_id = -1; - - Ref<FileAccess> log_file; - String log_file_path; - - bool _try_create_logs_dir(const String &p_logs_dir); - void _delete_old_log_files(const String &p_logs_dir); - - static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data); -#endif - - static GDMonoLog *singleton; - -public: - _FORCE_INLINE_ static GDMonoLog *get_singleton() { return singleton; } - - void initialize(); - - GDMonoLog(); - ~GDMonoLog(); -}; - -#endif // GD_MONO_LOG_H diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp deleted file mode 100644 index a860442764..0000000000 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ /dev/null @@ -1,1824 +0,0 @@ -/*************************************************************************/ -/* gd_mono_marshal.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_marshal.h" - -#include "../signal_awaiter_utils.h" -#include "gd_mono.h" -#include "gd_mono_cache.h" -#include "gd_mono_class.h" - -namespace GDMonoMarshal { - -Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant) { - switch (p_type.type_encoding) { - case MONO_TYPE_BOOLEAN: - return Variant::BOOL; - - case MONO_TYPE_I1: - return Variant::INT; - case MONO_TYPE_I2: - return Variant::INT; - case MONO_TYPE_I4: - return Variant::INT; - case MONO_TYPE_I8: - return Variant::INT; - - case MONO_TYPE_U1: - return Variant::INT; - case MONO_TYPE_U2: - return Variant::INT; - case MONO_TYPE_U4: - return Variant::INT; - case MONO_TYPE_U8: - return Variant::INT; - - case MONO_TYPE_R4: - return Variant::FLOAT; - case MONO_TYPE_R8: - return Variant::FLOAT; - - case MONO_TYPE_STRING: { - return Variant::STRING; - } break; - - case MONO_TYPE_VALUETYPE: { - GDMonoClass *vtclass = p_type.type_class; - - if (vtclass == CACHED_CLASS(Vector2)) { - return Variant::VECTOR2; - } - - if (vtclass == CACHED_CLASS(Vector2i)) { - return Variant::VECTOR2I; - } - - if (vtclass == CACHED_CLASS(Rect2)) { - return Variant::RECT2; - } - - if (vtclass == CACHED_CLASS(Rect2i)) { - return Variant::RECT2I; - } - - if (vtclass == CACHED_CLASS(Transform2D)) { - return Variant::TRANSFORM2D; - } - - if (vtclass == CACHED_CLASS(Vector3)) { - return Variant::VECTOR3; - } - - if (vtclass == CACHED_CLASS(Vector3i)) { - return Variant::VECTOR3I; - } - if (vtclass == CACHED_CLASS(Vector4)) { - return Variant::VECTOR4; - } - - if (vtclass == CACHED_CLASS(Vector4i)) { - return Variant::VECTOR4I; - } - - if (vtclass == CACHED_CLASS(Basis)) { - return Variant::BASIS; - } - - if (vtclass == CACHED_CLASS(Quaternion)) { - return Variant::QUATERNION; - } - - if (vtclass == CACHED_CLASS(Transform3D)) { - return Variant::TRANSFORM3D; - } - if (vtclass == CACHED_CLASS(Projection)) { - return Variant::PROJECTION; - } - if (vtclass == CACHED_CLASS(AABB)) { - return Variant::AABB; - } - - if (vtclass == CACHED_CLASS(Color)) { - return Variant::COLOR; - } - - if (vtclass == CACHED_CLASS(Plane)) { - return Variant::PLANE; - } - - if (vtclass == CACHED_CLASS(Callable)) { - return Variant::CALLABLE; - } - - if (vtclass == CACHED_CLASS(SignalInfo)) { - return Variant::SIGNAL; - } - - if (mono_class_is_enum(vtclass->get_mono_ptr())) { - return Variant::INT; - } - } break; - - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: { - MonoClass *elem_class = mono_class_get_element_class(p_type.type_class->get_mono_ptr()); - - if (elem_class == CACHED_CLASS_RAW(MonoObject)) { - return Variant::ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(uint8_t)) { - return Variant::PACKED_BYTE_ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(int32_t)) { - return Variant::PACKED_INT32_ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(int64_t)) { - return Variant::PACKED_INT64_ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(float)) { - return Variant::PACKED_FLOAT32_ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(double)) { - return Variant::PACKED_FLOAT64_ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(String)) { - return Variant::PACKED_STRING_ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(Vector2)) { - return Variant::PACKED_VECTOR2_ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(Vector3)) { - return Variant::PACKED_VECTOR3_ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(Color)) { - return Variant::PACKED_COLOR_ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(StringName)) { - return Variant::ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(NodePath)) { - return Variant::ARRAY; - } - - if (elem_class == CACHED_CLASS_RAW(RID)) { - return Variant::ARRAY; - } - - if (mono_class_is_enum(elem_class)) { - return Variant::ARRAY; - } - - GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(elem_class); - if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) { - return Variant::ARRAY; - } - } break; - - case MONO_TYPE_CLASS: { - GDMonoClass *type_class = p_type.type_class; - - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - return Variant::OBJECT; - } - - if (CACHED_CLASS(StringName) == type_class) { - return Variant::STRING_NAME; - } - - if (CACHED_CLASS(NodePath) == type_class) { - return Variant::NODE_PATH; - } - - if (CACHED_CLASS(RID) == type_class) { - return Variant::RID; - } - - if (CACHED_CLASS(Dictionary) == type_class) { - return Variant::DICTIONARY; - } - - if (CACHED_CLASS(Array) == type_class) { - return Variant::ARRAY; - } - - // IDictionary - if (p_type.type_class == CACHED_CLASS(System_Collections_IDictionary)) { - return Variant::DICTIONARY; - } - - // ICollection or IEnumerable - if (p_type.type_class == CACHED_CLASS(System_Collections_ICollection) || - p_type.type_class == CACHED_CLASS(System_Collections_IEnumerable)) { - return Variant::ARRAY; - } - } break; - - case MONO_TYPE_OBJECT: { - if (r_nil_is_variant) { - *r_nil_is_variant = true; - } - return Variant::NIL; - } break; - - case MONO_TYPE_GENERICINST: { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); - - // Godot.Collections.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - return Variant::DICTIONARY; - } - - // Godot.Collections.Array<T> - if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - return Variant::ARRAY; - } - - // System.Collections.Generic.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { - return Variant::DICTIONARY; - } - - // System.Collections.Generic.List<T> - if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { - return Variant::ARRAY; - } - - // IDictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { - return Variant::DICTIONARY; - } - - // ICollection<T> or IEnumerable<T> - if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { - return Variant::ARRAY; - } - - // GodotObject - GDMonoClass *type_class = p_type.type_class; - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - return Variant::OBJECT; - } - } break; - - default: { - } break; - } - - if (r_nil_is_variant) { - *r_nil_is_variant = false; - } - - // Unknown - return Variant::NIL; -} - -bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) { - switch (p_array_type.type_encoding) { - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: { - MonoClass *elem_class = mono_class_get_element_class(p_array_type.type_class->get_mono_ptr()); - r_elem_type = ManagedType::from_class(elem_class); - return true; - } break; - case MONO_TYPE_GENERICINST: { - MonoReflectionType *array_reftype = mono_type_get_object(mono_domain_get(), p_array_type.type_class->get_mono_type()); - - if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype) || - GDMonoUtils::Marshal::type_is_system_generic_list(array_reftype) || - GDMonoUtils::Marshal::type_is_generic_icollection(array_reftype) || - GDMonoUtils::Marshal::type_is_generic_ienumerable(array_reftype)) { - MonoReflectionType *elem_reftype; - - GDMonoUtils::Marshal::array_get_element_type(array_reftype, &elem_reftype); - - r_elem_type = ManagedType::from_reftype(elem_reftype); - return true; - } - } break; - default: { - } break; - } - - return false; -} - -MonoString *variant_to_mono_string(const Variant &p_var) { - if (p_var.get_type() == Variant::NIL) { - return nullptr; // Otherwise, Variant -> String would return the string "Null" - } - return mono_string_from_godot(p_var.operator String()); -} - -MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class) { - MonoArrayType *array_type = mono_type_get_array_type(p_type_class->get_mono_type()); - - if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { - return Array_to_mono_array(p_var.operator Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { - return PackedByteArray_to_mono_array(p_var.operator PackedByteArray()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { - return PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) { - return PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(float)) { - return PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(double)) { - return PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(String)) { - return PackedStringArray_to_mono_array(p_var.operator PackedStringArray()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { - return PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { - return PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Color)) { - return PackedColorArray_to_mono_array(p_var.operator PackedColorArray()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(StringName)) { - return Array_to_mono_array(p_var.operator Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) { - return Array_to_mono_array(p_var.operator Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(RID)) { - return Array_to_mono_array(p_var.operator Array()); - } - - if (mono_class_is_assignable_from(CACHED_CLASS(GodotObject)->get_mono_ptr(), array_type->eklass)) { - return Array_to_mono_array(p_var.operator ::Array(), array_type->eklass); - } - - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to array of unsupported element type:" + GDMonoClass::get_full_name(array_type->eklass) + "'."); -} - -MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class) { - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) { - return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); - } - - if (CACHED_CLASS(StringName) == p_type_class) { - return GDMonoUtils::create_managed_from(p_var.operator StringName()); - } - - if (CACHED_CLASS(NodePath) == p_type_class) { - return GDMonoUtils::create_managed_from(p_var.operator NodePath()); - } - - if (CACHED_CLASS(RID) == p_type_class) { - return GDMonoUtils::create_managed_from(p_var.operator ::RID()); - } - - // Godot.Collections.Dictionary or IDictionary - if (CACHED_CLASS(Dictionary) == p_type_class || CACHED_CLASS(System_Collections_IDictionary) == p_type_class) { - return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary)); - } - - // Godot.Collections.Array or ICollection or IEnumerable - if (CACHED_CLASS(Array) == p_type_class || - CACHED_CLASS(System_Collections_ICollection) == p_type_class || - CACHED_CLASS(System_Collections_IEnumerable) == p_type_class) { - return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array)); - } - - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type: '" + p_type_class->get_full_name() + "'."); -} - -MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class) { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type_class->get_mono_type()); - - // Godot.Collections.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), p_type_class); - } - - // Godot.Collections.Array<T> - if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - return GDMonoUtils::create_managed_from(p_var.operator Array(), p_type_class); - } - - // System.Collections.Generic.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { - MonoReflectionType *key_reftype = nullptr; - MonoReflectionType *value_reftype = nullptr; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - return Dictionary_to_system_generic_dict(p_var.operator Dictionary(), p_type_class, key_reftype, value_reftype); - } - - // System.Collections.Generic.List<T> - if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { - MonoReflectionType *elem_reftype = nullptr; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - return Array_to_system_generic_list(p_var.operator Array(), p_type_class, elem_reftype); - } - - // IDictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { - MonoReflectionType *key_reftype; - MonoReflectionType *value_reftype; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); - - return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), godot_dict_class); - } - - // ICollection<T> or IEnumerable<T> - if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { - MonoReflectionType *elem_reftype; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); - - return GDMonoUtils::create_managed_from(p_var.operator Array(), godot_array_class); - } - - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) { - return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); - } - - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported generic type: '" + p_type_class->get_full_name() + "'."); -} - -MonoObject *variant_to_mono_object(const Variant &p_var) { - // Variant - switch (p_var.get_type()) { - case Variant::BOOL: { - MonoBoolean val = p_var.operator bool(); - return BOX_BOOLEAN(val); - } - case Variant::INT: { - int64_t val = p_var.operator int64_t(); - return BOX_INT64(val); - } - case Variant::FLOAT: { -#ifdef REAL_T_IS_DOUBLE - double val = p_var.operator double(); - return BOX_DOUBLE(val); -#else - float val = p_var.operator float(); - return BOX_FLOAT(val); -#endif - } - case Variant::STRING: - return (MonoObject *)mono_string_from_godot(p_var.operator String()); - case Variant::VECTOR2: { - GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var.operator ::Vector2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); - } - case Variant::VECTOR2I: { - GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var.operator ::Vector2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from); - } - case Variant::RECT2: { - GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var.operator ::Rect2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); - } - case Variant::RECT2I: { - GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var.operator ::Rect2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from); - } - case Variant::VECTOR3: { - GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var.operator ::Vector3()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); - } - case Variant::VECTOR3I: { - GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var.operator ::Vector3i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from); - } - case Variant::TRANSFORM2D: { - GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var.operator ::Transform2D()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); - } - case Variant::VECTOR4: { - GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_var.operator ::Vector4()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector4), &from); - } - case Variant::VECTOR4I: { - GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_var.operator ::Vector4i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector4i), &from); - } - case Variant::PLANE: { - GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); - } - case Variant::QUATERNION: { - GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_var.operator ::Quaternion()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quaternion), &from); - } - case Variant::AABB: { - GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); - } - case Variant::BASIS: { - GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); - } - case Variant::TRANSFORM3D: { - GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_var.operator ::Transform3D()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform3D), &from); - } - case Variant::PROJECTION: { - GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_var.operator ::Projection()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Projection), &from); - } - case Variant::COLOR: { - GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); - } - case Variant::STRING_NAME: - return GDMonoUtils::create_managed_from(p_var.operator StringName()); - case Variant::NODE_PATH: - return GDMonoUtils::create_managed_from(p_var.operator NodePath()); - case Variant::RID: - return GDMonoUtils::create_managed_from(p_var.operator ::RID()); - case Variant::OBJECT: - return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); - case Variant::CALLABLE: { - GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from); - } - case Variant::SIGNAL: { - GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from); - } - case Variant::DICTIONARY: - return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary)); - case Variant::ARRAY: - return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array)); - case Variant::PACKED_BYTE_ARRAY: - return (MonoObject *)PackedByteArray_to_mono_array(p_var.operator PackedByteArray()); - case Variant::PACKED_INT32_ARRAY: - return (MonoObject *)PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array()); - case Variant::PACKED_INT64_ARRAY: - return (MonoObject *)PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array()); - case Variant::PACKED_FLOAT32_ARRAY: - return (MonoObject *)PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array()); - case Variant::PACKED_FLOAT64_ARRAY: - return (MonoObject *)PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array()); - case Variant::PACKED_STRING_ARRAY: - return (MonoObject *)PackedStringArray_to_mono_array(p_var.operator PackedStringArray()); - case Variant::PACKED_VECTOR2_ARRAY: - return (MonoObject *)PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array()); - case Variant::PACKED_VECTOR3_ARRAY: - return (MonoObject *)PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array()); - case Variant::PACKED_COLOR_ARRAY: - return (MonoObject *)PackedColorArray_to_mono_array(p_var.operator PackedColorArray()); - default: - return nullptr; - } -} - -size_t variant_get_managed_unboxed_size(const ManagedType &p_type) { - // This method prints no errors for unsupported types. It's called on all methods, not only - // those that end up being invoked with Variant parameters. - - // For MonoObject* we return 0, as it doesn't need to be stored. - constexpr size_t zero_for_mono_object = 0; - - switch (p_type.type_encoding) { - case MONO_TYPE_BOOLEAN: - return sizeof(MonoBoolean); - case MONO_TYPE_CHAR: - return sizeof(uint16_t); - case MONO_TYPE_I1: - return sizeof(int8_t); - case MONO_TYPE_I2: - return sizeof(int16_t); - case MONO_TYPE_I4: - return sizeof(int32_t); - case MONO_TYPE_I8: - return sizeof(int64_t); - case MONO_TYPE_U1: - return sizeof(uint8_t); - case MONO_TYPE_U2: - return sizeof(uint16_t); - case MONO_TYPE_U4: - return sizeof(uint32_t); - case MONO_TYPE_U8: - return sizeof(uint64_t); - case MONO_TYPE_R4: - return sizeof(float); - case MONO_TYPE_R8: - return sizeof(double); - case MONO_TYPE_VALUETYPE: { - GDMonoClass *vtclass = p_type.type_class; - -#define RETURN_CHECK_FOR_STRUCT(m_struct) \ - if (vtclass == CACHED_CLASS(m_struct)) { \ - return sizeof(M_##m_struct); \ - } - - RETURN_CHECK_FOR_STRUCT(Vector2); - RETURN_CHECK_FOR_STRUCT(Vector2i); - RETURN_CHECK_FOR_STRUCT(Rect2); - RETURN_CHECK_FOR_STRUCT(Rect2i); - RETURN_CHECK_FOR_STRUCT(Transform2D); - RETURN_CHECK_FOR_STRUCT(Vector3); - RETURN_CHECK_FOR_STRUCT(Vector3i); - RETURN_CHECK_FOR_STRUCT(Basis); - RETURN_CHECK_FOR_STRUCT(Quaternion); - RETURN_CHECK_FOR_STRUCT(Transform3D); - RETURN_CHECK_FOR_STRUCT(AABB); - RETURN_CHECK_FOR_STRUCT(Color); - RETURN_CHECK_FOR_STRUCT(Plane); - RETURN_CHECK_FOR_STRUCT(Callable); - RETURN_CHECK_FOR_STRUCT(SignalInfo); - -#undef RETURN_CHECK_FOR_STRUCT - - if (mono_class_is_enum(vtclass->get_mono_ptr())) { - MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); - switch (mono_type_get_type(enum_basetype)) { - case MONO_TYPE_BOOLEAN: - return sizeof(MonoBoolean); - case MONO_TYPE_CHAR: - return sizeof(uint16_t); - case MONO_TYPE_I1: - return sizeof(int8_t); - case MONO_TYPE_I2: - return sizeof(int16_t); - case MONO_TYPE_I4: - return sizeof(int32_t); - case MONO_TYPE_I8: - return sizeof(int64_t); - case MONO_TYPE_U1: - return sizeof(uint8_t); - case MONO_TYPE_U2: - return sizeof(uint16_t); - case MONO_TYPE_U4: - return sizeof(uint32_t); - case MONO_TYPE_U8: - return sizeof(uint64_t); - default: { - // Enum with unsupported base type. We return nullptr MonoObject* on error. - return zero_for_mono_object; - } - } - } - - // Enum with unsupported value type. We return nullptr MonoObject* on error. - } break; - case MONO_TYPE_STRING: - return zero_for_mono_object; - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_GENERICINST: - return zero_for_mono_object; - case MONO_TYPE_OBJECT: - return zero_for_mono_object; - } - - // Unsupported type encoding. We return nullptr MonoObject* on error. - return zero_for_mono_object; -} - -void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) { -#define RETURN_TYPE_VAL(m_type, m_val) \ - *reinterpret_cast<m_type *>(r_buffer) = m_val; \ - r_offset += sizeof(m_type); \ - return r_buffer; - - switch (p_type.type_encoding) { - case MONO_TYPE_BOOLEAN: - RETURN_TYPE_VAL(MonoBoolean, (MonoBoolean)p_var.operator bool()); - case MONO_TYPE_CHAR: - RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short()); - case MONO_TYPE_I1: - RETURN_TYPE_VAL(int8_t, p_var.operator signed char()); - case MONO_TYPE_I2: - RETURN_TYPE_VAL(int16_t, p_var.operator signed short()); - case MONO_TYPE_I4: - RETURN_TYPE_VAL(int32_t, p_var.operator signed int()); - case MONO_TYPE_I8: - RETURN_TYPE_VAL(int64_t, p_var.operator int64_t()); - case MONO_TYPE_U1: - RETURN_TYPE_VAL(uint8_t, p_var.operator unsigned char()); - case MONO_TYPE_U2: - RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short()); - case MONO_TYPE_U4: - RETURN_TYPE_VAL(uint32_t, p_var.operator unsigned int()); - case MONO_TYPE_U8: - RETURN_TYPE_VAL(uint64_t, p_var.operator uint64_t()); - case MONO_TYPE_R4: - RETURN_TYPE_VAL(float, p_var.operator float()); - case MONO_TYPE_R8: - RETURN_TYPE_VAL(double, p_var.operator double()); - case MONO_TYPE_VALUETYPE: { - GDMonoClass *vtclass = p_type.type_class; - -#define RETURN_CHECK_FOR_STRUCT(m_struct) \ - if (vtclass == CACHED_CLASS(m_struct)) { \ - GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \ - RETURN_TYPE_VAL(M_##m_struct, from); \ - } - - RETURN_CHECK_FOR_STRUCT(Vector2); - RETURN_CHECK_FOR_STRUCT(Vector2i); - RETURN_CHECK_FOR_STRUCT(Rect2); - RETURN_CHECK_FOR_STRUCT(Rect2i); - RETURN_CHECK_FOR_STRUCT(Transform2D); - RETURN_CHECK_FOR_STRUCT(Vector3); - RETURN_CHECK_FOR_STRUCT(Vector3i); - RETURN_CHECK_FOR_STRUCT(Basis); - RETURN_CHECK_FOR_STRUCT(Quaternion); - RETURN_CHECK_FOR_STRUCT(Transform3D); - RETURN_CHECK_FOR_STRUCT(AABB); - RETURN_CHECK_FOR_STRUCT(Color); - RETURN_CHECK_FOR_STRUCT(Plane); - -#undef RETURN_CHECK_FOR_STRUCT - - if (vtclass == CACHED_CLASS(Callable)) { - GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable()); - RETURN_TYPE_VAL(M_Callable, from); - } - - if (vtclass == CACHED_CLASS(SignalInfo)) { - GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal()); - RETURN_TYPE_VAL(M_SignalInfo, from); - } - - if (mono_class_is_enum(vtclass->get_mono_ptr())) { - MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); - switch (mono_type_get_type(enum_basetype)) { - case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_var.operator bool(); - RETURN_TYPE_VAL(MonoBoolean, val); - } - case MONO_TYPE_CHAR: { - uint16_t val = p_var.operator unsigned short(); - RETURN_TYPE_VAL(uint16_t, val); - } - case MONO_TYPE_I1: { - int8_t val = p_var.operator signed char(); - RETURN_TYPE_VAL(int8_t, val); - } - case MONO_TYPE_I2: { - int16_t val = p_var.operator signed short(); - RETURN_TYPE_VAL(int16_t, val); - } - case MONO_TYPE_I4: { - int32_t val = p_var.operator signed int(); - RETURN_TYPE_VAL(int32_t, val); - } - case MONO_TYPE_I8: { - int64_t val = p_var.operator int64_t(); - RETURN_TYPE_VAL(int64_t, val); - } - case MONO_TYPE_U1: { - uint8_t val = p_var.operator unsigned char(); - RETURN_TYPE_VAL(uint8_t, val); - } - case MONO_TYPE_U2: { - uint16_t val = p_var.operator unsigned short(); - RETURN_TYPE_VAL(uint16_t, val); - } - case MONO_TYPE_U4: { - uint32_t val = p_var.operator unsigned int(); - RETURN_TYPE_VAL(uint32_t, val); - } - case MONO_TYPE_U8: { - uint64_t val = p_var.operator uint64_t(); - RETURN_TYPE_VAL(uint64_t, val); - } - default: { - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + GDMonoClass::get_full_name(mono_class_from_mono_type(enum_basetype)) + "'."); - } - } - } - - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + p_type.type_class->get_full_name() + "'."); - } break; -#undef RETURN_TYPE_VAL - case MONO_TYPE_STRING: - return variant_to_mono_string(p_var); - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - return variant_to_mono_array(p_var, p_type.type_class); - case MONO_TYPE_CLASS: - return variant_to_mono_object_of_class(p_var, p_type.type_class); - case MONO_TYPE_GENERICINST: - return variant_to_mono_object_of_genericinst(p_var, p_type.type_class); - case MONO_TYPE_OBJECT: - return variant_to_mono_object(p_var); - } - - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + itos(p_type.type_encoding) + "."); -} - -MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) { - switch (p_type.type_encoding) { - case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_var.operator bool(); - return BOX_BOOLEAN(val); - } - case MONO_TYPE_CHAR: { - uint16_t val = p_var.operator unsigned short(); - return BOX_UINT16(val); - } - case MONO_TYPE_I1: { - int8_t val = p_var.operator signed char(); - return BOX_INT8(val); - } - case MONO_TYPE_I2: { - int16_t val = p_var.operator signed short(); - return BOX_INT16(val); - } - case MONO_TYPE_I4: { - int32_t val = p_var.operator signed int(); - return BOX_INT32(val); - } - case MONO_TYPE_I8: { - int64_t val = p_var.operator int64_t(); - return BOX_INT64(val); - } - case MONO_TYPE_U1: { - uint8_t val = p_var.operator unsigned char(); - return BOX_UINT8(val); - } - case MONO_TYPE_U2: { - uint16_t val = p_var.operator unsigned short(); - return BOX_UINT16(val); - } - case MONO_TYPE_U4: { - uint32_t val = p_var.operator unsigned int(); - return BOX_UINT32(val); - } - case MONO_TYPE_U8: { - uint64_t val = p_var.operator uint64_t(); - return BOX_UINT64(val); - } - case MONO_TYPE_R4: { - float val = p_var.operator float(); - return BOX_FLOAT(val); - } - case MONO_TYPE_R8: { - double val = p_var.operator double(); - return BOX_DOUBLE(val); - } - case MONO_TYPE_VALUETYPE: { - GDMonoClass *vtclass = p_type.type_class; - -#define RETURN_CHECK_FOR_STRUCT(m_struct) \ - if (vtclass == CACHED_CLASS(m_struct)) { \ - GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \ - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_struct), &from); \ - } - - RETURN_CHECK_FOR_STRUCT(Vector2); - RETURN_CHECK_FOR_STRUCT(Vector2i); - RETURN_CHECK_FOR_STRUCT(Rect2); - RETURN_CHECK_FOR_STRUCT(Rect2i); - RETURN_CHECK_FOR_STRUCT(Transform2D); - RETURN_CHECK_FOR_STRUCT(Vector3); - RETURN_CHECK_FOR_STRUCT(Vector3i); - RETURN_CHECK_FOR_STRUCT(Basis); - RETURN_CHECK_FOR_STRUCT(Quaternion); - RETURN_CHECK_FOR_STRUCT(Transform3D); - RETURN_CHECK_FOR_STRUCT(AABB); - RETURN_CHECK_FOR_STRUCT(Color); - RETURN_CHECK_FOR_STRUCT(Plane); - -#undef RETURN_CHECK_FOR_STRUCT - - if (vtclass == CACHED_CLASS(Callable)) { - GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from); - } - - if (vtclass == CACHED_CLASS(SignalInfo)) { - GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from); - } - - if (mono_class_is_enum(vtclass->get_mono_ptr())) { - MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); - MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype); - switch (mono_type_get_type(enum_basetype)) { - case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_var.operator bool(); - return BOX_ENUM(enum_baseclass, val); - } - case MONO_TYPE_CHAR: { - uint16_t val = p_var.operator unsigned short(); - return BOX_ENUM(enum_baseclass, val); - } - case MONO_TYPE_I1: { - int8_t val = p_var.operator signed char(); - return BOX_ENUM(enum_baseclass, val); - } - case MONO_TYPE_I2: { - int16_t val = p_var.operator signed short(); - return BOX_ENUM(enum_baseclass, val); - } - case MONO_TYPE_I4: { - int32_t val = p_var.operator signed int(); - return BOX_ENUM(enum_baseclass, val); - } - case MONO_TYPE_I8: { - int64_t val = p_var.operator int64_t(); - return BOX_ENUM(enum_baseclass, val); - } - case MONO_TYPE_U1: { - uint8_t val = p_var.operator unsigned char(); - return BOX_ENUM(enum_baseclass, val); - } - case MONO_TYPE_U2: { - uint16_t val = p_var.operator unsigned short(); - return BOX_ENUM(enum_baseclass, val); - } - case MONO_TYPE_U4: { - uint32_t val = p_var.operator unsigned int(); - return BOX_ENUM(enum_baseclass, val); - } - case MONO_TYPE_U8: { - uint64_t val = p_var.operator uint64_t(); - return BOX_ENUM(enum_baseclass, val); - } - default: { - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + GDMonoClass::get_full_name(enum_baseclass) + "'."); - } - } - } - - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + p_type.type_class->get_full_name() + "'."); - } break; - case MONO_TYPE_STRING: - return (MonoObject *)variant_to_mono_string(p_var); - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - return (MonoObject *)variant_to_mono_array(p_var, p_type.type_class); - case MONO_TYPE_CLASS: - return variant_to_mono_object_of_class(p_var, p_type.type_class); - case MONO_TYPE_GENERICINST: - return variant_to_mono_object_of_genericinst(p_var, p_type.type_class); - case MONO_TYPE_OBJECT: - return variant_to_mono_object(p_var); - } - - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + itos(p_type.type_encoding) + "."); -} - -Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) { - ERR_FAIL_COND_V(!p_type.type_class, Variant()); - -#ifdef DEBUG_ENABLED - CRASH_COND_MSG(p_type.type_encoding == MONO_TYPE_OBJECT, "Type of object should be known."); -#endif - - switch (p_type.type_encoding) { - case MONO_TYPE_BOOLEAN: - return (bool)unbox<MonoBoolean>(p_obj); - case MONO_TYPE_CHAR: - return unbox<uint16_t>(p_obj); - case MONO_TYPE_I1: - return unbox<int8_t>(p_obj); - case MONO_TYPE_I2: - return unbox<int16_t>(p_obj); - case MONO_TYPE_I4: - return unbox<int32_t>(p_obj); - case MONO_TYPE_I8: - return unbox<int64_t>(p_obj); - case MONO_TYPE_U1: - return unbox<uint8_t>(p_obj); - case MONO_TYPE_U2: - return unbox<uint16_t>(p_obj); - case MONO_TYPE_U4: - return unbox<uint32_t>(p_obj); - case MONO_TYPE_U8: - return unbox<uint64_t>(p_obj); - case MONO_TYPE_R4: - return unbox<float>(p_obj); - case MONO_TYPE_R8: - return unbox<double>(p_obj); - case MONO_TYPE_VALUETYPE: { - GDMonoClass *vtclass = p_type.type_class; - - if (vtclass == CACHED_CLASS(Vector2)) { - return MARSHALLED_IN(Vector2, unbox_addr<GDMonoMarshal::M_Vector2>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Vector2i)) { - return MARSHALLED_IN(Vector2i, unbox_addr<GDMonoMarshal::M_Vector2i>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Rect2)) { - return MARSHALLED_IN(Rect2, unbox_addr<GDMonoMarshal::M_Rect2>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Rect2i)) { - return MARSHALLED_IN(Rect2i, unbox_addr<GDMonoMarshal::M_Rect2i>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Transform2D)) { - return MARSHALLED_IN(Transform2D, unbox_addr<GDMonoMarshal::M_Transform2D>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Vector3)) { - return MARSHALLED_IN(Vector3, unbox_addr<GDMonoMarshal::M_Vector3>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Vector3i)) { - return MARSHALLED_IN(Vector3i, unbox_addr<GDMonoMarshal::M_Vector3i>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Basis)) { - return MARSHALLED_IN(Basis, unbox_addr<GDMonoMarshal::M_Basis>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Quaternion)) { - return MARSHALLED_IN(Quaternion, unbox_addr<GDMonoMarshal::M_Quaternion>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Transform3D)) { - return MARSHALLED_IN(Transform3D, unbox_addr<GDMonoMarshal::M_Transform3D>(p_obj)); - } - - if (vtclass == CACHED_CLASS(AABB)) { - return MARSHALLED_IN(AABB, unbox_addr<GDMonoMarshal::M_AABB>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Color)) { - return MARSHALLED_IN(Color, unbox_addr<GDMonoMarshal::M_Color>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Plane)) { - return MARSHALLED_IN(Plane, unbox_addr<GDMonoMarshal::M_Plane>(p_obj)); - } - - if (vtclass == CACHED_CLASS(Callable)) { - return managed_to_callable(unbox<GDMonoMarshal::M_Callable>(p_obj)); - } - - if (vtclass == CACHED_CLASS(SignalInfo)) { - return managed_to_signal_info(unbox<GDMonoMarshal::M_SignalInfo>(p_obj)); - } - - if (mono_class_is_enum(vtclass->get_mono_ptr())) { - return unbox<int32_t>(p_obj); - } - } break; - case MONO_TYPE_STRING: { - if (p_obj == nullptr) { - return Variant(); // NIL - } - return mono_string_to_godot_not_null((MonoString *)p_obj); - } break; - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type()); - - if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { - return mono_array_to_Array((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { - return mono_array_to_PackedByteArray((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { - return mono_array_to_PackedInt32Array((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) { - return mono_array_to_PackedInt64Array((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(float)) { - return mono_array_to_PackedFloat32Array((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(double)) { - return mono_array_to_PackedFloat64Array((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(String)) { - return mono_array_to_PackedStringArray((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { - return mono_array_to_PackedVector2Array((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { - return mono_array_to_PackedVector3Array((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Color)) { - return mono_array_to_PackedColorArray((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(StringName)) { - return mono_array_to_Array((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) { - return mono_array_to_Array((MonoArray *)p_obj); - } - - if (array_type->eklass == CACHED_CLASS_RAW(RID)) { - return mono_array_to_Array((MonoArray *)p_obj); - } - - GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); - if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) { - return mono_array_to_Array((MonoArray *)p_obj); - } - - if (p_fail_with_err) { - ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant."); - } else { - return Variant(); - } - } break; - case MONO_TYPE_CLASS: { - GDMonoClass *type_class = p_type.type_class; - - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj)); - if (ptr != nullptr) { - RefCounted *rc = Object::cast_to<RefCounted>(ptr); - return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr); - } - return Variant(); - } - - if (CACHED_CLASS(StringName) == type_class) { - StringName *ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_obj)); - return ptr ? Variant(*ptr) : Variant(); - } - - if (CACHED_CLASS(NodePath) == type_class) { - NodePath *ptr = unbox<NodePath *>(CACHED_FIELD(NodePath, ptr)->get_value(p_obj)); - return ptr ? Variant(*ptr) : Variant(); - } - - if (CACHED_CLASS(RID) == type_class) { - RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj)); - return ptr ? Variant(*ptr) : Variant(); - } - - // Godot.Collections.Dictionary - if (CACHED_CLASS(Dictionary) == type_class) { - MonoException *exc = nullptr; - Dictionary *ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr).invoke(p_obj, &exc); - UNHANDLED_EXCEPTION(exc); - return ptr ? Variant(*ptr) : Variant(); - } - - // Godot.Collections.Array - if (CACHED_CLASS(Array) == type_class) { - MonoException *exc = nullptr; - Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc); - UNHANDLED_EXCEPTION(exc); - return ptr ? Variant(*ptr) : Variant(); - } - } break; - case MONO_TYPE_GENERICINST: { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); - - // Godot.Collections.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - MonoException *exc = nullptr; - MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc); - UNHANDLED_EXCEPTION(exc); - return *unbox<Dictionary *>(ret); - } - - // Godot.Collections.Array<T> - if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - MonoException *exc = nullptr; - MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc); - UNHANDLED_EXCEPTION(exc); - return *unbox<Array *>(ret); - } - - // System.Collections.Generic.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { - MonoReflectionType *key_reftype = nullptr; - MonoReflectionType *value_reftype = nullptr; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - return system_generic_dict_to_Dictionary(p_obj, p_type.type_class, key_reftype, value_reftype); - } - - // System.Collections.Generic.List<T> - if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { - MonoReflectionType *elem_reftype = nullptr; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - return system_generic_list_to_Array_variant(p_obj, p_type.type_class, elem_reftype); - } - - // GodotObject - GDMonoClass *type_class = p_type.type_class; - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj)); - if (ptr != nullptr) { - RefCounted *rc = Object::cast_to<RefCounted>(ptr); - return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr); - } - return Variant(); - } - } break; - } - - if (p_fail_with_err) { - ERR_FAIL_V_MSG(Variant(), "Attempted to convert an unmarshallable managed type to Variant. Name: '" + p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + "."); - } else { - return Variant(); - } -} - -Variant mono_object_to_variant(MonoObject *p_obj) { - if (!p_obj) { - return Variant(); - } - - ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj)); - - return mono_object_to_variant_impl(p_obj, type); -} - -Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) { - if (!p_obj) { - return Variant(); - } - - return mono_object_to_variant_impl(p_obj, p_type); -} - -Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type) { - if (!p_obj) { - return Variant(); - } - - return mono_object_to_variant_impl(p_obj, p_type, /* fail_with_err: */ false); -} - -String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) { - if (p_obj == nullptr) { - return String("null"); - } - - ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj)); - Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type); - - if (var.get_type() == Variant::NIL) { // `&& p_obj != nullptr` but omitted because always true - // Cannot convert MonoObject* to Variant; fallback to 'ToString()'. - MonoException *exc = nullptr; - MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc); - - if (exc) { - if (r_exc) { - *r_exc = exc; - } - return String(); - } - - return GDMonoMarshal::mono_string_to_godot(mono_str); - } else { - return var.operator String(); - } -} - -MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) { - String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) + - ", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)"; - GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true); - CRASH_COND(ctor == nullptr); - - MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); - ERR_FAIL_NULL_V(mono_object, nullptr); - - GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype); - MonoObject *godot_dict = GDMonoUtils::create_managed_from(p_dict, godot_dict_class); - - void *ctor_args[1] = { godot_dict }; - - MonoException *exc = nullptr; - ctor->invoke_raw(mono_object, ctor_args, &exc); - UNHANDLED_EXCEPTION(exc); - - return mono_object; -} - -Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]] GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) { - GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype); - String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) + - ", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)"; - GDMonoMethod *godot_dict_ctor = godot_dict_class->get_method_with_desc(ctor_desc, true); - CRASH_COND(godot_dict_ctor == nullptr); - - MonoObject *godot_dict = mono_object_new(mono_domain_get(), godot_dict_class->get_mono_ptr()); - ERR_FAIL_NULL_V(godot_dict, Dictionary()); - - void *ctor_args[1] = { p_obj }; - - MonoException *exc = nullptr; - godot_dict_ctor->invoke_raw(godot_dict, ctor_args, &exc); - UNHANDLED_EXCEPTION(exc); - - exc = nullptr; - MonoObject *ret = godot_dict_class->get_method("GetPtr")->invoke(godot_dict, &exc); - UNHANDLED_EXCEPTION(exc); - - return *unbox<Dictionary *>(ret); -} - -MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) { - MonoType *elem_type = mono_reflection_type_get_type(p_elem_reftype); - - String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + GDMonoUtils::get_type_desc(elem_type) + ">)"; - GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true); - CRASH_COND(ctor == nullptr); - - MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); - ERR_FAIL_NULL_V(mono_object, nullptr); - - GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(p_elem_reftype); - MonoObject *godot_array = GDMonoUtils::create_managed_from(p_array, godot_array_class); - - void *ctor_args[1] = { godot_array }; - - MonoException *exc = nullptr; - ctor->invoke_raw(mono_object, ctor_args, &exc); - UNHANDLED_EXCEPTION(exc); - - return mono_object; -} - -Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_class, [[maybe_unused]] MonoReflectionType *p_elem_reftype) { - GDMonoMethod *to_array = p_class->get_method("ToArray", 0); - CRASH_COND(to_array == nullptr); - - MonoException *exc = nullptr; - MonoObject *array = to_array->invoke_raw(p_obj, nullptr, &exc); - UNHANDLED_EXCEPTION(exc); - - ERR_FAIL_NULL_V(array, Variant()); - - ManagedType type = ManagedType::from_class(mono_object_get_class(array)); - - bool result_is_array = type.type_encoding != MONO_TYPE_SZARRAY && type.type_encoding != MONO_TYPE_ARRAY; - ERR_FAIL_COND_V(result_is_array, Variant()); - - return mono_object_to_variant(array, type); -} - -MonoArray *Array_to_mono_array(const Array &p_array) { - int length = p_array.size(); - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), length); - - for (int i = 0; i < length; i++) { - MonoObject *boxed = variant_to_mono_object(p_array[i]); - mono_array_setref(ret, i, boxed); - } - - return ret; -} - -MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class) { - int length = p_array.size(); - MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class, length); - - for (int i = 0; i < length; i++) { - MonoObject *boxed = variant_to_mono_object(p_array[i]); - mono_array_setref(ret, i, boxed); - } - - return ret; -} - -Array mono_array_to_Array(MonoArray *p_array) { - Array ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - - for (int i = 0; i < length; i++) { - MonoObject *elem = mono_array_get(p_array, MonoObject *, i); - ret[i] = mono_object_to_variant(elem); - } - - return ret; -} - -MonoArray *PackedInt32Array_to_mono_array(const PackedInt32Array &p_array) { - const int32_t *src = p_array.ptr(); - int length = p_array.size(); - - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), length); - - int32_t *dst = mono_array_addr(ret, int32_t, 0); - memcpy(dst, src, length * sizeof(int32_t)); - - return ret; -} - -PackedInt32Array mono_array_to_PackedInt32Array(MonoArray *p_array) { - PackedInt32Array ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - int32_t *dst = ret.ptrw(); - - const int32_t *src = mono_array_addr(p_array, int32_t, 0); - memcpy(dst, src, length * sizeof(int32_t)); - - return ret; -} - -MonoArray *PackedInt64Array_to_mono_array(const PackedInt64Array &p_array) { - const int64_t *src = p_array.ptr(); - int length = p_array.size(); - - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int64_t), length); - - int64_t *dst = mono_array_addr(ret, int64_t, 0); - memcpy(dst, src, length * sizeof(int64_t)); - - return ret; -} - -PackedInt64Array mono_array_to_PackedInt64Array(MonoArray *p_array) { - PackedInt64Array ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - int64_t *dst = ret.ptrw(); - - const int64_t *src = mono_array_addr(p_array, int64_t, 0); - memcpy(dst, src, length * sizeof(int64_t)); - - return ret; -} - -MonoArray *PackedByteArray_to_mono_array(const PackedByteArray &p_array) { - const uint8_t *src = p_array.ptr(); - int length = p_array.size(); - - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), length); - - uint8_t *dst = mono_array_addr(ret, uint8_t, 0); - memcpy(dst, src, length * sizeof(uint8_t)); - - return ret; -} - -PackedByteArray mono_array_to_PackedByteArray(MonoArray *p_array) { - PackedByteArray ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - uint8_t *dst = ret.ptrw(); - - const uint8_t *src = mono_array_addr(p_array, uint8_t, 0); - memcpy(dst, src, length * sizeof(uint8_t)); - - return ret; -} - -MonoArray *PackedFloat32Array_to_mono_array(const PackedFloat32Array &p_array) { - const float *src = p_array.ptr(); - int length = p_array.size(); - - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(float), length); - - float *dst = mono_array_addr(ret, float, 0); - memcpy(dst, src, length * sizeof(float)); - - return ret; -} - -PackedFloat32Array mono_array_to_PackedFloat32Array(MonoArray *p_array) { - PackedFloat32Array ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - float *dst = ret.ptrw(); - - const float *src = mono_array_addr(p_array, float, 0); - memcpy(dst, src, length * sizeof(float)); - - return ret; -} - -MonoArray *PackedFloat64Array_to_mono_array(const PackedFloat64Array &p_array) { - const double *src = p_array.ptr(); - int length = p_array.size(); - - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(double), length); - - double *dst = mono_array_addr(ret, double, 0); - memcpy(dst, src, length * sizeof(double)); - - return ret; -} - -PackedFloat64Array mono_array_to_PackedFloat64Array(MonoArray *p_array) { - PackedFloat64Array ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - double *dst = ret.ptrw(); - - const double *src = mono_array_addr(p_array, double, 0); - memcpy(dst, src, length * sizeof(double)); - - return ret; -} - -MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array) { - const String *r = p_array.ptr(); - int length = p_array.size(); - - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), length); - - for (int i = 0; i < length; i++) { - MonoString *boxed = mono_string_from_godot(r[i]); - mono_array_setref(ret, i, boxed); - } - - return ret; -} - -PackedStringArray mono_array_to_PackedStringArray(MonoArray *p_array) { - PackedStringArray ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - String *w = ret.ptrw(); - - for (int i = 0; i < length; i++) { - MonoString *elem = mono_array_get(p_array, MonoString *, i); - w[i] = mono_string_to_godot(elem); - } - - return ret; -} - -MonoArray *PackedColorArray_to_mono_array(const PackedColorArray &p_array) { - const Color *src = p_array.ptr(); - int length = p_array.size(); - - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), length); - - if constexpr (InteropLayout::MATCHES_Color) { - Color *dst = mono_array_addr(ret, Color, 0); - memcpy(dst, src, length * sizeof(Color)); - } else { - for (int i = 0; i < length; i++) { - M_Color *raw = (M_Color *)mono_array_addr_with_size(ret, sizeof(M_Color), i); - *raw = MARSHALLED_OUT(Color, src[i]); - } - } - - return ret; -} - -PackedColorArray mono_array_to_PackedColorArray(MonoArray *p_array) { - PackedColorArray ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - Color *dst = ret.ptrw(); - - if constexpr (InteropLayout::MATCHES_Color) { - const Color *src = mono_array_addr(p_array, Color, 0); - memcpy(dst, src, length * sizeof(Color)); - } else { - for (int i = 0; i < length; i++) { - dst[i] = MARSHALLED_IN(Color, (M_Color *)mono_array_addr_with_size(p_array, sizeof(M_Color), i)); - } - } - - return ret; -} - -MonoArray *PackedVector2Array_to_mono_array(const PackedVector2Array &p_array) { - const Vector2 *src = p_array.ptr(); - int length = p_array.size(); - - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), length); - - if constexpr (InteropLayout::MATCHES_Vector2) { - Vector2 *dst = mono_array_addr(ret, Vector2, 0); - memcpy(dst, src, length * sizeof(Vector2)); - } else { - for (int i = 0; i < length; i++) { - M_Vector2 *raw = (M_Vector2 *)mono_array_addr_with_size(ret, sizeof(M_Vector2), i); - *raw = MARSHALLED_OUT(Vector2, src[i]); - } - } - - return ret; -} - -PackedVector2Array mono_array_to_PackedVector2Array(MonoArray *p_array) { - PackedVector2Array ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - Vector2 *dst = ret.ptrw(); - - if constexpr (InteropLayout::MATCHES_Vector2) { - const Vector2 *src = mono_array_addr(p_array, Vector2, 0); - memcpy(dst, src, length * sizeof(Vector2)); - } else { - for (int i = 0; i < length; i++) { - dst[i] = MARSHALLED_IN(Vector2, (M_Vector2 *)mono_array_addr_with_size(p_array, sizeof(M_Vector2), i)); - } - } - - return ret; -} - -MonoArray *PackedVector3Array_to_mono_array(const PackedVector3Array &p_array) { - const Vector3 *src = p_array.ptr(); - int length = p_array.size(); - - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), length); - - if constexpr (InteropLayout::MATCHES_Vector3) { - Vector3 *dst = mono_array_addr(ret, Vector3, 0); - memcpy(dst, src, length * sizeof(Vector3)); - } else { - for (int i = 0; i < length; i++) { - M_Vector3 *raw = (M_Vector3 *)mono_array_addr_with_size(ret, sizeof(M_Vector3), i); - *raw = MARSHALLED_OUT(Vector3, src[i]); - } - } - - return ret; -} - -PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array) { - PackedVector3Array ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - Vector3 *dst = ret.ptrw(); - - if constexpr (InteropLayout::MATCHES_Vector3) { - const Vector3 *src = mono_array_addr(p_array, Vector3, 0); - memcpy(dst, src, length * sizeof(Vector3)); - } else { - for (int i = 0; i < length; i++) { - dst[i] = MARSHALLED_IN(Vector3, (M_Vector3 *)mono_array_addr_with_size(p_array, sizeof(M_Vector3), i)); - } - } - - return ret; -} - -Callable managed_to_callable(const M_Callable &p_managed_callable) { - if (p_managed_callable.delegate) { - // TODO: Use pooling for ManagedCallable instances. - CallableCustom *managed_callable = memnew(ManagedCallable(p_managed_callable.delegate)); - return Callable(managed_callable); - } else { - Object *target = p_managed_callable.target - ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_callable.target)) - : nullptr; - StringName *method_ptr = p_managed_callable.method_string_name - ? unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name)) - : nullptr; - StringName method = method_ptr ? *method_ptr : StringName(); - return Callable(target, method); - } -} - -M_Callable callable_to_managed(const Callable &p_callable) { - if (p_callable.is_custom()) { - CallableCustom *custom = p_callable.get_custom(); - CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func(); - - if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) { - ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom); - return { - nullptr, nullptr, - managed_callable->get_delegate() - }; - } else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) { - SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom); - return { - GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(signal_awaiter_callable->get_object())), - GDMonoUtils::create_managed_from(signal_awaiter_callable->get_signal()), - nullptr - }; - } else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) { - EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom); - return { - GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(event_signal_callable->get_object())), - GDMonoUtils::create_managed_from(event_signal_callable->get_signal()), - nullptr - }; - } - - // Some other CallableCustom. We only support ManagedCallable. - return { nullptr, nullptr, nullptr }; - } else { - MonoObject *target_managed = GDMonoUtils::unmanaged_get_managed(p_callable.get_object()); - MonoObject *method_string_name_managed = GDMonoUtils::create_managed_from(p_callable.get_method()); - return { target_managed, method_string_name_managed, nullptr }; - } -} - -Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal) { - Object *owner = p_managed_signal.owner - ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_signal.owner)) - : nullptr; - StringName *name_ptr = p_managed_signal.name_string_name - ? unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name)) - : nullptr; - StringName name = name_ptr ? *name_ptr : StringName(); - return Signal(owner, name); -} - -M_SignalInfo signal_info_to_managed(const Signal &p_signal) { - Object *owner = p_signal.get_object(); - MonoObject *owner_managed = GDMonoUtils::unmanaged_get_managed(owner); - MonoObject *name_string_name_managed = GDMonoUtils::create_managed_from(p_signal.get_name()); - return { owner_managed, name_string_name_managed }; -} -} // namespace GDMonoMarshal diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h deleted file mode 100644 index 51f11ab18a..0000000000 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ /dev/null @@ -1,605 +0,0 @@ -/*************************************************************************/ -/* gd_mono_marshal.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_MARSHAL_H -#define GD_MONO_MARSHAL_H - -#include "core/variant/variant.h" - -#include "../managed_callable.h" -#include "gd_mono.h" -#include "gd_mono_utils.h" - -namespace GDMonoMarshal { - -template <typename T> -T unbox(MonoObject *p_obj) { - return *(T *)mono_object_unbox(p_obj); -} - -template <typename T> -T *unbox_addr(MonoObject *p_obj) { - return (T *)mono_object_unbox(p_obj); -} - -#define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x) -#define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x) -#define BOX_INT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int64_t), &x) -#define BOX_INT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int32_t), &x) -#define BOX_INT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int16_t), &x) -#define BOX_INT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int8_t), &x) -#define BOX_UINT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint64_t), &x) -#define BOX_UINT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint32_t), &x) -#define BOX_UINT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint16_t), &x) -#define BOX_UINT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), &x) -#define BOX_BOOLEAN(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(bool), &x) -#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x) -#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x) - -Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant = nullptr); - -bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type); - -// String - -_FORCE_INLINE_ String mono_string_to_godot_not_null(MonoString *p_mono_string) { - char32_t *utf32 = (char32_t *)mono_string_to_utf32(p_mono_string); - String ret = String(utf32); - mono_free(utf32); - return ret; -} - -_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) { - if (p_mono_string == nullptr) { - return String(); - } - - return mono_string_to_godot_not_null(p_mono_string); -} - -_FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) { - return mono_string_from_utf32((mono_unichar4 *)(p_string.get_data())); -} - -// Variant - -size_t variant_get_managed_unboxed_size(const ManagedType &p_type); -void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset); -MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type); - -MonoObject *variant_to_mono_object(const Variant &p_var); -MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class); -MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class); -MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class); -MonoString *variant_to_mono_string(const Variant &p_var); - -// These overloads were added to avoid passing a `const Variant *` to the `const Variant &` -// parameter. That would result in the `Variant(bool)` copy constructor being called as -// pointers are implicitly converted to bool. Implicit conversions are f-ing evil. - -_FORCE_INLINE_ void *variant_to_managed_unboxed(const Variant *p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) { - return variant_to_managed_unboxed(*p_var, p_type, r_buffer, r_offset); -} -_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) { - return variant_to_mono_object(*p_var, p_type); -} -_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) { - return variant_to_mono_object(*p_var); -} -_FORCE_INLINE_ MonoArray *variant_to_mono_array(const Variant *p_var, GDMonoClass *p_type_class) { - return variant_to_mono_array(*p_var, p_type_class); -} -_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_class(const Variant *p_var, GDMonoClass *p_type_class) { - return variant_to_mono_object_of_class(*p_var, p_type_class); -} -_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_genericinst(const Variant *p_var, GDMonoClass *p_type_class) { - return variant_to_mono_object_of_genericinst(*p_var, p_type_class); -} -_FORCE_INLINE_ MonoString *variant_to_mono_string(const Variant *p_var) { - return variant_to_mono_string(*p_var); -} - -Variant mono_object_to_variant(MonoObject *p_obj); -Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type); -Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type); - -/// Tries to convert the MonoObject* to Variant and then convert the Variant to String. -/// If the MonoObject* cannot be converted to Variant, then 'ToString()' is called instead. -String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc); - -// System.Collections.Generic - -MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype); -Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype); - -MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype); -Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype); - -// Array - -MonoArray *Array_to_mono_array(const Array &p_array); -MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class); -Array mono_array_to_Array(MonoArray *p_array); - -// PackedInt32Array - -MonoArray *PackedInt32Array_to_mono_array(const PackedInt32Array &p_array); -PackedInt32Array mono_array_to_PackedInt32Array(MonoArray *p_array); - -// PackedInt64Array - -MonoArray *PackedInt64Array_to_mono_array(const PackedInt64Array &p_array); -PackedInt64Array mono_array_to_PackedInt64Array(MonoArray *p_array); - -// PackedByteArray - -MonoArray *PackedByteArray_to_mono_array(const PackedByteArray &p_array); -PackedByteArray mono_array_to_PackedByteArray(MonoArray *p_array); - -// PackedFloat32Array - -MonoArray *PackedFloat32Array_to_mono_array(const PackedFloat32Array &p_array); -PackedFloat32Array mono_array_to_PackedFloat32Array(MonoArray *p_array); - -// PackedFloat64Array - -MonoArray *PackedFloat64Array_to_mono_array(const PackedFloat64Array &p_array); -PackedFloat64Array mono_array_to_PackedFloat64Array(MonoArray *p_array); - -// PackedStringArray - -MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array); -PackedStringArray mono_array_to_PackedStringArray(MonoArray *p_array); - -// PackedColorArray - -MonoArray *PackedColorArray_to_mono_array(const PackedColorArray &p_array); -PackedColorArray mono_array_to_PackedColorArray(MonoArray *p_array); - -// PackedVector2Array - -MonoArray *PackedVector2Array_to_mono_array(const PackedVector2Array &p_array); -PackedVector2Array mono_array_to_PackedVector2Array(MonoArray *p_array); - -// PackedVector3Array - -MonoArray *PackedVector3Array_to_mono_array(const PackedVector3Array &p_array); -PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array); - -#pragma pack(push, 1) - -struct M_Callable { - MonoObject *target = nullptr; - MonoObject *method_string_name = nullptr; - MonoDelegate *delegate = nullptr; -}; - -struct M_SignalInfo { - MonoObject *owner = nullptr; - MonoObject *name_string_name = nullptr; -}; - -#pragma pack(pop) - -// Callable -Callable managed_to_callable(const M_Callable &p_managed_callable); -M_Callable callable_to_managed(const Callable &p_callable); - -// SignalInfo -Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal); -M_SignalInfo signal_info_to_managed(const Signal &p_signal); - -// Structures - -namespace InteropLayout { - -enum { - MATCHES_int = (sizeof(int32_t) == sizeof(uint32_t)), - - MATCHES_float = (sizeof(float) == sizeof(uint32_t)), - - MATCHES_double = (sizeof(double) == sizeof(uint64_t)), - -#ifdef REAL_T_IS_DOUBLE - MATCHES_real_t = (sizeof(real_t) == sizeof(uint64_t)), -#else - MATCHES_real_t = (sizeof(real_t) == sizeof(uint32_t)), -#endif - - MATCHES_Vector2 = (MATCHES_real_t && (sizeof(Vector2) == (sizeof(real_t) * 2)) && - offsetof(Vector2, x) == (sizeof(real_t) * 0) && - offsetof(Vector2, y) == (sizeof(real_t) * 1)), - - MATCHES_Vector2i = (MATCHES_int && (sizeof(Vector2i) == (sizeof(int32_t) * 2)) && - offsetof(Vector2i, x) == (sizeof(int32_t) * 0) && - offsetof(Vector2i, y) == (sizeof(int32_t) * 1)), - - MATCHES_Rect2 = (MATCHES_Vector2 && (sizeof(Rect2) == (sizeof(Vector2) * 2)) && - offsetof(Rect2, position) == (sizeof(Vector2) * 0) && - offsetof(Rect2, size) == (sizeof(Vector2) * 1)), - - MATCHES_Rect2i = (MATCHES_Vector2i && (sizeof(Rect2i) == (sizeof(Vector2i) * 2)) && - offsetof(Rect2i, position) == (sizeof(Vector2i) * 0) && - offsetof(Rect2i, size) == (sizeof(Vector2i) * 1)), - - MATCHES_Transform2D = (MATCHES_Vector2 && (sizeof(Transform2D) == (sizeof(Vector2) * 3))), // No field offset required, it stores an array - - MATCHES_Vector3 = (MATCHES_real_t && (sizeof(Vector3) == (sizeof(real_t) * 3)) && - offsetof(Vector3, x) == (sizeof(real_t) * 0) && - offsetof(Vector3, y) == (sizeof(real_t) * 1) && - offsetof(Vector3, z) == (sizeof(real_t) * 2)), - - MATCHES_Vector4 = (MATCHES_real_t && (sizeof(Vector4) == (sizeof(real_t) * 4)) && - offsetof(Vector4, x) == (sizeof(real_t) * 0) && - offsetof(Vector4, y) == (sizeof(real_t) * 1) && - offsetof(Vector4, z) == (sizeof(real_t) * 2) && - offsetof(Vector4, w) == (sizeof(real_t) * 3)), - - MATCHES_Vector4i = (MATCHES_int && (sizeof(Vector4i) == (sizeof(int32_t) * 4)) && - offsetof(Vector4i, x) == (sizeof(int32_t) * 0) && - offsetof(Vector4i, y) == (sizeof(int32_t) * 1) && - offsetof(Vector4i, z) == (sizeof(int32_t) * 2) && - offsetof(Vector4i, w) == (sizeof(int32_t) * 3)), - - MATCHES_Vector3i = (MATCHES_int && (sizeof(Vector3i) == (sizeof(int32_t) * 3)) && - offsetof(Vector3i, x) == (sizeof(int32_t) * 0) && - offsetof(Vector3i, y) == (sizeof(int32_t) * 1) && - offsetof(Vector3i, z) == (sizeof(int32_t) * 2)), - - MATCHES_Basis = (MATCHES_Vector3 && (sizeof(Basis) == (sizeof(Vector3) * 3))), // No field offset required, it stores an array - - MATCHES_Quaternion = (MATCHES_real_t && (sizeof(Quaternion) == (sizeof(real_t) * 4)) && - offsetof(Quaternion, x) == (sizeof(real_t) * 0) && - offsetof(Quaternion, y) == (sizeof(real_t) * 1) && - offsetof(Quaternion, z) == (sizeof(real_t) * 2) && - offsetof(Quaternion, w) == (sizeof(real_t) * 3)), - - MATCHES_Transform3D = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform3D) == (sizeof(Basis) + sizeof(Vector3))) && - offsetof(Transform3D, basis) == 0 && - offsetof(Transform3D, origin) == sizeof(Basis)), - - MATCHES_Projection = (MATCHES_Vector4 && (sizeof(Projection) == (sizeof(Vector4) * 4))), - - MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) && - offsetof(AABB, position) == (sizeof(Vector3) * 0) && - offsetof(AABB, size) == (sizeof(Vector3) * 1)), - - MATCHES_Color = (MATCHES_float && (sizeof(Color) == (sizeof(float) * 4)) && - offsetof(Color, r) == (sizeof(float) * 0) && - offsetof(Color, g) == (sizeof(float) * 1) && - offsetof(Color, b) == (sizeof(float) * 2) && - offsetof(Color, a) == (sizeof(float) * 3)), - - MATCHES_Plane = (MATCHES_Vector3 && MATCHES_real_t && (sizeof(Plane) == (sizeof(Vector3) + sizeof(real_t))) && - offsetof(Plane, normal) == 0 && - offsetof(Plane, d) == sizeof(Vector3)) -}; - -// In the future we may force this if we want to ref return these structs -#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY -/* clang-format off */ -static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 && MATCHES_Vector4 && - MATCHES_Basis && MATCHES_Quaternion && MATCHES_Transform3D && MATCHES_Projection && MATCHES_AABB && MATCHES_Color && - MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i && MATCHES_Vector4i); -/* clang-format on */ -#endif -} // namespace InteropLayout - -#pragma pack(push, 1) - -struct M_Vector2 { - real_t x, y; - - static _FORCE_INLINE_ Vector2 convert_to(const M_Vector2 &p_from) { - return Vector2(p_from.x, p_from.y); - } - - static _FORCE_INLINE_ M_Vector2 convert_from(const Vector2 &p_from) { - M_Vector2 ret = { p_from.x, p_from.y }; - return ret; - } -}; - -struct M_Vector2i { - int32_t x, y; - - static _FORCE_INLINE_ Vector2i convert_to(const M_Vector2i &p_from) { - return Vector2i(p_from.x, p_from.y); - } - - static _FORCE_INLINE_ M_Vector2i convert_from(const Vector2i &p_from) { - M_Vector2i ret = { p_from.x, p_from.y }; - return ret; - } -}; - -struct M_Rect2 { - M_Vector2 position; - M_Vector2 size; - - static _FORCE_INLINE_ Rect2 convert_to(const M_Rect2 &p_from) { - return Rect2(M_Vector2::convert_to(p_from.position), - M_Vector2::convert_to(p_from.size)); - } - - static _FORCE_INLINE_ M_Rect2 convert_from(const Rect2 &p_from) { - M_Rect2 ret = { M_Vector2::convert_from(p_from.position), M_Vector2::convert_from(p_from.size) }; - return ret; - } -}; - -struct M_Rect2i { - M_Vector2i position; - M_Vector2i size; - - static _FORCE_INLINE_ Rect2i convert_to(const M_Rect2i &p_from) { - return Rect2i(M_Vector2i::convert_to(p_from.position), - M_Vector2i::convert_to(p_from.size)); - } - - static _FORCE_INLINE_ M_Rect2i convert_from(const Rect2i &p_from) { - M_Rect2i ret = { M_Vector2i::convert_from(p_from.position), M_Vector2i::convert_from(p_from.size) }; - return ret; - } -}; - -struct M_Transform2D { - M_Vector2 elements[3]; - - static _FORCE_INLINE_ Transform2D convert_to(const M_Transform2D &p_from) { - return Transform2D(p_from.elements[0].x, p_from.elements[0].y, - p_from.elements[1].x, p_from.elements[1].y, - p_from.elements[2].x, p_from.elements[2].y); - } - - static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) { - M_Transform2D ret = { - M_Vector2::convert_from(p_from.columns[0]), - M_Vector2::convert_from(p_from.columns[1]), - M_Vector2::convert_from(p_from.columns[2]) - }; - return ret; - } -}; - -struct M_Vector3 { - real_t x, y, z; - - static _FORCE_INLINE_ Vector3 convert_to(const M_Vector3 &p_from) { - return Vector3(p_from.x, p_from.y, p_from.z); - } - - static _FORCE_INLINE_ M_Vector3 convert_from(const Vector3 &p_from) { - M_Vector3 ret = { p_from.x, p_from.y, p_from.z }; - return ret; - } -}; - -struct M_Vector3i { - int32_t x, y, z; - - static _FORCE_INLINE_ Vector3i convert_to(const M_Vector3i &p_from) { - return Vector3i(p_from.x, p_from.y, p_from.z); - } - - static _FORCE_INLINE_ M_Vector3i convert_from(const Vector3i &p_from) { - M_Vector3i ret = { p_from.x, p_from.y, p_from.z }; - return ret; - } -}; - -struct M_Vector4 { - real_t x, y, z, w; - - static _FORCE_INLINE_ Vector4 convert_to(const M_Vector4 &p_from) { - return Vector4(p_from.x, p_from.y, p_from.z, p_from.w); - } - - static _FORCE_INLINE_ M_Vector4 convert_from(const Vector4 &p_from) { - M_Vector4 ret = { p_from.x, p_from.y, p_from.z, p_from.w }; - return ret; - } -}; - -struct M_Vector4i { - int32_t x, y, z, w; - - static _FORCE_INLINE_ Vector4i convert_to(const M_Vector4i &p_from) { - return Vector4i(p_from.x, p_from.y, p_from.z, p_from.w); - } - - static _FORCE_INLINE_ M_Vector4i convert_from(const Vector4i &p_from) { - M_Vector4i ret = { p_from.x, p_from.y, p_from.z, p_from.w }; - return ret; - } -}; - -struct M_Basis { - M_Vector3 elements[3]; - - static _FORCE_INLINE_ Basis convert_to(const M_Basis &p_from) { - return Basis(M_Vector3::convert_to(p_from.elements[0]), - M_Vector3::convert_to(p_from.elements[1]), - M_Vector3::convert_to(p_from.elements[2])); - } - - static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) { - M_Basis ret = { - M_Vector3::convert_from(p_from.rows[0]), - M_Vector3::convert_from(p_from.rows[1]), - M_Vector3::convert_from(p_from.rows[2]) - }; - return ret; - } -}; - -struct M_Quaternion { - real_t x, y, z, w; - - static _FORCE_INLINE_ Quaternion convert_to(const M_Quaternion &p_from) { - return Quaternion(p_from.x, p_from.y, p_from.z, p_from.w); - } - - static _FORCE_INLINE_ M_Quaternion convert_from(const Quaternion &p_from) { - M_Quaternion ret = { p_from.x, p_from.y, p_from.z, p_from.w }; - return ret; - } -}; - -struct M_Transform3D { - M_Basis basis; - M_Vector3 origin; - - static _FORCE_INLINE_ Transform3D convert_to(const M_Transform3D &p_from) { - return Transform3D(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin)); - } - - static _FORCE_INLINE_ M_Transform3D convert_from(const Transform3D &p_from) { - M_Transform3D ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) }; - return ret; - } -}; - -struct M_Projection { - M_Vector4 vec1; - M_Vector4 vec2; - M_Vector4 vec3; - M_Vector4 vec4; - - static _FORCE_INLINE_ Projection convert_to(const M_Projection &p_from) { - return Projection(M_Vector4::convert_to(p_from.vec1), M_Vector4::convert_to(p_from.vec2), M_Vector4::convert_to(p_from.vec3), M_Vector4::convert_to(p_from.vec4)); - } - - static _FORCE_INLINE_ M_Projection convert_from(const Projection &p_from) { - M_Projection ret = { M_Vector4::convert_from(p_from.matrix[0]), M_Vector4::convert_from(p_from.matrix[1]), M_Vector4::convert_from(p_from.matrix[2]), M_Vector4::convert_from(p_from.matrix[3]) }; - return ret; - } -}; - -struct M_AABB { - M_Vector3 position; - M_Vector3 size; - - static _FORCE_INLINE_ AABB convert_to(const M_AABB &p_from) { - return AABB(M_Vector3::convert_to(p_from.position), M_Vector3::convert_to(p_from.size)); - } - - static _FORCE_INLINE_ M_AABB convert_from(const AABB &p_from) { - M_AABB ret = { M_Vector3::convert_from(p_from.position), M_Vector3::convert_from(p_from.size) }; - return ret; - } -}; - -struct M_Color { - float r, g, b, a; - - static _FORCE_INLINE_ Color convert_to(const M_Color &p_from) { - return Color(p_from.r, p_from.g, p_from.b, p_from.a); - } - - static _FORCE_INLINE_ M_Color convert_from(const Color &p_from) { - M_Color ret = { p_from.r, p_from.g, p_from.b, p_from.a }; - return ret; - } -}; - -struct M_Plane { - M_Vector3 normal; - real_t d; - - static _FORCE_INLINE_ Plane convert_to(const M_Plane &p_from) { - return Plane(M_Vector3::convert_to(p_from.normal), p_from.d); - } - - static _FORCE_INLINE_ M_Plane convert_from(const Plane &p_from) { - M_Plane ret = { M_Vector3::convert_from(p_from.normal), p_from.d }; - return ret; - } -}; - -#pragma pack(pop) - -#define DECL_TYPE_MARSHAL_TEMPLATES(m_type) \ - template <int> \ - _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl(const M_##m_type *p_from); \ - \ - template <> \ - _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<0>(const M_##m_type *p_from) { \ - return M_##m_type::convert_to(*p_from); \ - } \ - \ - template <> \ - _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<1>(const M_##m_type *p_from) { \ - return *reinterpret_cast<const m_type *>(p_from); \ - } \ - \ - _FORCE_INLINE_ m_type marshalled_in_##m_type(const M_##m_type *p_from) { \ - return marshalled_in_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \ - } \ - \ - template <int> \ - _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl(const m_type &p_from); \ - \ - template <> \ - _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<0>(const m_type &p_from) { \ - return M_##m_type::convert_from(p_from); \ - } \ - \ - template <> \ - _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<1>(const m_type &p_from) { \ - return *reinterpret_cast<const M_##m_type *>(&p_from); \ - } \ - \ - _FORCE_INLINE_ M_##m_type marshalled_out_##m_type(const m_type &p_from) { \ - return marshalled_out_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \ - } - -DECL_TYPE_MARSHAL_TEMPLATES(Vector2) -DECL_TYPE_MARSHAL_TEMPLATES(Vector2i) -DECL_TYPE_MARSHAL_TEMPLATES(Rect2) -DECL_TYPE_MARSHAL_TEMPLATES(Rect2i) -DECL_TYPE_MARSHAL_TEMPLATES(Transform2D) -DECL_TYPE_MARSHAL_TEMPLATES(Vector3) -DECL_TYPE_MARSHAL_TEMPLATES(Vector3i) -DECL_TYPE_MARSHAL_TEMPLATES(Basis) -DECL_TYPE_MARSHAL_TEMPLATES(Vector4) -DECL_TYPE_MARSHAL_TEMPLATES(Vector4i) -DECL_TYPE_MARSHAL_TEMPLATES(Quaternion) -DECL_TYPE_MARSHAL_TEMPLATES(Transform3D) -DECL_TYPE_MARSHAL_TEMPLATES(Projection) -DECL_TYPE_MARSHAL_TEMPLATES(AABB) -DECL_TYPE_MARSHAL_TEMPLATES(Color) -DECL_TYPE_MARSHAL_TEMPLATES(Plane) - -#define MARSHALLED_IN(m_type, m_from_ptr) (GDMonoMarshal::marshalled_in_##m_type(m_from_ptr)) -#define MARSHALLED_OUT(m_type, m_from) (GDMonoMarshal::marshalled_out_##m_type(m_from)) -} // namespace GDMonoMarshal - -#endif // GD_MONO_MARSHAL_H diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp deleted file mode 100644 index 6734b44783..0000000000 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/*************************************************************************/ -/* gd_mono_method.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_method.h" - -#include <mono/metadata/attrdefs.h> -#include <mono/metadata/debug-helpers.h> - -#include "gd_mono_cache.h" -#include "gd_mono_class.h" -#include "gd_mono_marshal.h" -#include "gd_mono_utils.h" - -void GDMonoMethod::_update_signature() { - // Apparently MonoMethodSignature needs not to be freed. - // mono_method_signature caches the result, we don't need to cache it ourselves. - - MonoMethodSignature *method_sig = mono_method_signature(mono_method); - _update_signature(method_sig); -} - -void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) { - params_count = mono_signature_get_param_count(p_method_sig); - - MonoType *ret_type = mono_signature_get_return_type(p_method_sig); - if (ret_type) { - return_type.type_encoding = mono_type_get_type(ret_type); - - if (return_type.type_encoding != MONO_TYPE_VOID) { - MonoClass *ret_type_class = mono_class_from_mono_type(ret_type); - return_type.type_class = GDMono::get_singleton()->get_class(ret_type_class); - } - } - - void *iter = nullptr; - MonoType *param_raw_type; - while ((param_raw_type = mono_signature_get_params(p_method_sig, &iter)) != nullptr) { - ManagedType param_type; - - param_type.type_encoding = mono_type_get_type(param_raw_type); - - MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type); - param_type.type_class = GDMono::get_singleton()->get_class(param_type_class); - - param_types.push_back(param_type); - } - - // clear the cache - method_info_fetched = false; - method_info = MethodInfo(); - - for (int i = 0; i < params_count; i++) { - params_buffer_size += GDMonoMarshal::variant_get_managed_unboxed_size(param_types[i]); - } -} - -GDMonoClass *GDMonoMethod::get_enclosing_class() const { - return GDMono::get_singleton()->get_class(mono_method_get_class(mono_method)); -} - -bool GDMonoMethod::is_static() { - return mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_STATIC; -} - -IMonoClassMember::Visibility GDMonoMethod::get_visibility() { - switch (mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) { - case MONO_METHOD_ATTR_PRIVATE: - return IMonoClassMember::PRIVATE; - case MONO_METHOD_ATTR_FAM_AND_ASSEM: - return IMonoClassMember::PROTECTED_AND_INTERNAL; - case MONO_METHOD_ATTR_ASSEM: - return IMonoClassMember::INTERNAL; - case MONO_METHOD_ATTR_FAMILY: - return IMonoClassMember::PROTECTED; - case MONO_METHOD_ATTR_PUBLIC: - return IMonoClassMember::PUBLIC; - default: - ERR_FAIL_V(IMonoClassMember::PRIVATE); - } -} - -MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) const { - MonoException *exc = nullptr; - MonoObject *ret; - - if (params_count > 0) { - void **params = (void **)alloca(params_count * sizeof(void *)); - uint8_t *buffer = (uint8_t *)alloca(params_buffer_size); - unsigned int offset = 0; - - for (int i = 0; i < params_count; i++) { - params[i] = GDMonoMarshal::variant_to_managed_unboxed(p_params[i], param_types[i], buffer + offset, offset); - } - - ret = GDMonoUtils::runtime_invoke(mono_method, p_object, params, &exc); - } else { - ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc); - } - - if (exc) { - ret = nullptr; - if (r_exc) { - *r_exc = exc; - } else { - GDMonoUtils::set_pending_exception(exc); - } - } - - return ret; -} - -MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoException **r_exc) const { - ERR_FAIL_COND_V(get_parameters_count() > 0, nullptr); - return invoke_raw(p_object, nullptr, r_exc); -} - -MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) const { - MonoException *exc = nullptr; - MonoObject *ret = GDMonoUtils::runtime_invoke(mono_method, p_object, p_params, &exc); - - if (exc) { - ret = nullptr; - if (r_exc) { - *r_exc = exc; - } else { - GDMonoUtils::set_pending_exception(exc); - } - } - - return ret; -} - -bool GDMonoMethod::has_attribute(GDMonoClass *p_attr_class) { - ERR_FAIL_NULL_V(p_attr_class, false); - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return false; - } - - return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr()); -} - -MonoObject *GDMonoMethod::get_attribute(GDMonoClass *p_attr_class) { - ERR_FAIL_NULL_V(p_attr_class, nullptr); - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return nullptr; - } - - return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr()); -} - -void GDMonoMethod::fetch_attributes() { - ERR_FAIL_COND(attributes != nullptr); - attributes = mono_custom_attrs_from_method(mono_method); - attrs_fetched = true; -} - -String GDMonoMethod::get_full_name(bool p_signature) const { - char *res = mono_method_full_name(mono_method, p_signature); - String full_name(res); - mono_free(res); - return full_name; -} - -String GDMonoMethod::get_full_name_no_class() const { - String res; - - MonoMethodSignature *method_sig = mono_method_signature(mono_method); - - char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig)); - res += ret_str; - mono_free(ret_str); - - res += " "; - res += name; - res += "("; - - char *sig_desc = mono_signature_get_desc(method_sig, true); - res += sig_desc; - mono_free(sig_desc); - - res += ")"; - - return res; -} - -String GDMonoMethod::get_ret_type_full_name() const { - MonoMethodSignature *method_sig = mono_method_signature(mono_method); - char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig)); - String res = ret_str; - mono_free(ret_str); - return res; -} - -String GDMonoMethod::get_signature_desc(bool p_namespaces) const { - MonoMethodSignature *method_sig = mono_method_signature(mono_method); - char *sig_desc = mono_signature_get_desc(method_sig, p_namespaces); - String res = sig_desc; - mono_free(sig_desc); - return res; -} - -void GDMonoMethod::get_parameter_names(Vector<StringName> &names) const { - if (params_count > 0) { - const char **_names = memnew_arr(const char *, params_count); - mono_method_get_param_names(mono_method, _names); - for (int i = 0; i < params_count; ++i) { - names.push_back(StringName(_names[i])); - } - memdelete_arr(_names); - } -} - -void GDMonoMethod::get_parameter_types(Vector<ManagedType> &types) const { - for (int i = 0; i < params_count; ++i) { - types.push_back(param_types[i]); - } -} - -const MethodInfo &GDMonoMethod::get_method_info() { - if (!method_info_fetched) { - method_info.name = name; - - bool nil_is_variant = false; - method_info.return_val = PropertyInfo(GDMonoMarshal::managed_to_variant_type(return_type, &nil_is_variant), ""); - if (method_info.return_val.type == Variant::NIL && nil_is_variant) { - method_info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - } - - Vector<StringName> names; - get_parameter_names(names); - - for (int i = 0; i < params_count; ++i) { - nil_is_variant = false; - PropertyInfo arg_info = PropertyInfo(GDMonoMarshal::managed_to_variant_type(param_types[i], &nil_is_variant), names[i]); - if (arg_info.type == Variant::NIL && nil_is_variant) { - arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - } - - method_info.arguments.push_back(arg_info); - } - - // TODO: default arguments - - method_info_fetched = true; - } - - return method_info; -} - -GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) : - name(p_name), mono_method(p_method) { - _update_signature(); -} - -GDMonoMethod::~GDMonoMethod() { - if (attributes) { - mono_custom_attrs_free(attributes); - } -} diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h deleted file mode 100644 index be11ef5bfe..0000000000 --- a/modules/mono/mono_gd/gd_mono_method.h +++ /dev/null @@ -1,97 +0,0 @@ -/*************************************************************************/ -/* gd_mono_method.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_METHOD_H -#define GD_MONO_METHOD_H - -#include "gd_mono.h" -#include "gd_mono_header.h" -#include "i_mono_class_member.h" - -class GDMonoMethod : public IMonoClassMember { - StringName name; - - uint16_t params_count; - unsigned int params_buffer_size = 0; - ManagedType return_type; - Vector<ManagedType> param_types; - - bool method_info_fetched = false; - MethodInfo method_info; - - bool attrs_fetched = false; - MonoCustomAttrInfo *attributes = nullptr; - - void _update_signature(); - void _update_signature(MonoMethodSignature *p_method_sig); - - friend class GDMonoClass; - - MonoMethod *mono_method = nullptr; - -public: - virtual GDMonoClass *get_enclosing_class() const final; - - virtual MemberType get_member_type() const final { return MEMBER_TYPE_METHOD; } - - virtual StringName get_name() const final { return name; } - - virtual bool is_static() final; - - virtual Visibility get_visibility() final; - - virtual bool has_attribute(GDMonoClass *p_attr_class) final; - virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final; - void fetch_attributes(); - - _FORCE_INLINE_ MonoMethod *get_mono_ptr() const { return mono_method; } - - _FORCE_INLINE_ uint16_t get_parameters_count() const { return params_count; } - _FORCE_INLINE_ ManagedType get_return_type() const { return return_type; } - - MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = nullptr) const; - MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = nullptr) const; - MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = nullptr) const; - - String get_full_name(bool p_signature = false) const; - String get_full_name_no_class() const; - String get_ret_type_full_name() const; - String get_signature_desc(bool p_namespaces = false) const; - - void get_parameter_names(Vector<StringName> &names) const; - void get_parameter_types(Vector<ManagedType> &types) const; - - const MethodInfo &get_method_info(); - - GDMonoMethod(StringName p_name, MonoMethod *p_method); - ~GDMonoMethod(); -}; - -#endif // GD_MONO_METHOD_H diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h deleted file mode 100644 index 0180dee3ea..0000000000 --- a/modules/mono/mono_gd/gd_mono_method_thunk.h +++ /dev/null @@ -1,320 +0,0 @@ -/*************************************************************************/ -/* gd_mono_method_thunk.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_METHOD_THUNK_H -#define GD_MONO_METHOD_THUNK_H - -#include <type_traits> - -#include "gd_mono_class.h" -#include "gd_mono_header.h" -#include "gd_mono_marshal.h" -#include "gd_mono_method.h" -#include "gd_mono_utils.h" - -#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED) -#define HAVE_METHOD_THUNKS -#endif - -#ifdef HAVE_METHOD_THUNKS - -template <class... ParamTypes> -struct GDMonoMethodThunk { - typedef void(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **); - - M mono_method_thunk = nullptr; - -public: - _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - mono_method_thunk(p_args..., r_exc); - GD_MONO_END_RUNTIME_INVOKE; - } - - _FORCE_INLINE_ bool is_null() { - return mono_method_thunk == nullptr; - } - - _FORCE_INLINE_ void nullify() { - mono_method_thunk = nullptr; - } - - _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { -#ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == nullptr); - CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID); - - if (p_mono_method->is_static()) { - CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); - } else { - CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); - } -#endif - mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); - } - - GDMonoMethodThunk() {} - - explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) { - set_from_method(p_mono_method); - } -}; - -template <class R, class... ParamTypes> -struct GDMonoMethodThunkR { - typedef R(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **); - - M mono_method_thunk = nullptr; - -public: - _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - R r = mono_method_thunk(p_args..., r_exc); - GD_MONO_END_RUNTIME_INVOKE; - return r; - } - - _FORCE_INLINE_ bool is_null() { - return mono_method_thunk == nullptr; - } - - _FORCE_INLINE_ void nullify() { - mono_method_thunk = nullptr; - } - - _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { -#ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == nullptr); - CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID); - - if (p_mono_method->is_static()) { - CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); - } else { - CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); - } -#endif - mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); - } - - GDMonoMethodThunkR() {} - - explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) { -#ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == nullptr); -#endif - mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); - } -}; - -#else - -template <unsigned int ThunkParamCount, class P1, class... ParamTypes> -struct VariadicInvokeMonoMethodImpl { - static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) { - if (p_mono_method->is_static()) { - void *args[ThunkParamCount] = { p_arg1, p_args... }; - p_mono_method->invoke_raw(nullptr, args, r_exc); - } else { - void *args[ThunkParamCount] = { p_args... }; - p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc); - } - } -}; - -template <unsigned int ThunkParamCount, class... ParamTypes> -struct VariadicInvokeMonoMethod { - static void invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) { - VariadicInvokeMonoMethodImpl<ThunkParamCount, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc); - } -}; - -template <> -struct VariadicInvokeMonoMethod<0> { - static void invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) { -#ifdef DEBUG_ENABLED - CRASH_COND(!p_mono_method->is_static()); -#endif - p_mono_method->invoke_raw(nullptr, nullptr, r_exc); - } -}; - -template <class P1> -struct VariadicInvokeMonoMethod<1, P1> { - static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) { - if (p_mono_method->is_static()) { - void *args[1] = { p_arg1 }; - p_mono_method->invoke_raw(nullptr, args, r_exc); - } else { - p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc); - } - } -}; - -template <class R> -R unbox_if_needed(MonoObject *p_val, const ManagedType &, typename std::enable_if<!std::is_pointer<R>::value>::type * = 0) { - return GDMonoMarshal::unbox<R>(p_val); -} - -template <class R> -R unbox_if_needed(MonoObject *p_val, const ManagedType &p_type, typename std::enable_if<std::is_pointer<R>::value>::type * = 0) { - if (mono_class_is_valuetype(p_type.type_class->get_mono_ptr())) { - return GDMonoMarshal::unbox<R>(p_val); - } else { - // If it's not a value type, we assume 'R' is a pointer to 'MonoObject' or a compatible type, like 'MonoException'. - return (R)p_val; - } -} - -template <unsigned int ThunkParamCount, class R, class P1, class... ParamTypes> -struct VariadicInvokeMonoMethodRImpl { - static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) { - if (p_mono_method->is_static()) { - void *args[ThunkParamCount] = { p_arg1, p_args... }; - MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc); - return unbox_if_needed<R>(r, p_mono_method->get_return_type()); - } else { - void *args[ThunkParamCount] = { p_args... }; - MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc); - return unbox_if_needed<R>(r, p_mono_method->get_return_type()); - } - } -}; - -template <unsigned int ThunkParamCount, class R, class... ParamTypes> -struct VariadicInvokeMonoMethodR { - static R invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) { - return VariadicInvokeMonoMethodRImpl<ThunkParamCount, R, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc); - } -}; - -template <class R> -struct VariadicInvokeMonoMethodR<0, R> { - static R invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) { -#ifdef DEBUG_ENABLED - CRASH_COND(!p_mono_method->is_static()); -#endif - MonoObject *r = p_mono_method->invoke_raw(nullptr, nullptr, r_exc); - return unbox_if_needed<R>(r, p_mono_method->get_return_type()); - } -}; - -template <class R, class P1> -struct VariadicInvokeMonoMethodR<1, R, P1> { - static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) { - if (p_mono_method->is_static()) { - void *args[1] = { p_arg1 }; - MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc); - return unbox_if_needed<R>(r, p_mono_method->get_return_type()); - } else { - MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc); - return unbox_if_needed<R>(r, p_mono_method->get_return_type()); - } - } -}; - -template <class... ParamTypes> -struct GDMonoMethodThunk { - GDMonoMethod *mono_method = nullptr; - -public: - _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) { - VariadicInvokeMonoMethod<sizeof...(ParamTypes), ParamTypes...>::invoke(mono_method, p_args..., r_exc); - } - - _FORCE_INLINE_ bool is_null() { - return mono_method == nullptr; - } - - _FORCE_INLINE_ void nullify() { - mono_method = nullptr; - } - - _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { -#ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == nullptr); - CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID); - - if (p_mono_method->is_static()) { - CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); - } else { - CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); - } -#endif - mono_method = p_mono_method; - } - - GDMonoMethodThunk() {} - - explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) { - set_from_method(p_mono_method); - } -}; - -template <class R, class... ParamTypes> -struct GDMonoMethodThunkR { - GDMonoMethod *mono_method = nullptr; - -public: - _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) { - return VariadicInvokeMonoMethodR<sizeof...(ParamTypes), R, ParamTypes...>::invoke(mono_method, p_args..., r_exc); - } - - _FORCE_INLINE_ bool is_null() { - return mono_method == nullptr; - } - - _FORCE_INLINE_ void nullify() { - mono_method = nullptr; - } - - _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { -#ifdef DEBUG_ENABLED - CRASH_COND(p_mono_method == nullptr); - CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID); - - if (p_mono_method->is_static()) { - CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); - } else { - CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); - } -#endif - mono_method = p_mono_method; - } - - GDMonoMethodThunkR() {} - - explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) { - set_from_method(p_mono_method); - } -}; - -#endif - -#endif // GD_MONO_METHOD_THUNK_H diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp deleted file mode 100644 index c9775ae9cb..0000000000 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/*************************************************************************/ -/* gd_mono_property.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_property.h" - -#include "gd_mono_cache.h" -#include "gd_mono_class.h" -#include "gd_mono_marshal.h" -#include "gd_mono_utils.h" - -#include <mono/metadata/attrdefs.h> - -GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner) { - owner = p_owner; - mono_property = p_mono_property; - name = String::utf8(mono_property_get_name(mono_property)); - - MonoMethod *prop_method = mono_property_get_get_method(mono_property); - - if (prop_method) { - MonoMethodSignature *getter_sig = mono_method_signature(prop_method); - - MonoType *ret_type = mono_signature_get_return_type(getter_sig); - - type.type_encoding = mono_type_get_type(ret_type); - MonoClass *ret_type_class = mono_class_from_mono_type(ret_type); - type.type_class = GDMono::get_singleton()->get_class(ret_type_class); - } else { - prop_method = mono_property_get_set_method(mono_property); - - MonoMethodSignature *setter_sig = mono_method_signature(prop_method); - - void *iter = nullptr; - MonoType *param_raw_type = mono_signature_get_params(setter_sig, &iter); - - type.type_encoding = mono_type_get_type(param_raw_type); - MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type); - type.type_class = GDMono::get_singleton()->get_class(param_type_class); - } - - param_buffer_size = GDMonoMarshal::variant_get_managed_unboxed_size(type); - - attrs_fetched = false; - attributes = nullptr; -} - -GDMonoProperty::~GDMonoProperty() { - if (attributes) { - mono_custom_attrs_free(attributes); - } -} - -bool GDMonoProperty::is_static() { - MonoMethod *prop_method = mono_property_get_get_method(mono_property); - if (prop_method == nullptr) { - prop_method = mono_property_get_set_method(mono_property); - } - return mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_STATIC; -} - -IMonoClassMember::Visibility GDMonoProperty::get_visibility() { - MonoMethod *prop_method = mono_property_get_get_method(mono_property); - if (prop_method == nullptr) { - prop_method = mono_property_get_set_method(mono_property); - } - - switch (mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) { - case MONO_METHOD_ATTR_PRIVATE: - return IMonoClassMember::PRIVATE; - case MONO_METHOD_ATTR_FAM_AND_ASSEM: - return IMonoClassMember::PROTECTED_AND_INTERNAL; - case MONO_METHOD_ATTR_ASSEM: - return IMonoClassMember::INTERNAL; - case MONO_METHOD_ATTR_FAMILY: - return IMonoClassMember::PROTECTED; - case MONO_METHOD_ATTR_PUBLIC: - return IMonoClassMember::PUBLIC; - default: - ERR_FAIL_V(IMonoClassMember::PRIVATE); - } -} - -bool GDMonoProperty::has_attribute(GDMonoClass *p_attr_class) { - ERR_FAIL_NULL_V(p_attr_class, false); - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return false; - } - - return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr()); -} - -MonoObject *GDMonoProperty::get_attribute(GDMonoClass *p_attr_class) { - ERR_FAIL_NULL_V(p_attr_class, nullptr); - - if (!attrs_fetched) { - fetch_attributes(); - } - - if (!attributes) { - return nullptr; - } - - return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr()); -} - -void GDMonoProperty::fetch_attributes() { - ERR_FAIL_COND(attributes != nullptr); - attributes = mono_custom_attrs_from_property(owner->get_mono_ptr(), mono_property); - attrs_fetched = true; -} - -bool GDMonoProperty::has_getter() { - return mono_property_get_get_method(mono_property) != nullptr; -} - -bool GDMonoProperty::has_setter() { - return mono_property_get_set_method(mono_property) != nullptr; -} - -void GDMonoProperty::set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc) { - uint8_t *buffer = (uint8_t *)alloca(param_buffer_size); - unsigned int offset = 0; - - void *params[1] = { - GDMonoMarshal::variant_to_managed_unboxed(p_value, type, buffer, offset) - }; - -#ifdef DEBUG_ENABLED - CRASH_COND(offset != param_buffer_size); -#endif - - MonoException *exc = nullptr; - GDMonoUtils::property_set_value(mono_property, p_object, params, &exc); - if (exc) { - if (r_exc) { - *r_exc = exc; - } else { - GDMonoUtils::set_pending_exception(exc); - } - } -} - -MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoException **r_exc) { - MonoException *exc = nullptr; - MonoObject *ret = GDMonoUtils::property_get_value(mono_property, p_object, nullptr, &exc); - - if (exc) { - ret = nullptr; - if (r_exc) { - *r_exc = exc; - } else { - GDMonoUtils::set_pending_exception(exc); - } - } - - return ret; -} - -bool GDMonoProperty::get_bool_value(MonoObject *p_object) { - return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object)); -} - -int GDMonoProperty::get_int_value(MonoObject *p_object) { - return GDMonoMarshal::unbox<int32_t>(get_value(p_object)); -} - -String GDMonoProperty::get_string_value(MonoObject *p_object) { - MonoObject *val = get_value(p_object); - return GDMonoMarshal::mono_string_to_godot((MonoString *)val); -} diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h deleted file mode 100644 index 6fc681aeb5..0000000000 --- a/modules/mono/mono_gd/gd_mono_property.h +++ /dev/null @@ -1,80 +0,0 @@ -/*************************************************************************/ -/* gd_mono_property.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_PROPERTY_H -#define GD_MONO_PROPERTY_H - -#include "gd_mono.h" -#include "gd_mono_header.h" -#include "i_mono_class_member.h" - -class GDMonoProperty : public IMonoClassMember { - GDMonoClass *owner = nullptr; - MonoProperty *mono_property = nullptr; - - StringName name; - ManagedType type; - - bool attrs_fetched; - MonoCustomAttrInfo *attributes = nullptr; - - unsigned int param_buffer_size; - -public: - virtual GDMonoClass *get_enclosing_class() const final { return owner; } - - virtual MemberType get_member_type() const final { return MEMBER_TYPE_PROPERTY; } - - virtual StringName get_name() const final { return name; } - - virtual bool is_static() final; - virtual Visibility get_visibility() final; - - virtual bool has_attribute(GDMonoClass *p_attr_class) final; - virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final; - void fetch_attributes(); - - bool has_getter(); - bool has_setter(); - - _FORCE_INLINE_ ManagedType get_type() const { return type; } - - void set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc = nullptr); - MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = nullptr); - - bool get_bool_value(MonoObject *p_object); - int get_int_value(MonoObject *p_object); - String get_string_value(MonoObject *p_object); - - GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner); - ~GDMonoProperty(); -}; - -#endif // GD_MONO_PROPERTY_H diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp deleted file mode 100644 index 1983d6ebe2..0000000000 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ /dev/null @@ -1,677 +0,0 @@ -/*************************************************************************/ -/* gd_mono_utils.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_utils.h" - -#include <mono/metadata/debug-helpers.h> -#include <mono/metadata/exception.h> - -#include "core/debugger/engine_debugger.h" -#include "core/debugger/script_debugger.h" -#include "core/io/dir_access.h" -#include "core/object/ref_counted.h" -#include "core/os/mutex.h" -#include "core/os/os.h" - -#ifdef TOOLS_ENABLED -#include "editor/debugger/editor_debugger_node.h" -#endif - -#include "../csharp_script.h" -#include "../utils/macros.h" -#include "gd_mono.h" -#include "gd_mono_cache.h" -#include "gd_mono_class.h" -#include "gd_mono_marshal.h" - -namespace GDMonoUtils { - -MonoObject *unmanaged_get_managed(Object *unmanaged) { - if (!unmanaged) { - return nullptr; - } - - if (unmanaged->get_script_instance()) { - CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance()); - - if (cs_instance) { - return cs_instance->get_mono_object(); - } - } - - // If the owner does not have a CSharpInstance... - - void *data = CSharpLanguage::get_instance_binding(unmanaged); - ERR_FAIL_NULL_V(data, nullptr); - CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value(); - ERR_FAIL_COND_V(!script_binding.inited, nullptr); - - MonoGCHandleData &gchandle = script_binding.gchandle; - - MonoObject *target = gchandle.get_target(); - - if (target) { - return target; - } - - CSharpLanguage::get_singleton()->release_script_gchandle(gchandle); - - // Create a new one - -#ifdef DEBUG_ENABLED - CRASH_COND(script_binding.type_name == StringName()); - CRASH_COND(script_binding.wrapper_class == nullptr); -#endif - - MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged); - ERR_FAIL_NULL_V(mono_object, nullptr); - - gchandle = MonoGCHandleData::new_strong_handle(mono_object); - - // Tie managed to unmanaged - RefCounted *rc = Object::cast_to<RefCounted>(unmanaged); - - if (rc) { - // 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_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr) - rc->reference(); - CSharpLanguage::get_singleton()->post_unsafe_reference(rc); - } - - return mono_object; -} - -void set_main_thread(MonoThread *p_thread) { - mono_thread_set_main(p_thread); -} - -MonoThread *attach_current_thread() { - ERR_FAIL_COND_V(!GDMono::get_singleton()->is_runtime_initialized(), nullptr); - MonoDomain *scripts_domain = GDMono::get_singleton()->get_scripts_domain(); -#ifndef GD_MONO_SINGLE_APPDOMAIN - MonoThread *mono_thread = mono_thread_attach(scripts_domain ? scripts_domain : mono_get_root_domain()); -#else - // The scripts domain is the root domain - MonoThread *mono_thread = mono_thread_attach(scripts_domain); -#endif - ERR_FAIL_NULL_V(mono_thread, nullptr); - return mono_thread; -} - -void detach_current_thread() { - ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized()); - MonoThread *mono_thread = mono_thread_current(); - ERR_FAIL_NULL(mono_thread); - mono_thread_detach(mono_thread); -} - -void detach_current_thread(MonoThread *p_mono_thread) { - ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized()); - ERR_FAIL_NULL(p_mono_thread); - mono_thread_detach(p_mono_thread); -} - -MonoThread *get_current_thread() { - return mono_thread_current(); -} - -bool is_thread_attached() { - return mono_domain_get() != nullptr; -} - -uint32_t new_strong_gchandle(MonoObject *p_object) { - return mono_gchandle_new(p_object, /* pinned: */ false); -} - -uint32_t new_strong_gchandle_pinned(MonoObject *p_object) { - return mono_gchandle_new(p_object, /* pinned: */ true); -} - -uint32_t new_weak_gchandle(MonoObject *p_object) { - return mono_gchandle_new_weakref(p_object, /* track_resurrection: */ false); -} - -void free_gchandle(uint32_t p_gchandle) { - mono_gchandle_free(p_gchandle); -} - -void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) { - GDMonoMethod *ctor = p_class->get_method(".ctor", 0); - ERR_FAIL_NULL(ctor); - ctor->invoke_raw(p_this_obj, nullptr, r_exc); -} - -bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b) { - MonoException *exc = nullptr; - MonoBoolean res = CACHED_METHOD_THUNK(Delegate, Equals).invoke((MonoObject *)p_a, (MonoObject *)p_b, &exc); - UNHANDLED_EXCEPTION(exc); - return (bool)res; -} - -GDMonoClass *get_object_class(MonoObject *p_object) { - return GDMono::get_singleton()->get_class(mono_object_get_class(p_object)); -} - -GDMonoClass *type_get_proxy_class(const StringName &p_type) { - String class_name = p_type; - - if (class_name[0] == '_') { - class_name = class_name.substr(1, class_name.length()); - } - - GDMonoClass *klass = GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name); - - if (klass && klass->is_static()) { - // A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object. - return GDMonoCache::cached_data.class_GodotObject; - } - -#ifdef TOOLS_ENABLED - if (!klass) { - return GDMono::get_singleton()->get_editor_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name); - } -#endif - - return klass; -} - -GDMonoClass *get_class_native_base(GDMonoClass *p_class) { - GDMonoClass *klass = p_class; - - do { - const GDMonoAssembly *assembly = klass->get_assembly(); - - if (assembly == GDMono::get_singleton()->get_core_api_assembly()) { - return klass; - } -#ifdef TOOLS_ENABLED - if (assembly == GDMono::get_singleton()->get_editor_api_assembly()) { - return klass; - } -#endif - } while ((klass = klass->get_parent_class()) != nullptr); - - return nullptr; -} - -MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) { - bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), p_native); - ERR_FAIL_COND_V_MSG(!parent_is_object_class, nullptr, - "Type inherits from native type '" + p_native + "', so it can't be instantiated in object of type: '" + p_object->get_class() + "'."); - - MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); - ERR_FAIL_NULL_V(mono_object, nullptr); - - CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object); - - // Construct - GDMonoUtils::runtime_object_init(mono_object, p_class); - - return mono_object; -} - -MonoObject *create_managed_from(const StringName &p_from) { - MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(StringName)); - ERR_FAIL_NULL_V(mono_object, nullptr); - - // Construct - GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(StringName)); - - CACHED_FIELD(StringName, ptr)->set_value_raw(mono_object, memnew(StringName(p_from))); - - return mono_object; -} - -MonoObject *create_managed_from(const NodePath &p_from) { - MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(NodePath)); - ERR_FAIL_NULL_V(mono_object, nullptr); - - // Construct - GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(NodePath)); - - CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from))); - - return mono_object; -} - -MonoObject *create_managed_from(const RID &p_from) { - MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(RID)); - ERR_FAIL_NULL_V(mono_object, nullptr); - - // Construct - GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(RID)); - - CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from))); - - return mono_object; -} - -MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) { - MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); - ERR_FAIL_NULL_V(mono_object, nullptr); - - // Search constructor that takes a pointer as parameter - MonoMethod *m; - void *iter = nullptr; - while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) { - if (strcmp(mono_method_get_name(m), ".ctor") == 0) { - MonoMethodSignature *sig = mono_method_signature(m); - void *front = nullptr; - if (mono_signature_get_param_count(sig) == 1 && - mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) { - break; - } - } - } - - CRASH_COND(m == nullptr); - - Array *new_array = memnew(Array(p_from)); - void *args[1] = { &new_array }; - - MonoException *exc = nullptr; - GDMonoUtils::runtime_invoke(m, mono_object, args, &exc); - UNHANDLED_EXCEPTION(exc); - - return mono_object; -} - -MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) { - MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); - ERR_FAIL_NULL_V(mono_object, nullptr); - - // Search constructor that takes a pointer as parameter - MonoMethod *m; - void *iter = nullptr; - while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) { - if (strcmp(mono_method_get_name(m), ".ctor") == 0) { - MonoMethodSignature *sig = mono_method_signature(m); - void *front = nullptr; - if (mono_signature_get_param_count(sig) == 1 && - mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) { - break; - } - } - } - - CRASH_COND(m == nullptr); - - Dictionary *new_dict = memnew(Dictionary(p_from)); - void *args[1] = { &new_dict }; - - MonoException *exc = nullptr; - GDMonoUtils::runtime_invoke(m, mono_object, args, &exc); - UNHANDLED_EXCEPTION(exc); - - return mono_object; -} - -MonoDomain *create_domain(const String &p_friendly_name) { - print_verbose("Mono: Creating domain '" + p_friendly_name + "'..."); - - MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), nullptr); - - if (domain) { - // Workaround to avoid this exception: - // System.Configuration.ConfigurationErrorsException: Error Initializing the configuration system. - // ---> System.ArgumentException: The 'ExeConfigFilename' argument cannot be null. - mono_domain_set_config(domain, ".", ""); - } - - return domain; -} - -String get_type_desc(MonoType *p_type) { - return mono_type_full_name(p_type); -} - -String get_type_desc(MonoReflectionType *p_reftype) { - return get_type_desc(mono_reflection_type_get_type(p_reftype)); -} - -String get_exception_name_and_message(MonoException *p_exc) { - String res; - - MonoClass *klass = mono_object_get_class((MonoObject *)p_exc); - MonoType *type = mono_class_get_type(klass); - - char *full_name = mono_type_full_name(type); - res += full_name; - mono_free(full_name); - - res += ": "; - - MonoProperty *prop = mono_class_get_property_from_name(klass, "Message"); - MonoString *msg = (MonoString *)property_get_value(prop, (MonoObject *)p_exc, nullptr, nullptr); - res += GDMonoMarshal::mono_string_to_godot(msg); - - return res; -} - -void debug_print_unhandled_exception(MonoException *p_exc) { - print_unhandled_exception(p_exc); - debug_send_unhandled_exception_error(p_exc); -} - -void debug_send_unhandled_exception_error(MonoException *p_exc) { -#ifdef DEBUG_ENABLED - if (!EngineDebugger::is_active()) { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - ERR_PRINT(GDMonoUtils::get_exception_name_and_message(p_exc)); - } -#endif - return; - } - - static thread_local bool _recursion_flag_ = false; - if (_recursion_flag_) { - return; - } - _recursion_flag_ = true; - SCOPE_EXIT { _recursion_flag_ = false; }; - - ScriptLanguage::StackInfo separator; - separator.file = String(); - separator.func = "--- " + RTR("End of inner exception stack trace") + " ---"; - separator.line = 0; - - Vector<ScriptLanguage::StackInfo> si; - String exc_msg; - - while (p_exc != nullptr) { - GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace); - MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr()); - - MonoBoolean need_file_info = true; - void *ctor_args[2] = { p_exc, &need_file_info }; - - MonoException *unexpected_exc = nullptr; - CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc); - - if (unexpected_exc) { - GDMonoInternals::unhandled_exception(unexpected_exc); - return; - } - - Vector<ScriptLanguage::StackInfo> _si; - if (stack_trace != nullptr) { - _si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace); - for (int i = _si.size() - 1; i >= 0; i--) { - si.insert(0, _si[i]); - } - } - - exc_msg += (exc_msg.length() > 0 ? " ---> " : "") + GDMonoUtils::get_exception_name_and_message(p_exc); - - GDMonoClass *exc_class = GDMono::get_singleton()->get_class(mono_get_exception_class()); - GDMonoProperty *inner_exc_prop = exc_class->get_property("InnerException"); - CRASH_COND(inner_exc_prop == nullptr); - - MonoObject *inner_exc = inner_exc_prop->get_value((MonoObject *)p_exc); - if (inner_exc != nullptr) { - si.insert(0, separator); - } - - p_exc = (MonoException *)inner_exc; - } - - String file = si.size() ? si[0].file : __FILE__; - String func = si.size() ? si[0].func : FUNCTION_STR; - int line = si.size() ? si[0].line : __LINE__; - String error_msg = "Unhandled exception"; - - EngineDebugger::get_script_debugger()->send_error(func, file, line, error_msg, exc_msg, true, ERR_HANDLER_ERROR, si); -#endif -} - -void debug_unhandled_exception(MonoException *p_exc) { - GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well -} - -void print_unhandled_exception(MonoException *p_exc) { - mono_print_unhandled_exception((MonoObject *)p_exc); -} - -void set_pending_exception(MonoException *p_exc) { -#ifdef NO_PENDING_EXCEPTIONS - debug_unhandled_exception(p_exc); -#else - if (get_runtime_invoke_count() == 0) { - debug_unhandled_exception(p_exc); - return; - } - - if (!mono_runtime_set_pending_exception(p_exc, false)) { - ERR_PRINT("Exception thrown from managed code, but it could not be set as pending:"); - GDMonoUtils::debug_print_unhandled_exception(p_exc); - } -#endif -} - -thread_local int current_invoke_count = 0; - -MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - MonoObject *ret = mono_runtime_invoke(p_method, p_obj, p_params, (MonoObject **)r_exc); - GD_MONO_END_RUNTIME_INVOKE; - return ret; -} - -MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc); - GD_MONO_END_RUNTIME_INVOKE; - return ret; -} - -void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - mono_property_set_value(p_prop, p_obj, p_params, (MonoObject **)r_exc); - GD_MONO_END_RUNTIME_INVOKE; -} - -MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - MonoObject *ret = mono_property_get_value(p_prop, p_obj, p_params, (MonoObject **)r_exc); - GD_MONO_END_RUNTIME_INVOKE; - return ret; -} - -uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error) { - r_error = false; - switch (mono_type_get_type(p_enum_basetype)) { - case MONO_TYPE_BOOLEAN: - return (bool)GDMonoMarshal::unbox<MonoBoolean>(p_boxed) ? 1 : 0; - case MONO_TYPE_CHAR: - return GDMonoMarshal::unbox<uint16_t>(p_boxed); - case MONO_TYPE_U1: - return GDMonoMarshal::unbox<uint8_t>(p_boxed); - case MONO_TYPE_U2: - return GDMonoMarshal::unbox<uint16_t>(p_boxed); - case MONO_TYPE_U4: - return GDMonoMarshal::unbox<uint32_t>(p_boxed); - case MONO_TYPE_U8: - return GDMonoMarshal::unbox<uint64_t>(p_boxed); - case MONO_TYPE_I1: - return GDMonoMarshal::unbox<int8_t>(p_boxed); - case MONO_TYPE_I2: - return GDMonoMarshal::unbox<int16_t>(p_boxed); - case MONO_TYPE_I4: - return GDMonoMarshal::unbox<int32_t>(p_boxed); - case MONO_TYPE_I8: - return GDMonoMarshal::unbox<int64_t>(p_boxed); - default: - r_error = true; - return 0; - } -} - -void dispose(MonoObject *p_mono_object, MonoException **r_exc) { - CACHED_METHOD_THUNK(GodotObject, Dispose).invoke(p_mono_object, r_exc); -} - -namespace Marshal { - -#ifdef MONO_GLUE_ENABLED -#ifdef TOOLS_ENABLED -#define NO_GLUE_RET(m_ret) \ - { \ - if (!GDMonoCache::cached_data.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); - MonoException *exc = nullptr; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray).invoke(p_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return (bool)res; -} - -bool type_is_generic_dictionary(MonoReflectionType *p_reftype) { - NO_GLUE_RET(false); - MonoException *exc = nullptr; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary).invoke(p_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return (bool)res; -} - -bool type_is_system_generic_list(MonoReflectionType *p_reftype) { - NO_GLUE_RET(false); - MonoException *exc = nullptr; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericList).invoke(p_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return (bool)res; -} - -bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype) { - NO_GLUE_RET(false); - MonoException *exc = nullptr; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericDictionary).invoke(p_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return (bool)res; -} - -bool type_is_generic_ienumerable(MonoReflectionType *p_reftype) { - NO_GLUE_RET(false); - MonoException *exc = nullptr; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIEnumerable).invoke(p_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return (bool)res; -} - -bool type_is_generic_icollection(MonoReflectionType *p_reftype) { - NO_GLUE_RET(false); - MonoException *exc = nullptr; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericICollection).invoke(p_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return (bool)res; -} - -bool type_is_generic_idictionary(MonoReflectionType *p_reftype) { - NO_GLUE_RET(false); - MonoException *exc = nullptr; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIDictionary).invoke(p_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return (bool)res; -} - -bool type_has_flags_attribute(MonoReflectionType *p_reftype) { - NO_GLUE_RET(false); - MonoException *exc = nullptr; - MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeHasFlagsAttribute).invoke(p_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return (bool)res; -} - -void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) { - MonoException *exc = nullptr; - CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc); - UNHANDLED_EXCEPTION(exc); -} - -void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) { - MonoException *exc = nullptr; - CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc); - UNHANDLED_EXCEPTION(exc); -} - -void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { - MonoException *exc = nullptr; - CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes).invoke(p_dict_reftype, r_key_reftype, r_value_reftype, &exc); - UNHANDLED_EXCEPTION(exc); -} - -GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) { - NO_GLUE_RET(nullptr); - MonoException *exc = nullptr; - MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType).invoke(p_elem_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); -} - -GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) { - NO_GLUE_RET(nullptr); - MonoException *exc = nullptr; - MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType).invoke(p_key_reftype, p_value_reftype, &exc); - UNHANDLED_EXCEPTION(exc); - return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); -} -} // namespace Marshal - -ScopeThreadAttach::ScopeThreadAttach() { - if (likely(GDMono::get_singleton()->is_runtime_initialized()) && unlikely(!mono_domain_get())) { - mono_thread = GDMonoUtils::attach_current_thread(); - } -} - -ScopeThreadAttach::~ScopeThreadAttach() { - if (unlikely(mono_thread)) { - GDMonoUtils::detach_current_thread(mono_thread); - } -} - -StringName get_native_godot_class_name(GDMonoClass *p_class) { - MonoObject *native_name_obj = p_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(nullptr); - StringName *ptr = GDMonoMarshal::unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(native_name_obj)); - return ptr ? *ptr : StringName(); -} -} // namespace GDMonoUtils diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h deleted file mode 100644 index 300cacfa4b..0000000000 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ /dev/null @@ -1,205 +0,0 @@ -/*************************************************************************/ -/* gd_mono_utils.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_UTILS_H -#define GD_MONO_UTILS_H - -#include <mono/metadata/threads.h> - -#include "../mono_gc_handle.h" -#include "../utils/macros.h" -#include "gd_mono_header.h" -#ifdef JAVASCRIPT_ENABLED -#include "gd_mono_wasm_m2n.h" -#endif - -#include "core/object/class_db.h" -#include "core/object/ref_counted.h" - -#define UNHANDLED_EXCEPTION(m_exc) \ - if (unlikely(m_exc != nullptr)) { \ - GDMonoUtils::debug_unhandled_exception(m_exc); \ - GD_UNREACHABLE(); \ - } else \ - ((void)0) - -namespace GDMonoUtils { - -namespace Marshal { - -bool type_is_generic_array(MonoReflectionType *p_reftype); -bool type_is_generic_dictionary(MonoReflectionType *p_reftype); -bool type_is_system_generic_list(MonoReflectionType *p_reftype); -bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype); -bool type_is_generic_ienumerable(MonoReflectionType *p_reftype); -bool type_is_generic_icollection(MonoReflectionType *p_reftype); -bool type_is_generic_idictionary(MonoReflectionType *p_reftype); -bool type_has_flags_attribute(MonoReflectionType *p_reftype); - -void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_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); - -GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype); -GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype); -} // namespace Marshal - -_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); -} - -/** - * If the object has a csharp script, returns the target of the gchandle stored in the script instance - * Otherwise returns a newly constructed MonoObject* which is attached to the object - * Returns nullptr on error - */ -MonoObject *unmanaged_get_managed(Object *unmanaged); - -void set_main_thread(MonoThread *p_thread); -MonoThread *attach_current_thread(); -void detach_current_thread(); -void detach_current_thread(MonoThread *p_mono_thread); -MonoThread *get_current_thread(); -bool is_thread_attached(); - -uint32_t new_strong_gchandle(MonoObject *p_object); -uint32_t new_strong_gchandle_pinned(MonoObject *p_object); -uint32_t new_weak_gchandle(MonoObject *p_object); -void free_gchandle(uint32_t p_gchandle); - -void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = nullptr); - -bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b); - -GDMonoClass *get_object_class(MonoObject *p_object); -GDMonoClass *type_get_proxy_class(const StringName &p_type); -GDMonoClass *get_class_native_base(GDMonoClass *p_class); - -MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object); - -MonoObject *create_managed_from(const StringName &p_from); -MonoObject *create_managed_from(const NodePath &p_from); -MonoObject *create_managed_from(const RID &p_from); -MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class); -MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class); - -MonoDomain *create_domain(const String &p_friendly_name); - -String get_type_desc(MonoType *p_type); -String get_type_desc(MonoReflectionType *p_reftype); - -String get_exception_name_and_message(MonoException *p_exc); - -void debug_print_unhandled_exception(MonoException *p_exc); -void debug_send_unhandled_exception_error(MonoException *p_exc); -void debug_unhandled_exception(MonoException *p_exc); -void print_unhandled_exception(MonoException *p_exc); - -/** - * Sets the exception as pending. The exception will be thrown when returning to managed code. - * If no managed method is being invoked by the runtime, the exception will be treated as - * an unhandled exception and the method will not return. - */ -void set_pending_exception(MonoException *p_exc); - -extern thread_local int current_invoke_count; - -_FORCE_INLINE_ int get_runtime_invoke_count() { - return current_invoke_count; -} - -_FORCE_INLINE_ int &get_runtime_invoke_count_ref() { - return current_invoke_count; -} - -MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc); - -MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc); - -void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc); -MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc); - -uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error); - -void dispose(MonoObject *p_mono_object, MonoException **r_exc); - -struct ScopeThreadAttach { - ScopeThreadAttach(); - ~ScopeThreadAttach(); - -private: - MonoThread *mono_thread = nullptr; -}; - -StringName get_native_godot_class_name(GDMonoClass *p_class); - -template <typename... P> -void add_internal_call(const char *p_name, void (*p_func)(P...)) { -#ifdef JAVASCRIPT_ENABLED - GDMonoWasmM2n::ICallTrampolines<P...>::add(); -#endif - mono_add_internal_call(p_name, (void *)p_func); -} - -template <typename R, typename... P> -void add_internal_call(const char *p_name, R (*p_func)(P...)) { -#ifdef JAVASCRIPT_ENABLED - GDMonoWasmM2n::ICallTrampolinesR<R, P...>::add(); -#endif - mono_add_internal_call(p_name, (void *)p_func); -} -} // namespace GDMonoUtils - -#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoUtils::get_native_godot_class_name(m_class)) - -#define GD_MONO_BEGIN_RUNTIME_INVOKE \ - int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \ - _runtime_invoke_count_ref += 1; \ - ((void)0) - -#define GD_MONO_END_RUNTIME_INVOKE \ - _runtime_invoke_count_ref -= 1; \ - ((void)0) - -#define GD_MONO_SCOPE_THREAD_ATTACH \ - GDMonoUtils::ScopeThreadAttach __gdmono__scope__thread__attach__; \ - (void)__gdmono__scope__thread__attach__; \ - ((void)0) - -#ifdef DEBUG_ENABLED -#define GD_MONO_ASSERT_THREAD_ATTACHED \ - CRASH_COND(!GDMonoUtils::is_thread_attached()); \ - ((void)0) -#else -#define GD_MONO_ASSERT_THREAD_ATTACHED ((void)0) -#endif - -#endif // GD_MONO_UTILS_H diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp deleted file mode 100644 index dbfca2dc0c..0000000000 --- a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************/ -/* gd_mono_wasm_m2n.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gd_mono_wasm_m2n.h" - -#ifdef JAVASCRIPT_ENABLED - -#include "core/templates/oa_hash_map.h" - -typedef mono_bool (*GodotMonoM2nIcallTrampolineDispatch)(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs); - -// This extern function is implemented in our patched version of Mono -MONO_API void godot_mono_register_m2n_icall_trampoline_dispatch_hook(GodotMonoM2nIcallTrampolineDispatch hook); - -namespace GDMonoWasmM2n { - -struct HashMapCookieComparator { - static bool compare(const char *p_lhs, const char *p_rhs) { - return strcmp(p_lhs, p_rhs) == 0; - } -}; - -// The default hasher supports 'const char *' C Strings, but we need a custom comparator -OAHashMap<const char *, TrampolineFunc, HashMapHasherDefault, HashMapCookieComparator> trampolines; - -void set_trampoline(const char *cookies, GDMonoWasmM2n::TrampolineFunc trampoline_func) { - trampolines.set(cookies, trampoline_func); -} - -mono_bool trampoline_dispatch_hook(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs) { - TrampolineFunc *trampoline_func = trampolines.lookup_ptr(cookie); - - if (!trampoline_func) { - return false; - } - - (*trampoline_func)(target_func, margs); - return true; -} - -bool initialized = false; - -void lazy_initialize() { - // Doesn't need to be thread safe - if (!initialized) { - initialized = true; - godot_mono_register_m2n_icall_trampoline_dispatch_hook(&trampoline_dispatch_hook); - } -} -} // namespace GDMonoWasmM2n - -#endif diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h deleted file mode 100644 index 83e2750e5a..0000000000 --- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h +++ /dev/null @@ -1,263 +0,0 @@ -/*************************************************************************/ -/* gd_mono_wasm_m2n.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_WASM_M2N_H -#define GD_MONO_WASM_M2N_H - -#ifdef JAVASCRIPT_ENABLED - -#include "core/string/ustring.h" -#include "core/typedefs.h" - -#include <mono/metadata/loader.h> -#include <mono/utils/mono-publib.h> -#include <stdexcept> -#include <type_traits> - -extern "C" { - -struct Mono_InterpMethodArguments { - size_t ilen; - void **iargs; - size_t flen; - double *fargs = nullptr; - void **retval; - size_t is_float_ret; - //#ifdef TARGET_WASM - void *sig = nullptr; - //#endif -}; -} // extern "C" - -namespace GDMonoWasmM2n { - -template <typename T, size_t Size> -struct array { - T elems[Size]; -}; - -template <typename T> -constexpr char get_m2n_cookie_impl() { -#define M2N_REG_COOKIE(m_type, m_cookie) \ - if constexpr (std::is_same_v<m_type, T>) { \ - return m_cookie; \ - } - - M2N_REG_COOKIE(MonoBoolean, 'I'); - M2N_REG_COOKIE(int8_t, 'I'); - M2N_REG_COOKIE(uint8_t, 'I'); - M2N_REG_COOKIE(int16_t, 'I'); - M2N_REG_COOKIE(uint16_t, 'I'); - M2N_REG_COOKIE(int32_t, 'I'); - M2N_REG_COOKIE(uint32_t, 'I'); - M2N_REG_COOKIE(int64_t, 'L'); - M2N_REG_COOKIE(uint64_t, 'L'); - M2N_REG_COOKIE(float, 'F'); - M2N_REG_COOKIE(double, 'D'); - - if constexpr (std::is_pointer_v<T>) { - if constexpr (sizeof(void *) == 4) { - return 'I'; - } else { - return 'L'; - } - } - - if constexpr (std::is_void_v<T>) { - return 'V'; - } - - return 'X'; - -#undef M2N_REG_COOKIE -} - -template <typename T> -constexpr char get_m2n_cookie() { - constexpr char cookie = get_m2n_cookie_impl<T>(); - static_assert(cookie != 'X', "Type not supported in internal call signature."); - return cookie; -} - -template <typename... T> -constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies() { - return array<const char, sizeof...(T) + 2>{ 'V', get_m2n_cookie<T>()..., '\0' }; -} - -template <typename R, typename... T> -constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies_r() { - return array<const char, sizeof...(T) + 2>{ get_m2n_cookie<R>(), get_m2n_cookie<T>()..., '\0' }; -} - -template <typename T> -constexpr size_t calc_m2n_index(size_t &r_int_idx, size_t &r_float_idx) { - constexpr char cookie = get_m2n_cookie<T>(); - - static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D'); - - if constexpr (cookie == 'I' || cookie == 'L') { - size_t ret = r_int_idx; - r_int_idx += cookie == 'I' ? 1 : 2; - return ret; - } else { - size_t ret = r_float_idx; - r_float_idx += cookie == 'F' ? 1 : 2; - return ret; - } -} - -template <typename... P> -constexpr array<size_t, sizeof...(P)> get_indices_for_type() { - size_t int_idx = 0; - size_t float_idx = 0; - return array<size_t, sizeof...(P)>{ calc_m2n_index<P>(int_idx, float_idx)... }; -} - -constexpr size_t fidx(size_t p_x) { - if constexpr (sizeof(void *) == 4) { - return p_x * 2; - } else { - return p_x; - } -} - -template <typename T> -T m2n_arg_cast(Mono_InterpMethodArguments *p_margs, size_t p_idx) { - constexpr char cookie = get_m2n_cookie<T>(); - - static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D'); - - if constexpr (cookie == 'I') { - return (T)(size_t)p_margs->iargs[p_idx]; - } else if constexpr (cookie == 'L') { - static_assert(std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t> || - (sizeof(void *) == 8 && std::is_pointer_v<T>), - "Invalid type for cookie 'L'."); - - union { - T l; - struct { - int32_t lo; - int32_t hi; - } pair; - } p; - - p.pair.lo = (int32_t)(size_t)p_margs->iargs[p_idx]; - p.pair.hi = (int32_t)(size_t)p_margs->iargs[p_idx + 1]; - - return p.l; - } else if constexpr (cookie == 'F') { - return *reinterpret_cast<float *>(&p_margs->fargs[fidx(p_idx)]); - } else if constexpr (cookie == 'D') { - return (T)p_margs->fargs[p_idx]; - } -} - -template <typename... P, size_t... Is> -void m2n_trampoline_with_idx_seq(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) { - constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>(); - typedef void (*Func)(P...); - Func func = (Func)p_target_func; - func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...); -} - -template <typename R, typename... P, size_t... Is> -void m2n_trampoline_with_idx_seq_r(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) { - constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>(); - typedef R (*Func)(P...); - Func func = (Func)p_target_func; - R res = func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...); - *reinterpret_cast<R *>(p_margs->retval) = res; -} - -inline void m2n_trampoline_with_idx_seq_0(void *p_target_func, Mono_InterpMethodArguments *p_margs) { - typedef void (*Func)(); - Func func = (Func)p_target_func; - func(); -} - -template <typename R> -void m2n_trampoline_with_idx_seq_r0(void *p_target_func, Mono_InterpMethodArguments *p_margs) { - typedef R (*Func)(); - Func func = (Func)p_target_func; - R res = func(); - *reinterpret_cast<R *>(p_margs->retval) = res; -} - -template <typename... P> -void m2n_trampoline(void *p_target_func, Mono_InterpMethodArguments *p_margs) { - if constexpr (sizeof...(P) == 0) { - m2n_trampoline_with_idx_seq_0(p_target_func, p_margs); - } else { - m2n_trampoline_with_idx_seq<P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{}); - } -} - -template <typename R, typename... P> -void m2n_trampoline_r(void *p_target_func, Mono_InterpMethodArguments *p_margs) { - if constexpr (sizeof...(P) == 0) { - m2n_trampoline_with_idx_seq_r0<R>(p_target_func, p_margs); - } else { - m2n_trampoline_with_idx_seq_r<R, P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{}); - } -} - -typedef void (*TrampolineFunc)(void *p_target_func, Mono_InterpMethodArguments *p_margs); - -void set_trampoline(const char *cookies, TrampolineFunc trampoline_func); - -void lazy_initialize(); - -template <typename... P> -struct ICallTrampolines { - static constexpr auto cookies = get_m2n_cookies<P...>(); - - static void add() { - lazy_initialize(); - set_trampoline(cookies.elems, &m2n_trampoline<P...>); - } -}; - -template <typename R, typename... P> -struct ICallTrampolinesR { - static constexpr auto cookies = get_m2n_cookies_r<R, P...>(); - - static void add() { - lazy_initialize(); - set_trampoline(cookies.elems, &m2n_trampoline_r<R, P...>); - } -}; - -void initialize(); -} // namespace GDMonoWasmM2n - -#endif - -#endif // GD_MONO_WASM_M2N_H diff --git a/modules/mono/mono_gd/i_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h deleted file mode 100644 index 14e8ca82b9..0000000000 --- a/modules/mono/mono_gd/i_mono_class_member.h +++ /dev/null @@ -1,70 +0,0 @@ -/*************************************************************************/ -/* i_mono_class_member.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef I_MONO_CLASS_MEMBER_H -#define I_MONO_CLASS_MEMBER_H - -#include "gd_mono_header.h" - -#include <mono/metadata/object.h> - -class IMonoClassMember { -public: - enum Visibility { - PRIVATE, - PROTECTED_AND_INTERNAL, // FAM_AND_ASSEM - INTERNAL, // ASSEMBLY - PROTECTED, // FAMILY - PUBLIC - }; - - enum MemberType { - MEMBER_TYPE_FIELD, - MEMBER_TYPE_PROPERTY, - MEMBER_TYPE_METHOD - }; - - virtual ~IMonoClassMember() {} - - virtual GDMonoClass *get_enclosing_class() const = 0; - - virtual MemberType get_member_type() const = 0; - - virtual StringName get_name() const = 0; - - virtual bool is_static() = 0; - - virtual Visibility get_visibility() = 0; - - virtual bool has_attribute(GDMonoClass *p_attr_class) = 0; - virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) = 0; -}; - -#endif // I_MONO_CLASS_MEMBER_H diff --git a/modules/mono/mono_gd/managed_type.cpp b/modules/mono/mono_gd/managed_type.cpp deleted file mode 100644 index 5860d7db1e..0000000000 --- a/modules/mono/mono_gd/managed_type.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************/ -/* managed_type.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "managed_type.h" - -#include "gd_mono.h" -#include "gd_mono_class.h" - -ManagedType ManagedType::from_class(GDMonoClass *p_class) { - return ManagedType(mono_type_get_type(p_class->get_mono_type()), p_class); -} - -ManagedType ManagedType::from_class(MonoClass *p_mono_class) { - GDMonoClass *tclass = GDMono::get_singleton()->get_class(p_mono_class); - ERR_FAIL_COND_V(!tclass, ManagedType()); - - return ManagedType(mono_type_get_type(tclass->get_mono_type()), tclass); -} - -ManagedType ManagedType::from_type(MonoType *p_mono_type) { - MonoClass *mono_class = mono_class_from_mono_type(p_mono_type); - GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_class); - ERR_FAIL_COND_V(!tclass, ManagedType()); - - return ManagedType(mono_type_get_type(p_mono_type), tclass); -} - -ManagedType ManagedType::from_reftype(MonoReflectionType *p_mono_reftype) { - MonoType *mono_type = mono_reflection_type_get_type(p_mono_reftype); - return from_type(mono_type); -} diff --git a/modules/mono/mono_gd/managed_type.h b/modules/mono/mono_gd/managed_type.h deleted file mode 100644 index 603ff3aca1..0000000000 --- a/modules/mono/mono_gd/managed_type.h +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************/ -/* managed_type.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef MANAGED_TYPE_H -#define MANAGED_TYPE_H - -#include <mono/metadata/object.h> - -#include "gd_mono_header.h" - -struct ManagedType { - int type_encoding = 0; - GDMonoClass *type_class = nullptr; - - static ManagedType from_class(GDMonoClass *p_class); - static ManagedType from_class(MonoClass *p_mono_class); - static ManagedType from_type(MonoType *p_mono_type); - static ManagedType from_reftype(MonoReflectionType *p_mono_reftype); - - ManagedType() {} - - ManagedType(int p_type_encoding, GDMonoClass *p_type_class) : - type_encoding(p_type_encoding), - type_class(p_type_class) { - } -}; - -#endif // MANAGED_TYPE_H diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp index 4797d5dae1..7fb983cd37 100644 --- a/modules/mono/mono_gd/support/android_support.cpp +++ b/modules/mono/mono_gd/support/android_support.cpp @@ -359,7 +359,7 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) { ScopedLocalRef<jbyteArray> encoded(env, (jbyteArray)env->CallObjectMethod(certificate, getEncoded)); jsize encodedLength = env->GetArrayLength(encoded); - MonoArray *encoded_ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), encodedLength); + MonoArray *encoded_ret = mono_array_new(mono_domain_get(), mono_get_byte_class(), encodedLength); uint8_t *dest = (uint8_t *)mono_array_addr(encoded_ret, uint8_t, 0); env->GetByteArrayRegion(encoded, 0, encodedLength, reinterpret_cast<jbyte *>(dest)); |