summaryrefslogtreecommitdiff
path: root/modules/mono/mono_gd
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/mono_gd')
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp242
-rw-r--r--modules/mono/mono_gd/gd_mono.h34
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp24
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h8
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp22
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h9
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp52
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h20
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h22
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp55
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp64
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h5
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp224
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h35
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp18
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h22
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp19
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h21
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp131
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h48
-rw-r--r--modules/mono/mono_gd/i_mono_class_member.h (renamed from modules/mono/mono_gd/gd_mono_class_member.h)17
-rw-r--r--modules/mono/mono_gd/managed_type.cpp58
-rw-r--r--modules/mono/mono_gd/managed_type.h58
24 files changed, 842 insertions, 372 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index a80155bd89..19e49d29f9 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -30,10 +30,12 @@
#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/os/dir_access.h"
#include "core/os/file_access.h"
@@ -54,16 +56,9 @@
#include "main/main.h"
#endif
-#ifdef MONO_PRINT_HANDLER_ENABLED
-void gdmono_MonoPrintCallback(const char *string, mono_bool is_stdout) {
-
- if (is_stdout) {
- OS::get_singleton()->print(string);
- } else {
- OS::get_singleton()->printerr(string);
- }
-}
-#endif
+#define OUT_OF_SYNC_ERR_MESSAGE(m_assembly_name) "The assembly '" m_assembly_name "' is out of sync. " \
+ "This error is expected if you just upgraded to a newer Godot version. " \
+ "Building the project will update the assembly to the correct version."
GDMono *GDMono::singleton = NULL;
@@ -90,6 +85,14 @@ void setup_runtime_main_args() {
mono_runtime_set_main_args(main_args.size(), main_args.ptrw());
}
+void gdmono_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());
+ }
+}
+
#ifdef DEBUG_ENABLED
static bool _wait_for_debugger_msecs(uint32_t p_msecs) {
@@ -102,7 +105,7 @@ static bool _wait_for_debugger_msecs(uint32_t p_msecs) {
OS::get_singleton()->delay_usec((p_msecs < 25 ? p_msecs : 25) * 1000);
- int tdiff = OS::get_singleton()->get_ticks_msec() - last_tick;
+ uint32_t tdiff = OS::get_singleton()->get_ticks_msec() - last_tick;
if (tdiff > p_msecs) {
p_msecs = 0;
@@ -130,9 +133,14 @@ void gdmono_debug_init() {
}
#endif
- CharString 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();
+ CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8();
+
+ if (da_args.length() == 0) {
+ da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) +
+ ",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n"))
+ .utf8();
+ }
+
// --debugger-agent=help
const char *options[] = {
"--soft-breakpoints",
@@ -145,6 +153,50 @@ void gdmono_debug_init() {
} // namespace
+void GDMono::add_mono_shared_libs_dir_to_path() {
+ // 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 += ';';
+
+ 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
+
+#else
+ path_value += ':';
+
+ 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
+
+ OS::get_singleton()->set_environment(path_var, path_value);
+#endif // WINDOWS_ENABLED || UNIX_ENABLED
+}
+
void GDMono::initialize() {
ERR_FAIL_NULL(Engine::get_singleton());
@@ -157,16 +209,11 @@ void GDMono::initialize() {
GDMonoLog::get_singleton()->initialize();
-#ifdef MONO_PRINT_HANDLER_ENABLED
- mono_trace_set_print_handler(gdmono_MonoPrintCallback);
- mono_trace_set_printerr_handler(gdmono_MonoPrintCallback);
-#endif
-
String assembly_rootdir;
String config_dir;
#ifdef TOOLS_ENABLED
-#ifdef WINDOWS_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)) {
@@ -176,7 +223,7 @@ void GDMono::initialize() {
if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) {
config_dir = mono_reg_info.config_dir;
}
-#elif OSX_ENABLED
+#elif defined(OSX_ENABLED)
const char *c_assembly_rootdir = mono_assembly_getrootdir();
const char *c_config_dir = mono_get_config_dir();
@@ -208,18 +255,32 @@ void GDMono::initialize() {
assembly_rootdir = bundled_assembly_rootdir;
config_dir = bundled_config_dir;
}
+
+#ifdef WINDOWS_ENABLED
+ if (assembly_rootdir.empty() || config_dir.empty()) {
+ // 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);
+
+ ERR_PRINT("Cannot find Mono in the registry");
+ }
+#endif // WINDOWS_ENABLED
+
#else
// These are always the directories in export templates
assembly_rootdir = bundled_assembly_rootdir;
config_dir = bundled_config_dir;
-#endif
+#endif // TOOLS_ENABLED
// Leak if we call mono_set_dirs more than once
mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : NULL,
config_dir.length() ? config_dir.utf8().get_data() : NULL);
+ add_mono_shared_libs_dir_to_path();
+
GDMonoAssembly::initialize();
+ gdmono_profiler_init();
+
#ifdef DEBUG_ENABLED
gdmono_debug_init();
#endif
@@ -228,6 +289,29 @@ void GDMono::initialize() {
mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL);
+#ifndef TOOLS_ENABLED
+ if (!DirAccess::exists("res://.mono")) {
+ // 'res://.mono/' is missing so there is nothing to load. We don't need to initialize mono, but
+ // we still do so unless mscorlib is missing (which is the case for projects that don't use C#).
+
+ String mscorlib_fname("mscorlib.dll");
+
+ Vector<String> search_dirs;
+ GDMonoAssembly::fill_search_dirs(search_dirs);
+
+ bool found = false;
+ for (int i = 0; i < search_dirs.size(); i++) {
+ if (FileAccess::exists(search_dirs[i].plus_file(mscorlib_fname))) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return; // mscorlib is missing, do not initialize mono
+ }
+#endif
+
root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
ERR_EXPLAIN("Mono: Failed to initialize runtime");
@@ -285,15 +369,15 @@ void GDMono::initialize() {
// metadata, so we invalidate the version in the metadata and unload the script domain.
if (core_api_assembly_out_of_sync) {
- ERR_PRINT("The loaded Core API assembly is out of sync");
+ ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME));
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
- ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed");
+ ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed");
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
}
if (editor_api_assembly_out_of_sync) {
- ERR_PRINT("The loaded Editor API assembly is out of sync");
+ ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME));
metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
}
@@ -322,7 +406,7 @@ namespace GodotSharpBindings {
uint64_t get_core_api_hash();
#ifdef TOOLS_ENABLED
uint64_t get_editor_api_hash();
-#endif // TOOLS_ENABLED
+#endif
uint32_t get_bindings_version();
void register_generated_icalls();
@@ -339,29 +423,20 @@ void GDMono::_register_internal_calls() {
#endif
}
-#ifdef DEBUG_METHODS_ENABLED
void GDMono::_initialize_and_check_api_hashes() {
- api_core_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
-
#ifdef MONO_GLUE_ENABLED
- if (api_core_hash != GodotSharpBindings::get_core_api_hash()) {
+ if (get_api_core_hash() != GodotSharpBindings::get_core_api_hash()) {
ERR_PRINT("Mono: Core API hash mismatch!");
}
-#endif
#ifdef TOOLS_ENABLED
- api_editor_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
-
-#ifdef MONO_GLUE_ENABLED
- if (api_editor_hash != GodotSharpBindings::get_editor_api_hash()) {
+ if (get_api_editor_hash() != GodotSharpBindings::get_editor_api_hash()) {
ERR_PRINT("Mono: Editor API hash mismatch!");
}
-#endif
-
#endif // TOOLS_ENABLED
+#endif // MONO_GLUE_ENABLED
}
-#endif // DEBUG_METHODS_ENABLED
void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) {
@@ -513,6 +588,8 @@ bool GDMono::_load_core_api_assembly() {
CS_GLUE_VERSION != api_assembly_ver.cs_glue_version;
if (!core_api_assembly_out_of_sync) {
GDMonoUtils::update_godot_api_cache();
+
+ _install_trace_listener();
}
#else
GDMonoUtils::update_godot_api_cache();
@@ -581,8 +658,6 @@ bool GDMono::_load_project_assembly() {
if (success) {
mono_assembly_set_main(project_assembly->get_assembly());
-
- CSharpLanguage::get_singleton()->project_assembly_loaded();
} else {
if (OS::get_singleton()->is_stdout_verbose())
print_error("Mono: Failed to load project assembly");
@@ -616,6 +691,23 @@ bool GDMono::_load_api_assemblies() {
return true;
}
+void GDMono::_install_trace_listener() {
+
+#ifdef DEBUG_ENABLED
+ // Install the trace listener now before the project assembly is loaded
+ typedef void (*DebuggingUtils_InstallTraceListener)(MonoObject **);
+ MonoException *exc = NULL;
+ GDMonoClass *debug_utils = core_api_assembly->get_class(BINDINGS_NAMESPACE, "DebuggingUtils");
+ DebuggingUtils_InstallTraceListener install_func =
+ (DebuggingUtils_InstallTraceListener)debug_utils->get_method_thunk("InstallTraceListener");
+ install_func((MonoObject **)&exc);
+ if (exc) {
+ ERR_PRINT("Failed to install System.Diagnostics.Trace listener");
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ }
+#endif
+}
+
#ifdef TOOLS_ENABLED
String GDMono::_get_api_assembly_metadata_path() {
@@ -705,8 +797,6 @@ Error GDMono::_unload_scripts_domain() {
if (mono_domain_get() != root_domain)
mono_domain_set(root_domain, true);
- mono_gc_collect(mono_gc_max_generation());
-
finalizing_scripts_domain = true;
if (!mono_domain_finalize(scripts_domain, 2000)) {
@@ -726,7 +816,9 @@ Error GDMono::_unload_scripts_domain() {
#endif
core_api_assembly_out_of_sync = false;
+#ifdef TOOLS_ENABLED
editor_api_assembly_out_of_sync = false;
+#endif
MonoDomain *domain = scripts_domain;
scripts_domain = NULL;
@@ -759,7 +851,7 @@ Error GDMono::_load_tools_domain() {
}
#endif
-#ifdef TOOLS_ENABLED
+#ifdef GD_MONO_HOT_RELOAD
Error GDMono::reload_scripts_domain() {
ERR_FAIL_COND_V(!runtime_initialized, ERR_BUG);
@@ -772,6 +864,8 @@ Error GDMono::reload_scripts_domain() {
}
}
+ CSharpLanguage::get_singleton()->_on_scripts_domain_unloaded();
+
Error err = _load_scripts_domain();
if (err != OK) {
ERR_PRINT("Mono: Failed to load scripts domain");
@@ -780,14 +874,18 @@ Error GDMono::reload_scripts_domain() {
#ifdef MONO_GLUE_ENABLED
if (!_load_api_assemblies()) {
- if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) ||
- (editor_api_assembly && editor_api_assembly_out_of_sync)) {
+ if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated))
+#ifdef TOOLS_ENABLED
+ || (editor_api_assembly && editor_api_assembly_out_of_sync)
+#endif
+ ) {
+#ifdef TOOLS_ENABLED
// The assembly was successfully loaded, but the full api could not be cached.
// This is most likely an outdated assembly loaded because of an invalid version in the
// metadata, so we invalidate the version in the metadata and unload the script domain.
if (core_api_assembly_out_of_sync) {
- ERR_PRINT("The loaded Core API assembly is out of sync");
+ ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME));
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed");
@@ -795,16 +893,20 @@ Error GDMono::reload_scripts_domain() {
}
if (editor_api_assembly_out_of_sync) {
- ERR_PRINT("The loaded Editor API assembly is out of sync");
+ ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME));
metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
}
- Error err = _unload_scripts_domain();
+ err = _unload_scripts_domain();
if (err != OK) {
WARN_PRINT("Mono: Failed to unload scripts domain");
}
return ERR_CANT_RESOLVE;
+#else
+ ERR_PRINT("The loaded API assembly is invalid");
+ CRASH_NOW();
+#endif
} else {
return ERR_CANT_OPEN;
}
@@ -832,14 +934,20 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
if (mono_domain_get() == p_domain)
mono_domain_set(root_domain, true);
- mono_gc_collect(mono_gc_max_generation());
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));
+#ifdef TOOLS_ENABLED
+ if (p_domain == tools_domain) {
+ editor_tools_assembly = NULL;
+ }
+#endif
+
MonoException *exc = NULL;
mono_domain_try_unload(p_domain, (MonoObject **)&exc);
@@ -899,8 +1007,10 @@ void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) {
if (ScriptDebugger::get_singleton())
ScriptDebugger::get_singleton()->idle_poll();
#endif
- abort();
- _UNREACHABLE_();
+
+ exit(mono_environment_exitcode_get());
+
+ GD_UNREACHABLE();
}
GDMono::GDMono() {
@@ -919,7 +1029,9 @@ GDMono::GDMono() {
#endif
core_api_assembly_out_of_sync = false;
+#ifdef TOOLS_ENABLED
editor_api_assembly_out_of_sync = false;
+#endif
corlib_assembly = NULL;
core_api_assembly = NULL;
@@ -929,23 +1041,29 @@ GDMono::GDMono() {
editor_tools_assembly = NULL;
#endif
-#ifdef DEBUG_METHODS_ENABLED
api_core_hash = 0;
#ifdef TOOLS_ENABLED
api_editor_hash = 0;
#endif
-#endif
}
GDMono::~GDMono() {
if (is_runtime_initialized()) {
- if (scripts_domain) {
+#ifdef TOOLS_ENABLED
+ if (tools_domain) {
+ Error err = finalize_and_unload_domain(tools_domain);
+ if (err != OK) {
+ ERR_PRINT("Mono: Failed to unload tools domain");
+ }
+ }
+#endif
+ if (scripts_domain) {
Error err = _unload_scripts_domain();
if (err != OK) {
- WARN_PRINT("Mono: Failed to unload scripts domain");
+ ERR_PRINT("Mono: Failed to unload scripts domain");
}
}
@@ -966,6 +1084,8 @@ GDMono::~GDMono() {
mono_jit_cleanup(root_domain);
+ print_verbose("Mono: Finalized");
+
runtime_initialized = false;
}
@@ -1057,17 +1177,9 @@ void _GodotSharp::_bind_methods() {
_GodotSharp::_GodotSharp() {
singleton = this;
- queue_empty = true;
-#ifndef NO_THREADS
- queue_mutex = Mutex::create();
-#endif
}
_GodotSharp::~_GodotSharp() {
singleton = NULL;
-
- if (queue_mutex) {
- memdelete(queue_mutex);
- }
}
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index fd9551b6de..216c96a612 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -95,7 +95,9 @@ class GDMono {
#endif
bool core_api_assembly_out_of_sync;
+#ifdef TOOLS_ENABLED
bool editor_api_assembly_out_of_sync;
+#endif
GDMonoAssembly *corlib_assembly;
GDMonoAssembly *core_api_assembly;
@@ -123,6 +125,8 @@ class GDMono {
String _get_api_assembly_metadata_path();
#endif
+ void _install_trace_listener();
+
void _register_internal_calls();
Error _load_scripts_domain();
@@ -132,13 +136,11 @@ class GDMono {
Error _load_tools_domain();
#endif
-#ifdef DEBUG_METHODS_ENABLED
uint64_t api_core_hash;
#ifdef TOOLS_ENABLED
uint64_t api_editor_hash;
#endif
void _initialize_and_check_api_hashes();
-#endif
GDMonoLog *gdmono_log;
@@ -146,15 +148,23 @@ class GDMono {
MonoRegInfo mono_reg_info;
#endif
+ void add_mono_shared_libs_dir_to_path();
+
protected:
static GDMono *singleton;
public:
-#ifdef DEBUG_METHODS_ENABLED
- uint64_t get_api_core_hash() { return api_core_hash; }
+ uint64_t get_api_core_hash() {
+ if (api_core_hash == 0)
+ api_core_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
+ return api_core_hash;
+ }
#ifdef TOOLS_ENABLED
- uint64_t get_api_editor_hash() { return api_editor_hash; }
-#endif
+ uint64_t get_api_editor_hash() {
+ if (api_editor_hash == 0)
+ api_editor_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
+ return api_editor_hash;
+ }
#endif
#ifdef TOOLS_ENABLED
@@ -193,7 +203,7 @@ public:
GDMonoClass *get_class(MonoClass *p_raw_class);
-#ifdef TOOLS_ENABLED
+#ifdef GD_MONO_HOT_RELOAD
Error reload_scripts_domain();
#endif
@@ -266,12 +276,6 @@ class _GodotSharp : public Object {
List<NodePath *> np_delete_queue;
List<RID *> rid_delete_queue;
- bool queue_empty;
-
-#ifndef NO_THREADS
- Mutex *queue_mutex;
-#endif
-
protected:
static _GodotSharp *singleton;
static void _bind_methods();
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 72b0204672..8fec28b186 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -50,7 +50,7 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin
const char *rootdir = mono_assembly_getrootdir();
if (rootdir) {
- String framework_dir = String(rootdir).plus_file("mono").plus_file("4.5");
+ String framework_dir = String::utf8(rootdir).plus_file("mono").plus_file("4.5");
r_search_dirs.push_back(framework_dir);
r_search_dirs.push_back(framework_dir.plus_file("Facades"));
}
@@ -277,6 +277,7 @@ Error GDMonoAssembly::load(bool p_refonly) {
ERR_FAIL_NULL_V(image, ERR_FILE_CANT_OPEN);
#ifdef DEBUG_ENABLED
+ Vector<uint8_t> pdb_data;
String pdb_path(path + ".pdb");
if (!FileAccess::exists(pdb_path)) {
@@ -286,8 +287,9 @@ Error GDMonoAssembly::load(bool p_refonly) {
goto no_pdb;
}
- pdb_data.clear();
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:
@@ -306,6 +308,9 @@ no_pdb:
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
+ // Decrement refcount which was previously incremented by mono_image_open_from_data_with_name
+ mono_image_close(image);
+
loaded = true;
modified_time = last_modified_time;
@@ -321,8 +326,6 @@ Error GDMonoAssembly::wrapper_for_image(MonoImage *p_image) {
image = p_image;
- mono_image_addref(image);
-
loaded = true;
return OK;
@@ -332,13 +335,6 @@ void GDMonoAssembly::unload() {
ERR_FAIL_COND(!loaded);
-#ifdef DEBUG_ENABLED
- if (pdb_data.size()) {
- mono_debug_close_image(image);
- pdb_data.clear();
- }
-#endif
-
for (Map<MonoClass *, GDMonoClass *>::Element *E = cached_raw.front(); E; E = E->next()) {
memdelete(E->value());
}
@@ -346,8 +342,6 @@ void GDMonoAssembly::unload() {
cached_classes.clear();
cached_raw.clear();
- mono_image_close(image);
-
assembly = NULL;
image = NULL;
loaded = false;
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 2af40ec901..32432af37d 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -84,10 +84,6 @@ class GDMonoAssembly {
bool gdobject_class_cache_updated;
Map<StringName, GDMonoClass *> gdobject_class_cache;
-#ifdef DEBUG_ENABLED
- Vector<uint8_t> pdb_data;
-#endif
-
static bool no_search;
static bool in_preload;
static Vector<String> search_dirs;
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index c55f9160bd..4342f46109 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -55,12 +55,21 @@ String GDMonoClass::get_full_name() const {
}
MonoType *GDMonoClass::get_mono_type() {
- // Care, you cannot compare MonoType pointers
+ // 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);
}
-bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
+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);
}
@@ -252,6 +261,11 @@ bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) {
return get_fetched_method_unknown_params(p_name) != NULL;
}
+bool GDMonoClass::implements_interface(GDMonoClass *p_interface) {
+
+ return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr());
+}
+
GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
MethodKey key = MethodKey(p_name, p_params_count);
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index 689001f494..249422b844 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -109,6 +109,9 @@ public:
String get_full_name() const;
MonoType *get_mono_type();
+ uint32_t get_flags() const;
+ bool is_static() const;
+
bool is_assignable_from(GDMonoClass *p_from) const;
_FORCE_INLINE_ StringName get_namespace() const { return namespace_name; }
@@ -132,6 +135,8 @@ public:
void fetch_attributes();
void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
+ bool implements_interface(GDMonoClass *p_interface);
+
GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0);
GDMonoMethod *get_method(MonoMethod *p_raw_method);
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index f09e93e662..9779797d1a 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -49,7 +49,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
#define SET_FROM_ARRAY(m_type) \
{ \
MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \
- mono_field_set_value(p_object, mono_field, &managed); \
+ mono_field_set_value(p_object, mono_field, managed); \
}
switch (type.type_encoding) {
@@ -313,6 +313,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
ERR_FAIL();
} break;
@@ -422,8 +434,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -434,8 +446,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
@@ -443,6 +455,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
mono_field_set_value(p_object, mono_field, managed);
break;
}
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
} break;
default: {
@@ -505,20 +529,20 @@ bool GDMonoField::is_static() {
return mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_STATIC;
}
-GDMonoClassMember::Visibility GDMonoField::get_visibility() {
+IMonoClassMember::Visibility GDMonoField::get_visibility() {
switch (mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_FIELD_ACCESS_MASK) {
case MONO_FIELD_ATTR_PRIVATE:
- return GDMonoClassMember::PRIVATE;
+ return IMonoClassMember::PRIVATE;
case MONO_FIELD_ATTR_FAM_AND_ASSEM:
- return GDMonoClassMember::PROTECTED_AND_INTERNAL;
+ return IMonoClassMember::PROTECTED_AND_INTERNAL;
case MONO_FIELD_ATTR_ASSEMBLY:
- return GDMonoClassMember::INTERNAL;
+ return IMonoClassMember::INTERNAL;
case MONO_FIELD_ATTR_FAMILY:
- return GDMonoClassMember::PROTECTED;
+ return IMonoClassMember::PROTECTED;
case MONO_FIELD_ATTR_PUBLIC:
- return GDMonoClassMember::PUBLIC;
+ return IMonoClassMember::PUBLIC;
default:
- ERR_FAIL_V(GDMonoClassMember::PRIVATE);
+ ERR_FAIL_V(IMonoClassMember::PRIVATE);
}
}
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
index a6b368c4d6..e348583370 100644
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ b/modules/mono/mono_gd/gd_mono_field.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -32,10 +32,10 @@
#define GDMONOFIELD_H
#include "gd_mono.h"
-#include "gd_mono_class_member.h"
#include "gd_mono_header.h"
+#include "i_mono_class_member.h"
-class GDMonoField : public GDMonoClassMember {
+class GDMonoField : public IMonoClassMember {
GDMonoClass *owner;
MonoClassField *mono_field;
@@ -47,15 +47,15 @@ class GDMonoField : public GDMonoClassMember {
MonoCustomAttrInfo *attributes;
public:
- virtual MemberType get_member_type() { return MEMBER_TYPE_FIELD; }
+ virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_FIELD; }
- virtual StringName get_name() { return name; }
+ virtual StringName get_name() GD_FINAL { return name; }
- virtual bool is_static();
- virtual Visibility get_visibility();
+ virtual bool is_static() GD_FINAL;
+ virtual Visibility get_visibility() GD_FINAL;
- virtual bool has_attribute(GDMonoClass *p_attr_class);
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class);
+ virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
void fetch_attributes();
_FORCE_INLINE_ ManagedType get_type() const { return type; }
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
index 51d0c9b356..d7962eac8b 100644
--- a/modules/mono/mono_gd/gd_mono_header.h
+++ b/modules/mono/mono_gd/gd_mono_header.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -35,24 +35,12 @@
class GDMonoAssembly;
class GDMonoClass;
-class GDMonoClassMember;
class GDMonoField;
-class GDMonoProperty;
class GDMonoMethod;
+class GDMonoProperty;
-struct ManagedType {
- int type_encoding;
- GDMonoClass *type_class;
-
- ManagedType() :
- type_encoding(0),
- type_class(NULL) {
- }
+class IMonoClassMember;
- ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
- type_encoding(p_type_encoding),
- type_class(p_type_class) {
- }
-};
+#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
index 505c030ca1..63bcfe053c 100644
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -34,6 +34,8 @@
#include "../mono_gc_handle.h"
#include "../utils/macros.h"
#include "../utils/thread_local.h"
+#include "gd_mono_class.h"
+#include "gd_mono_marshal.h"
#include "gd_mono_utils.h"
#include <mono/metadata/exception.h>
@@ -55,10 +57,48 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
CRASH_COND(!klass);
- Ref<MonoGCHandle> gchandle = ref ? MonoGCHandle::create_weak(managed) :
- MonoGCHandle::create_strong(managed);
+ GDMonoClass *native = GDMonoUtils::get_class_native_base(klass);
- Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass);
+ CRASH_COND(native == NULL);
+
+ 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 = MonoGCHandle::create_strong(managed);
+
+ Reference *kref = Object::cast_to<Reference>(unmanaged);
+ if (kref) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
+
+ kref->reference();
+ }
+
+ // The object was just created, no script instance binding should have been attached
+ CRASH_COND(unmanaged->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()));
+
+ void *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
+ unmanaged->set_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index(), data);
+
+ return;
+ }
+
+ Ref<MonoGCHandle> gchandle = ref ? MonoGCHandle::create_weak(managed) : MonoGCHandle::create_strong(managed);
+
+ Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native);
CRASH_COND(script.is_null());
@@ -71,8 +111,9 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
void unhandled_exception(MonoException *p_exc) {
mono_unhandled_exception((MonoObject *)p_exc); // prints the exception as well
- abort();
- _UNREACHABLE_();
+ // Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders
+ GDMono::unhandled_exception_hook((MonoObject *)p_exc, NULL);
+ GD_UNREACHABLE();
}
} // namespace GDMonoInternals
diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h
index 50cadcedf6..2d77bde27c 100644
--- a/modules/mono/mono_gd/gd_mono_internals.h
+++ b/modules/mono/mono_gd/gd_mono_internals.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -45,7 +45,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
* Do not call this function directly.
* Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead.
*/
-_NO_RETURN_ void unhandled_exception(MonoException *p_exc);
+GD_NORETURN void unhandled_exception(MonoException *p_exc);
} // namespace GDMonoInternals
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index b7bb2cb2d6..a6e04e561d 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -37,6 +37,7 @@
#include "core/os/os.h"
#include "../godotsharp_dirs.h"
+#include "../utils/string_utils.h"
static int log_level_get_id(const char *p_log_level) {
@@ -52,7 +53,7 @@ static int log_level_get_id(const char *p_log_level) {
return -1;
}
-void gdmono_MonoLogCallback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) {
+static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) {
FileAccess *f = GDMonoLog::get_singleton()->get_log_file();
@@ -72,8 +73,11 @@ void gdmono_MonoLogCallback(const char *log_domain, const char *log_level, const
if (fatal) {
ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: " + GDMonoLog::get_singleton()->get_log_file_path() + "\n");
- // If we were to abort without flushing, the log wouldn't get written.
+ // Make sure to flush before aborting
f->flush();
+ f->close();
+ memdelete(f);
+
abort();
}
}
@@ -93,17 +97,9 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
return true;
}
-void GDMonoLog::_open_log_file(const String &p_file_path) {
-
- log_file = FileAccess::open(p_file_path, FileAccess::WRITE);
-
- ERR_EXPLAIN("Failed to create log file");
- ERR_FAIL_COND(!log_file);
-}
-
void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
- static const uint64_t MAX_SECS = 5 * 86400;
+ static const uint64_t MAX_SECS = 5 * 86400; // 5 days
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND(!da);
@@ -120,10 +116,9 @@ void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
if (!current.ends_with(".txt"))
continue;
- String name = current.get_basename();
- uint64_t unixtime = (uint64_t)name.to_int64();
+ uint64_t modified_time = FileAccess::get_modified_time(da->get_current_dir().plus_file(current));
- if (OS::get_singleton()->get_unix_time() - unixtime > MAX_SECS) {
+ if (OS::get_singleton()->get_unix_time() - modified_time > MAX_SECS) {
da->remove(current);
}
}
@@ -133,27 +128,48 @@ void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
void GDMonoLog::initialize() {
+ CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
+
+ if (log_level.length() != 0 && log_level_get_id(log_level.get_data()) == -1) {
+ ERR_PRINTS(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): " + log_level.get_data());
+ log_level = CharString();
+ }
+
+ if (log_level.length() == 0) {
#ifdef DEBUG_ENABLED
- const char *log_level = "debug";
+ log_level = String("info").utf8();
#else
- const char *log_level = "warning";
+ log_level = String("warning").utf8();
#endif
+ }
String logs_dir = GodotSharpDirs::get_mono_logs_dir();
if (_try_create_logs_dir(logs_dir)) {
_delete_old_log_files(logs_dir);
- log_file_path = logs_dir.plus_file(String::num_int64(OS::get_singleton()->get_unix_time()) + ".txt");
- _open_log_file(log_file_path);
+ OS::Date date_now = OS::get_singleton()->get_date();
+ OS::Time time_now = OS::get_singleton()->get_time();
+ int pid = OS::get_singleton()->get_process_id();
+
+ String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d (%d).txt",
+ date_now.year, date_now.month, date_now.day,
+ time_now.hour, time_now.min, time_now.sec, pid);
+
+ log_file_path = logs_dir.plus_file(log_file_name);
+
+ log_file = FileAccess::open(log_file_path, FileAccess::WRITE);
+ if (!log_file) {
+ ERR_PRINT("Mono: Cannot create log file");
+ }
}
- mono_trace_set_level_string(log_level);
- log_level_id = log_level_get_id(log_level);
+ mono_trace_set_level_string(log_level.get_data());
+ log_level_id = log_level_get_id(log_level.get_data());
if (log_file) {
- print_verbose("Mono: Logfile is " + log_file_path);
- mono_trace_set_log_handler(gdmono_MonoLogCallback, this);
+ OS::get_singleton()->print("Mono: Logfile 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");
}
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
index 3b4ff07b7b..91d0557aa3 100644
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -41,7 +41,6 @@ class GDMonoLog {
String log_file_path;
bool _try_create_logs_dir(const String &p_logs_dir);
- void _open_log_file(const String &p_file_path);
void _delete_old_log_files(const String &p_logs_dir);
static GDMonoLog *singleton;
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index b0b2aec667..d586b73cf9 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -35,7 +35,7 @@
namespace GDMonoMarshal {
-Variant::Type managed_to_variant_type(const ManagedType &p_type) {
+Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
return Variant::BOOL;
@@ -68,39 +68,39 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
} break;
case MONO_TYPE_VALUETYPE: {
- GDMonoClass *tclass = p_type.type_class;
+ GDMonoClass *vtclass = p_type.type_class;
- if (tclass == CACHED_CLASS(Vector2))
+ if (vtclass == CACHED_CLASS(Vector2))
return Variant::VECTOR2;
- if (tclass == CACHED_CLASS(Rect2))
+ if (vtclass == CACHED_CLASS(Rect2))
return Variant::RECT2;
- if (tclass == CACHED_CLASS(Transform2D))
+ if (vtclass == CACHED_CLASS(Transform2D))
return Variant::TRANSFORM2D;
- if (tclass == CACHED_CLASS(Vector3))
+ if (vtclass == CACHED_CLASS(Vector3))
return Variant::VECTOR3;
- if (tclass == CACHED_CLASS(Basis))
+ if (vtclass == CACHED_CLASS(Basis))
return Variant::BASIS;
- if (tclass == CACHED_CLASS(Quat))
+ if (vtclass == CACHED_CLASS(Quat))
return Variant::QUAT;
- if (tclass == CACHED_CLASS(Transform))
+ if (vtclass == CACHED_CLASS(Transform))
return Variant::TRANSFORM;
- if (tclass == CACHED_CLASS(AABB))
+ if (vtclass == CACHED_CLASS(AABB))
return Variant::AABB;
- if (tclass == CACHED_CLASS(Color))
+ if (vtclass == CACHED_CLASS(Color))
return Variant::COLOR;
- if (tclass == CACHED_CLASS(Plane))
+ if (vtclass == CACHED_CLASS(Plane))
return Variant::PLANE;
- if (mono_class_is_enum(tclass->get_mono_ptr()))
+ if (mono_class_is_enum(vtclass->get_mono_ptr()))
return Variant::INT;
} break;
@@ -156,26 +156,74 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
if (CACHED_CLASS(Array) == type_class) {
return Variant::ARRAY;
}
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return Variant::DICTIONARY;
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return Variant::ARRAY;
+ }
} break;
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
+ if (r_export_info) {
+ MonoReflectionType *key_reftype;
+ MonoReflectionType *value_reftype;
+
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes),
+ reftype, &key_reftype, &value_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ ManagedType key_type = ManagedType::from_reftype(key_reftype);
+ ManagedType value_type = ManagedType::from_reftype(value_reftype);
+
+ r_export_info->dictionary.key_type = managed_to_variant_type(key_type);
+ r_export_info->dictionary.key_native_name = NATIVE_GDMONOCLASS_NAME(key_type.type_class);
+ r_export_info->dictionary.value_type = managed_to_variant_type(value_type);
+ r_export_info->dictionary.value_native_name = NATIVE_GDMONOCLASS_NAME(value_type.type_class);
+ }
+
return Variant::DICTIONARY;
}
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
+ if (r_export_info) {
+ MonoReflectionType *elem_reftype;
+
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType),
+ reftype, &elem_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ ManagedType elem_type = ManagedType::from_reftype(elem_reftype);
+
+ r_export_info->array.element_type = managed_to_variant_type(elem_type);
+ r_export_info->array.element_native_name = NATIVE_GDMONOCLASS_NAME(elem_type.type_class);
+ }
+
+ return Variant::ARRAY;
+ }
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return Variant::DICTIONARY;
+ }
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
return Variant::ARRAY;
}
} break;
@@ -294,60 +342,60 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
} break;
case MONO_TYPE_VALUETYPE: {
- GDMonoClass *tclass = p_type.type_class;
+ GDMonoClass *vtclass = p_type.type_class;
- if (tclass == CACHED_CLASS(Vector2)) {
+ if (vtclass == CACHED_CLASS(Vector2)) {
GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
}
- if (tclass == CACHED_CLASS(Rect2)) {
+ if (vtclass == CACHED_CLASS(Rect2)) {
GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
}
- if (tclass == CACHED_CLASS(Transform2D)) {
+ if (vtclass == CACHED_CLASS(Transform2D)) {
GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
}
- if (tclass == CACHED_CLASS(Vector3)) {
+ if (vtclass == CACHED_CLASS(Vector3)) {
GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
}
- if (tclass == CACHED_CLASS(Basis)) {
+ if (vtclass == CACHED_CLASS(Basis)) {
GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
}
- if (tclass == CACHED_CLASS(Quat)) {
+ if (vtclass == CACHED_CLASS(Quat)) {
GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
}
- if (tclass == CACHED_CLASS(Transform)) {
+ if (vtclass == CACHED_CLASS(Transform)) {
GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
}
- if (tclass == CACHED_CLASS(AABB)) {
+ if (vtclass == CACHED_CLASS(AABB)) {
GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
}
- if (tclass == CACHED_CLASS(Color)) {
+ if (vtclass == CACHED_CLASS(Color)) {
GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
}
- if (tclass == CACHED_CLASS(Plane)) {
+ if (vtclass == CACHED_CLASS(Plane)) {
GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
}
- if (mono_class_is_enum(tclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
+ 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: {
@@ -453,6 +501,14 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
if (CACHED_CLASS(Array) == type_class) {
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
}
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+ }
} break;
case MONO_TYPE_OBJECT: {
// Variant
@@ -548,8 +604,8 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -557,13 +613,21 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
}
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+ }
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+ }
} break;
} break;
}
@@ -577,15 +641,9 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
if (!p_obj)
return Variant();
- GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
- ERR_FAIL_COND_V(!tclass, Variant());
+ ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
- MonoType *raw_type = tclass->get_mono_type();
-
- ManagedType type;
-
- type.type_encoding = mono_type_get_type(raw_type);
- type.type_class = tclass;
+ ERR_FAIL_COND_V(!type.type_class, Variant());
switch (type.type_encoding) {
case MONO_TYPE_BOOLEAN:
@@ -624,39 +682,39 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
} break;
case MONO_TYPE_VALUETYPE: {
- GDMonoClass *tclass = type.type_class;
+ GDMonoClass *vtclass = type.type_class;
- if (tclass == CACHED_CLASS(Vector2))
+ if (vtclass == CACHED_CLASS(Vector2))
return MARSHALLED_IN(Vector2, (GDMonoMarshal::M_Vector2 *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Rect2))
+ if (vtclass == CACHED_CLASS(Rect2))
return MARSHALLED_IN(Rect2, (GDMonoMarshal::M_Rect2 *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Transform2D))
+ if (vtclass == CACHED_CLASS(Transform2D))
return MARSHALLED_IN(Transform2D, (GDMonoMarshal::M_Transform2D *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Vector3))
+ if (vtclass == CACHED_CLASS(Vector3))
return MARSHALLED_IN(Vector3, (GDMonoMarshal::M_Vector3 *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Basis))
+ if (vtclass == CACHED_CLASS(Basis))
return MARSHALLED_IN(Basis, (GDMonoMarshal::M_Basis *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Quat))
+ if (vtclass == CACHED_CLASS(Quat))
return MARSHALLED_IN(Quat, (GDMonoMarshal::M_Quat *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Transform))
+ if (vtclass == CACHED_CLASS(Transform))
return MARSHALLED_IN(Transform, (GDMonoMarshal::M_Transform *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(AABB))
+ if (vtclass == CACHED_CLASS(AABB))
return MARSHALLED_IN(AABB, (GDMonoMarshal::M_AABB *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Color))
+ if (vtclass == CACHED_CLASS(Color))
return MARSHALLED_IN(Color, (GDMonoMarshal::M_Color *)mono_object_unbox(p_obj));
- if (tclass == CACHED_CLASS(Plane))
+ if (vtclass == CACHED_CLASS(Plane))
return MARSHALLED_IN(Plane, (GDMonoMarshal::M_Plane *)mono_object_unbox(p_obj));
- if (mono_class_is_enum(tclass->get_mono_ptr()))
+ if (mono_class_is_enum(vtclass->get_mono_ptr()))
return unbox<int32_t>(p_obj);
} break;
@@ -698,7 +756,11 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
// GodotObject
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
- return ptr ? Variant(ptr) : Variant();
+ if (ptr != NULL) {
+ Reference *ref = Object::cast_to<Reference>(ptr);
+ return ref ? Variant(Ref<Reference>(ref)) : Variant(ptr);
+ }
+ return Variant();
}
if (CACHED_CLASS(NodePath) == type_class) {
@@ -713,17 +775,33 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
if (CACHED_CLASS(Array) == type_class) {
MonoException *exc = NULL;
- Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, (MonoObject **)&exc);
+ Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
if (CACHED_CLASS(Dictionary) == type_class) {
MonoException *exc = NULL;
- Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, (MonoObject **)&exc);
+ Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ Dictionary dict;
+ MonoException *exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return dict;
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ Array array;
+ MonoException *exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return array;
+ }
} break;
case MONO_TYPE_GENERICINST: {
@@ -731,12 +809,12 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
- MonoException *exc = NULL;
+ exc = NULL;
MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return *unbox<Dictionary *>(ret);
@@ -744,16 +822,32 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
- MonoException *exc = NULL;
+ exc = NULL;
MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return *unbox<Array *>(ret);
}
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ Dictionary dict;
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return dict;
+ }
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ Array array;
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return array;
+ }
} break;
}
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 4002f2a225..8d3fd4b349 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -32,6 +32,7 @@
#define GDMONOMARSHAL_H
#include "core/variant.h"
+
#include "gd_mono.h"
#include "gd_mono_utils.h"
@@ -56,7 +57,28 @@ T unbox(MonoObject *p_obj) {
#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);
+// FIXME: Made this struct in a hurry. It could be done differently.
+struct ExportInfo {
+ struct ArrayInfo {
+ Variant::Type element_type;
+ String element_native_name;
+
+ ArrayInfo() :
+ element_type(Variant::NIL) {}
+ } array;
+ struct DictionaryInfo {
+ Variant::Type key_type;
+ String key_native_name;
+ Variant::Type value_type;
+ String value_native_name;
+
+ DictionaryInfo() :
+ key_type(Variant::NIL),
+ value_type(Variant::NIL) {}
+ } dictionary;
+};
+
+Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info = NULL);
// String
@@ -206,9 +228,10 @@ enum {
// In the future we may force this if we want to ref return these structs
#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
-// Sometimes clang-format can be an ass
-GD_STATIC_ASSERT(MATCHES_Vector2 &&MATCHES_Rect2 &&MATCHES_Transform2D &&MATCHES_Vector3 &&
- MATCHES_Basis &&MATCHES_Quat &&MATCHES_Transform &&MATCHES_AABB &&MATCHES_Color &&MATCHES_Plane);
+/* clang-format off */
+GD_STATIC_ASSERT(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 &&
+ MATCHES_Basis && MATCHES_Quat && MATCHES_Transform && MATCHES_AABB && MATCHES_Color &&MATCHES_Plane);
+/* clang-format on */
#endif
} // namespace InteropLayout
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index 6ef6e97f5a..7f11e4671d 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -78,20 +78,20 @@ bool GDMonoMethod::is_static() {
return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC;
}
-GDMonoClassMember::Visibility GDMonoMethod::get_visibility() {
+IMonoClassMember::Visibility GDMonoMethod::get_visibility() {
switch (mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
case MONO_METHOD_ATTR_PRIVATE:
- return GDMonoClassMember::PRIVATE;
+ return IMonoClassMember::PRIVATE;
case MONO_METHOD_ATTR_FAM_AND_ASSEM:
- return GDMonoClassMember::PROTECTED_AND_INTERNAL;
+ return IMonoClassMember::PROTECTED_AND_INTERNAL;
case MONO_METHOD_ATTR_ASSEM:
- return GDMonoClassMember::INTERNAL;
+ return IMonoClassMember::INTERNAL;
case MONO_METHOD_ATTR_FAMILY:
- return GDMonoClassMember::PROTECTED;
+ return IMonoClassMember::PROTECTED;
case MONO_METHOD_ATTR_PUBLIC:
- return GDMonoClassMember::PUBLIC;
+ return IMonoClassMember::PUBLIC;
default:
- ERR_FAIL_V(GDMonoClassMember::PRIVATE);
+ ERR_FAIL_V(IMonoClassMember::PRIVATE);
}
}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index 6c3ae5fce0..f74cef438d 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -32,10 +32,10 @@
#define GD_MONO_METHOD_H
#include "gd_mono.h"
-#include "gd_mono_class_member.h"
#include "gd_mono_header.h"
+#include "i_mono_class_member.h"
-class GDMonoMethod : public GDMonoClassMember {
+class GDMonoMethod : public IMonoClassMember {
StringName name;
@@ -57,17 +57,17 @@ class GDMonoMethod : public GDMonoClassMember {
MonoMethod *mono_method;
public:
- virtual MemberType get_member_type() { return MEMBER_TYPE_METHOD; }
+ virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_METHOD; }
- virtual StringName get_name() { return name; }
+ virtual StringName get_name() GD_FINAL { return name; }
- virtual bool is_static();
+ virtual bool is_static() GD_FINAL;
- virtual Visibility get_visibility();
+ virtual Visibility get_visibility() GD_FINAL;
- virtual bool has_attribute(GDMonoClass *p_attr_class);
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class);
- virtual void fetch_attributes();
+ virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ void fetch_attributes();
_FORCE_INLINE_ int get_parameters_count() { return params_count; }
_FORCE_INLINE_ ManagedType get_return_type() { return return_type; }
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index ce66e0c8db..5842e26241 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -27,6 +27,7 @@
/* 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_class.h"
@@ -79,24 +80,24 @@ bool GDMonoProperty::is_static() {
return mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_STATIC;
}
-GDMonoClassMember::Visibility GDMonoProperty::get_visibility() {
+IMonoClassMember::Visibility GDMonoProperty::get_visibility() {
MonoMethod *prop_method = mono_property_get_get_method(mono_property);
if (prop_method == NULL)
prop_method = mono_property_get_set_method(mono_property);
switch (mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
case MONO_METHOD_ATTR_PRIVATE:
- return GDMonoClassMember::PRIVATE;
+ return IMonoClassMember::PRIVATE;
case MONO_METHOD_ATTR_FAM_AND_ASSEM:
- return GDMonoClassMember::PROTECTED_AND_INTERNAL;
+ return IMonoClassMember::PROTECTED_AND_INTERNAL;
case MONO_METHOD_ATTR_ASSEM:
- return GDMonoClassMember::INTERNAL;
+ return IMonoClassMember::INTERNAL;
case MONO_METHOD_ATTR_FAMILY:
- return GDMonoClassMember::PROTECTED;
+ return IMonoClassMember::PROTECTED;
case MONO_METHOD_ATTR_PUBLIC:
- return GDMonoClassMember::PUBLIC;
+ return IMonoClassMember::PUBLIC;
default:
- ERR_FAIL_V(GDMonoClassMember::PRIVATE);
+ ERR_FAIL_V(IMonoClassMember::PRIVATE);
}
}
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index b3f1e2114a..2700c460b0 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -27,14 +27,15 @@
/* 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_class_member.h"
#include "gd_mono_header.h"
+#include "i_mono_class_member.h"
-class GDMonoProperty : public GDMonoClassMember {
+class GDMonoProperty : public IMonoClassMember {
GDMonoClass *owner;
MonoProperty *mono_property;
@@ -46,15 +47,15 @@ class GDMonoProperty : public GDMonoClassMember {
MonoCustomAttrInfo *attributes;
public:
- virtual MemberType get_member_type() { return MEMBER_TYPE_PROPERTY; }
+ virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_PROPERTY; }
- virtual StringName get_name() { return name; }
+ virtual StringName get_name() GD_FINAL { return name; }
- virtual bool is_static();
- virtual Visibility get_visibility();
+ virtual bool is_static() GD_FINAL;
+ virtual Visibility get_visibility() GD_FINAL;
- virtual bool has_attribute(GDMonoClass *p_attr_class);
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class);
+ virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
void fetch_attributes();
bool has_getter();
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 211987d242..bcf5712d16 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -39,6 +39,7 @@
#include "../csharp_script.h"
#include "../utils/macros.h"
+#include "../utils/mutex_utils.h"
#include "gd_mono.h"
#include "gd_mono_class.h"
#include "gd_mono_marshal.h"
@@ -62,6 +63,7 @@ MonoCache mono_cache;
#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val)
#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.method_##m_class##_##m_method, m_val)
#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val)
+#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.property_##m_class##_##m_property, m_val)
void MonoCache::clear_members() {
@@ -80,6 +82,9 @@ void MonoCache::clear_members() {
class_String = NULL;
class_IntPtr = NULL;
+ class_System_Collections_IEnumerable = NULL;
+ class_System_Collections_IDictionary = NULL;
+
#ifdef DEBUG_ENABLED
class_System_Diagnostics_StackTrace = NULL;
methodthunk_System_Diagnostics_StackTrace_GetFrames = NULL;
@@ -142,12 +147,17 @@ void MonoCache::clear_members() {
methodthunk_GodotObject_Dispose = NULL;
methodthunk_Array_GetPtr = NULL;
methodthunk_Dictionary_GetPtr = NULL;
- methodthunk_MarshalUtils_IsArrayGenericType = NULL;
- methodthunk_MarshalUtils_IsDictionaryGenericType = NULL;
methodthunk_SignalAwaiter_SignalCallback = NULL;
methodthunk_SignalAwaiter_FailureCallback = NULL;
methodthunk_GodotTaskScheduler_Activate = NULL;
+ methodthunk_MarshalUtils_TypeIsGenericArray = NULL;
+ methodthunk_MarshalUtils_TypeIsGenericDictionary = NULL;
+ methodthunk_MarshalUtils_ArrayGetElementType = NULL;
+ methodthunk_MarshalUtils_DictionaryGetKeyValueTypes = NULL;
+ methodthunk_MarshalUtils_EnumerableToArray = NULL;
+ methodthunk_MarshalUtils_IDictionaryToDictionary = NULL;
+
task_scheduler_handle = Ref<MonoGCHandle>();
}
@@ -177,6 +187,9 @@ void update_corlib_cache() {
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_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, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_thunk("GetFrames"));
@@ -241,12 +254,17 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, (GodotObject_Dispose)CACHED_CLASS(GodotObject)->get_method_thunk("Dispose", 0));
CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method_thunk("GetPtr", 0));
CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method_thunk("GetPtr", 0));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsArrayGenericType", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsDictionaryGenericType", 1));
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("SignalCallback", 1));
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0));
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, (TypeIsGenericArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericArray", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, (TypeIsGenericDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericDictionary", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, (EnumerableToArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("EnumerableToArray", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, (IDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IDictionaryToDictionary", 2));
+
#ifdef DEBUG_ENABLED
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4));
#endif
@@ -265,61 +283,72 @@ void clear_cache() {
}
MonoObject *unmanaged_get_managed(Object *unmanaged) {
- if (unmanaged) {
- 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 (!unmanaged)
+ return NULL;
+
+ 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 = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+
+ ERR_FAIL_NULL_V(data, NULL);
+
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
- // If the owner does not have a CSharpInstance...
+ if (!script_binding.inited) {
+ SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->get_language_bind_mutex());
- void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+ if (!script_binding.inited) { // Other thread may have set it up
+ // Already had a binding that needs to be setup
+ CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, unmanaged);
- if (data) {
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, NULL);
+ }
+ }
- Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
- ERR_FAIL_COND_V(gchandle.is_null(), NULL);
+ Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
+ ERR_FAIL_COND_V(gchandle.is_null(), NULL);
- MonoObject *target = gchandle->get_target();
+ MonoObject *target = gchandle->get_target();
- if (target)
- return target;
+ if (target)
+ return target;
- CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
+ CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
- // Create a new one
+ // Create a new one
#ifdef DEBUG_ENABLED
- CRASH_COND(script_binding.type_name == StringName());
- CRASH_COND(script_binding.wrapper_class == NULL);
+ CRASH_COND(script_binding.type_name == StringName());
+ CRASH_COND(script_binding.wrapper_class == NULL);
#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, NULL);
-
- gchandle->set_handle(MonoGCHandle::new_strong_handle(mono_object), MonoGCHandle::STRONG_HANDLE);
+ MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged);
+ ERR_FAIL_NULL_V(mono_object, NULL);
- // Tie managed to unmanaged
- Reference *ref = Object::cast_to<Reference>(unmanaged);
+ gchandle->set_handle(MonoGCHandle::new_strong_handle(mono_object), MonoGCHandle::STRONG_HANDLE);
- if (ref) {
- // Unsafe refcount increment. The managed instance also counts as a reference.
- // This way if the unmanaged world has no references to our owner
- // but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
+ // Tie managed to unmanaged
+ Reference *ref = Object::cast_to<Reference>(unmanaged);
- ref->reference();
- }
+ if (ref) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
- return mono_object;
- }
+ ref->reference();
}
- return NULL;
+ return mono_object;
}
void set_main_thread(MonoThread *p_thread) {
@@ -362,6 +391,11 @@ GDMonoClass *type_get_proxy_class(const StringName &p_type) {
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 mono_cache.class_GodotObject;
+ }
+
#ifdef TOOLS_ENABLED
if (!klass) {
return GDMono::get_singleton()->get_editor_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
@@ -565,7 +599,7 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
if (unexpected_exc) {
GDMonoInternals::unhandled_exception(unexpected_exc);
- _UNREACHABLE_();
+ GD_UNREACHABLE();
}
Vector<ScriptLanguage::StackInfo> _si;
@@ -598,13 +632,8 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
}
void debug_unhandled_exception(MonoException *p_exc) {
-#ifdef DEBUG_ENABLED
- GDMonoUtils::debug_send_unhandled_exception_error(p_exc);
- if (ScriptDebugger::get_singleton())
- ScriptDebugger::get_singleton()->idle_poll();
-#endif
GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well
- _UNREACHABLE_();
+ GD_UNREACHABLE();
}
void print_unhandled_exception(MonoException *p_exc) {
@@ -615,7 +644,7 @@ void set_pending_exception(MonoException *p_exc) {
#ifdef HAS_PENDING_EXCEPTIONS
if (get_runtime_invoke_count() == 0) {
debug_unhandled_exception(p_exc);
- _UNREACHABLE_();
+ GD_UNREACHABLE();
}
if (!mono_runtime_set_pending_exception(p_exc, false)) {
@@ -624,7 +653,7 @@ void set_pending_exception(MonoException *p_exc) {
}
#else
debug_unhandled_exception(p_exc);
- _UNREACHABLE_();
+ GD_UNREACHABLE();
#endif
}
@@ -695,7 +724,7 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &
}
void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
- invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, (MonoObject **)r_exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, r_exc);
}
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 170df32991..87610e286c 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -44,23 +44,26 @@
#define UNLIKELY_UNHANDLED_EXCEPTION(m_exc) \
if (unlikely(m_exc != NULL)) { \
GDMonoUtils::debug_unhandled_exception(m_exc); \
- _UNREACHABLE_(); \
+ GD_UNREACHABLE(); \
}
namespace GDMonoUtils {
-typedef void (*GodotObject_Dispose)(MonoObject *, MonoObject **);
-typedef Array *(*Array_GetPtr)(MonoObject *, MonoObject **);
-typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoObject **);
-typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
-typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
-typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
-typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
-typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **);
+typedef void (*GodotObject_Dispose)(MonoObject *, MonoException **);
+typedef Array *(*Array_GetPtr)(MonoObject *, MonoException **);
+typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoException **);
+typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoException **);
+typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoException **);
+typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoException **);
+typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoException **);
+typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoException **);
+
+typedef MonoBoolean (*TypeIsGenericArray)(MonoReflectionType *, MonoException **);
+typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoException **);
+typedef MonoBoolean (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **);
+typedef MonoBoolean (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **);
+typedef void (*EnumerableToArray)(MonoObject *, Array *, MonoException **);
+typedef void (*IDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **);
struct MonoCache {
@@ -83,6 +86,9 @@ struct MonoCache {
GDMonoClass *class_String;
GDMonoClass *class_IntPtr;
+ GDMonoClass *class_System_Collections_IEnumerable;
+ GDMonoClass *class_System_Collections_IDictionary;
+
#ifdef DEBUG_ENABLED
GDMonoClass *class_System_Diagnostics_StackTrace;
StackTrace_GetFrames methodthunk_System_Diagnostics_StackTrace_GetFrames;
@@ -146,12 +152,17 @@ struct MonoCache {
GodotObject_Dispose methodthunk_GodotObject_Dispose;
Array_GetPtr methodthunk_Array_GetPtr;
Dictionary_GetPtr methodthunk_Dictionary_GetPtr;
- IsArrayGenericType methodthunk_MarshalUtils_IsArrayGenericType;
- IsDictionaryGenericType methodthunk_MarshalUtils_IsDictionaryGenericType;
SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
+ TypeIsGenericArray methodthunk_MarshalUtils_TypeIsGenericArray;
+ TypeIsGenericDictionary methodthunk_MarshalUtils_TypeIsGenericDictionary;
+ ArrayGetElementType methodthunk_MarshalUtils_ArrayGetElementType;
+ DictionaryGetKeyValueTypes methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
+ EnumerableToArray methodthunk_MarshalUtils_EnumerableToArray;
+ IDictionaryToDictionary methodthunk_MarshalUtils_IDictionaryToDictionary;
+
Ref<MonoGCHandle> task_scheduler_handle;
bool corlib_cache_updated;
@@ -214,7 +225,7 @@ void set_exception_message(MonoException *p_exc, String message);
void debug_print_unhandled_exception(MonoException *p_exc);
void debug_send_unhandled_exception_error(MonoException *p_exc);
-_NO_RETURN_ void debug_unhandled_exception(MonoException *p_exc);
+GD_NORETURN void debug_unhandled_exception(MonoException *p_exc);
void print_unhandled_exception(MonoException *p_exc);
/**
@@ -255,6 +266,7 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc);
#define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field)
#define CACHED_METHOD(m_class, m_method) (GDMonoUtils::mono_cache.method_##m_class##_##m_method)
#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method)
+#define CACHED_PROPERTY(m_class, m_property) (GDMonoUtils::mono_cache.property_##m_class##_##m_property)
#ifdef REAL_T_IS_DOUBLE
#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double)
diff --git a/modules/mono/mono_gd/gd_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h
index 008ea0e416..553d9edc72 100644
--- a/modules/mono/mono_gd/gd_mono_class_member.h
+++ b/modules/mono/mono_gd/i_mono_class_member.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* gd_mono_class_member.h */
+/* i_mono_class_member.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
@@ -27,14 +27,15 @@
/* 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_MEMBER_H
-#define GD_MONO_CLASS_MEMBER_H
+
+#ifndef I_MONO_CLASS_MEMBER_H
+#define I_MONO_CLASS_MEMBER_H
#include "gd_mono_header.h"
#include <mono/metadata/object.h>
-class GDMonoClassMember {
+class IMonoClassMember {
public:
enum Visibility {
PRIVATE,
@@ -50,7 +51,7 @@ public:
MEMBER_TYPE_METHOD
};
- virtual ~GDMonoClassMember() {}
+ virtual ~IMonoClassMember() {}
virtual MemberType get_member_type() = 0;
@@ -64,4 +65,4 @@ public:
virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) = 0;
};
-#endif // GD_MONO_CLASS_MEMBER_H
+#endif // I_MONO_CLASS_MEMBER_H
diff --git a/modules/mono/mono_gd/managed_type.cpp b/modules/mono/mono_gd/managed_type.cpp
new file mode 100644
index 0000000000..9f736b71cd
--- /dev/null
+++ b/modules/mono/mono_gd/managed_type.cpp
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* managed_type.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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
new file mode 100644
index 0000000000..a537e56aea
--- /dev/null
+++ b/modules/mono/mono_gd/managed_type.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* managed_type.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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;
+ GDMonoClass *type_class;
+
+ 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() :
+ type_encoding(0),
+ type_class(NULL) {
+ }
+
+ ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
+ type_encoding(p_type_encoding),
+ type_class(p_type_class) {
+ }
+};
+
+#endif // MANAGED_TYPE_H