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.cpp41
-rw-r--r--modules/mono/mono_gd/gd_mono.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp97
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h8
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp55
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h19
7 files changed, 119 insertions, 107 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 77f01842bb..2c88832998 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -31,6 +31,7 @@
#include <mono/metadata/mono-config.h>
#include <mono/metadata/mono-debug.h>
+#include <mono/metadata/mono-gc.h>
#include "os/dir_access.h"
#include "os/file_access.h"
@@ -265,6 +266,13 @@ void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) {
assemblies[p_domain_id][p_assembly->get_name()] = p_assembly;
}
+GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) {
+
+ MonoDomain *domain = mono_domain_get();
+ uint32_t domain_id = domain ? mono_domain_get_id(domain) : 0;
+ return assemblies[domain_id].getptr(p_name);
+}
+
bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) {
CRASH_COND(!r_assembly);
@@ -272,39 +280,22 @@ bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) {
if (OS::get_singleton()->is_stdout_verbose())
OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + "...\n").utf8());
- MonoImageOpenStatus status;
+ MonoImageOpenStatus status = MONO_IMAGE_OK;
MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
MonoAssembly *assembly = mono_assembly_load_full(aname, NULL, &status, false);
mono_assembly_name_free(aname);
- if (!assembly)
- return false;
+ ERR_FAIL_NULL_V(assembly, false);
uint32_t domain_id = mono_domain_get_id(mono_domain_get());
GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name);
- if (stored_assembly) {
- // Loaded by our preload hook (status is not initialized when returning from a preload hook)
- ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false);
- *r_assembly = *stored_assembly;
- } else {
- ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);
-
- MonoImage *assembly_image = mono_assembly_get_image(assembly);
- ERR_FAIL_NULL_V(assembly_image, false);
+ ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);
+ ERR_FAIL_COND_V(stored_assembly == NULL, false);
- const char *path = mono_image_get_filename(assembly_image);
-
- *r_assembly = memnew(GDMonoAssembly(p_name, path));
- Error error = (*r_assembly)->wrapper_for_image(assembly_image);
-
- if (error != OK) {
- memdelete(*r_assembly);
- *r_assembly = NULL;
- ERR_FAIL_V(false);
- }
- }
+ ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false);
+ *r_assembly = *stored_assembly;
if (OS::get_singleton()->is_stdout_verbose())
OS::get_singleton()->print(String("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8());
@@ -438,10 +429,14 @@ 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;
mono_domain_finalize(scripts_domain, 2000);
finalizing_scripts_domain = false;
+ mono_gc_collect(mono_gc_max_generation());
+
_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
api_assembly = NULL;
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index ab96d575e6..b188c0730a 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -122,7 +122,9 @@ public:
static GDMono *get_singleton() { return singleton; }
+ // Do not use these, unless you know what you're doing
void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly);
+ GDMonoAssembly **get_loaded_assembly(const String &p_name);
_FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized; }
_FORCE_INLINE_ bool is_finalizing_scripts_domain() const { return finalizing_scripts_domain; }
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index a98537b9e1..4b370295f3 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -39,28 +39,60 @@
#include "../godotsharp_dirs.h"
#include "gd_mono_class.h"
-MonoAssembly *gdmono_load_assembly_from(const String &p_name, const String &p_path) {
+bool GDMonoAssembly::no_search = false;
+Vector<String> GDMonoAssembly::search_dirs;
- MonoDomain *domain = mono_domain_get();
+MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data) {
- GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path));
- Error err = assembly->load(domain);
- ERR_FAIL_COND_V(err != OK, NULL);
+ (void)user_data; // UNUSED
- GDMono::get_singleton()->add_assembly(mono_domain_get_id(domain), assembly);
+ String name = mono_assembly_name_get_name(aname);
+ bool has_extension = name.ends_with(".dll") || name.ends_with(".exe");
- return assembly->get_assembly();
-}
+ if (no_search)
+ return NULL;
-MonoAssembly *gdmono_MonoAssemblyPreLoad(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
+ GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
+ if (loaded_asm)
+ return (*loaded_asm)->get_assembly();
- (void)user_data; // UNUSED
+ no_search = true; // Avoid the recursion madness
+
+ String path;
+ MonoAssembly *res = NULL;
+
+ for (int i = 0; i < search_dirs.size(); i++) {
+ const String &search_dir = search_dirs[i];
- MonoAssembly *assembly_loaded = mono_assembly_loaded(aname);
- if (assembly_loaded) // Already loaded
- return assembly_loaded;
+ if (has_extension) {
+ path = search_dir.plus_file(name);
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name.get_basename(), path);
+ break;
+ }
+ } else {
+ path = search_dir.plus_file(name + ".dll");
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name, path);
+ break;
+ }
+
+ path = search_dir.plus_file(name + ".exe");
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name, path);
+ break;
+ }
+ }
+ }
- static Vector<String> search_dirs;
+ no_search = false;
+
+ return res;
+}
+
+MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
+
+ (void)user_data; // UNUSED
if (search_dirs.empty()) {
search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
@@ -80,35 +112,32 @@ MonoAssembly *gdmono_MonoAssemblyPreLoad(MonoAssemblyName *aname, char **assembl
}
}
- String name = mono_assembly_name_get_name(aname);
- bool has_extension = name.ends_with(".dll") || name.ends_with(".exe");
+ return NULL;
+}
- String path;
+MonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path) {
- for (int i = 0; i < search_dirs.size(); i++) {
- const String &search_dir = search_dirs[i];
+ GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path));
- if (has_extension) {
- path = search_dir.plus_file(name);
- if (FileAccess::exists(path))
- return gdmono_load_assembly_from(name.get_basename(), path);
- } else {
- path = search_dir.plus_file(name + ".dll");
- if (FileAccess::exists(path))
- return gdmono_load_assembly_from(name, path);
+ MonoDomain *domain = mono_domain_get();
- path = search_dir.plus_file(name + ".exe");
- if (FileAccess::exists(path))
- return gdmono_load_assembly_from(name, path);
- }
+ Error err = assembly->load(domain);
+
+ if (err != OK) {
+ memdelete(assembly);
+ ERR_FAIL_V(NULL);
}
- return NULL;
+ GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, assembly);
+
+ return assembly->get_assembly();
}
void GDMonoAssembly::initialize() {
- mono_install_assembly_preload_hook(&gdmono_MonoAssemblyPreLoad, NULL);
+ // TODO refonly as well?
+ mono_install_assembly_preload_hook(&GDMonoAssembly::_preload_hook, NULL);
+ mono_install_assembly_search_hook(&GDMonoAssembly::_search_hook, NULL);
}
Error GDMonoAssembly::load(MonoDomain *p_domain) {
@@ -153,7 +182,7 @@ no_pdb:
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
- if (mono_image_get_entry_point(image)) {
+ if (p_domain && mono_image_get_entry_point(image)) {
// TODO should this be removed? do we want to call main? what other effects does this have?
mono_jit_exec(p_domain, assembly, 0, NULL);
}
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 89e091549c..710b674622 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -86,6 +86,14 @@ class GDMonoAssembly {
Vector<uint8_t> pdb_data;
#endif
+ static bool no_search;
+ static Vector<String> search_dirs;
+
+ static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data);
+ static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
+
+ static MonoAssembly *_load_assembly_from(const String &p_name, const String &p_path);
+
friend class GDMono;
static void initialize();
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 0c64380e31..c2d8eeaa32 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -279,11 +279,11 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
}
bool GDMonoField::get_bool_value(MonoObject *p_object) {
- return UNBOX_BOOLEAN(get_value(p_object));
+ return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object));
}
int GDMonoField::get_int_value(MonoObject *p_object) {
- return UNBOX_INT32(get_value(p_object));
+ return GDMonoMarshal::unbox<int32_t>(get_value(p_object));
}
String GDMonoField::get_string_value(MonoObject *p_object) {
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index b5419952de..b64915109f 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -41,11 +41,11 @@ namespace GDMonoMarshal {
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_t), raw); \
}
-#define RETURN_UNBOXED_STRUCT(m_t, m_var_in) \
- { \
- float *raw = UNBOX_FLOAT_PTR(m_var_in); \
- MARSHALLED_IN(m_t, raw, ret); \
- return ret; \
+#define RETURN_UNBOXED_STRUCT(m_t, m_var_in) \
+ { \
+ float *raw = (float *)mono_object_unbox(m_var_in); \
+ MARSHALLED_IN(m_t, raw, ret); \
+ return ret; \
}
Variant::Type managed_to_variant_type(const ManagedType &p_type) {
@@ -453,30 +453,30 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
- return (bool)UNBOX_BOOLEAN(p_obj);
+ return (bool)unbox<MonoBoolean>(p_obj);
case MONO_TYPE_I1:
- return UNBOX_INT8(p_obj);
+ return unbox<int8_t>(p_obj);
case MONO_TYPE_I2:
- return UNBOX_INT16(p_obj);
+ return unbox<int16_t>(p_obj);
case MONO_TYPE_I4:
- return UNBOX_INT32(p_obj);
+ return unbox<int32_t>(p_obj);
case MONO_TYPE_I8:
- return UNBOX_INT64(p_obj);
+ return unbox<int64_t>(p_obj);
case MONO_TYPE_U1:
- return UNBOX_UINT8(p_obj);
+ return unbox<uint8_t>(p_obj);
case MONO_TYPE_U2:
- return UNBOX_UINT16(p_obj);
+ return unbox<uint16_t>(p_obj);
case MONO_TYPE_U4:
- return UNBOX_UINT32(p_obj);
+ return unbox<uint32_t>(p_obj);
case MONO_TYPE_U8:
- return UNBOX_UINT64(p_obj);
+ return unbox<uint64_t>(p_obj);
case MONO_TYPE_R4:
- return UNBOX_FLOAT(p_obj);
+ return unbox<float>(p_obj);
case MONO_TYPE_R8:
- return UNBOX_DOUBLE(p_obj);
+ return unbox<double>(p_obj);
case MONO_TYPE_STRING: {
String str = mono_string_to_godot((MonoString *)p_obj);
@@ -554,29 +554,18 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
// GodotObject
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- GDMonoField *ptr_field = CACHED_FIELD(GodotObject, ptr);
-
- ERR_FAIL_NULL_V(ptr_field, Variant());
-
- void *ptr_to_unmanaged = UNBOX_PTR(ptr_field->get_value(p_obj));
-
- if (!ptr_to_unmanaged) // IntPtr.Zero
- return Variant();
-
- Object *object_ptr = static_cast<Object *>(ptr_to_unmanaged);
-
- if (!object_ptr)
- return Variant();
-
- return object_ptr;
+ Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
+ return ptr ? Variant(ptr) : Variant();
}
if (CACHED_CLASS(NodePath) == type_class) {
- return UNBOX_PTR(CACHED_FIELD(NodePath, ptr)->get_value(p_obj));
+ NodePath *ptr = unbox<NodePath *>(CACHED_FIELD(NodePath, ptr)->get_value(p_obj));
+ return ptr ? Variant(*ptr) : Variant();
}
if (CACHED_CLASS(RID) == type_class) {
- return UNBOX_PTR(CACHED_FIELD(RID, ptr)->get_value(p_obj));
+ RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj));
+ return ptr ? Variant(*ptr) : Variant();
}
} break;
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 5fbafa0acb..38dd22357d 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -36,21 +36,10 @@
namespace GDMonoMarshal {
-#define UNBOX_CHAR_PTR(x) (char *)mono_object_unbox(x)
-#define UNBOX_FLOAT_PTR(x) (float *)mono_object_unbox(x)
-
-#define UNBOX_DOUBLE(x) *(double *)mono_object_unbox(x)
-#define UNBOX_FLOAT(x) *(float *)mono_object_unbox(x)
-#define UNBOX_INT64(x) *(int64_t *)mono_object_unbox(x)
-#define UNBOX_INT32(x) *(int32_t *)mono_object_unbox(x)
-#define UNBOX_INT16(x) *(int16_t *)mono_object_unbox(x)
-#define UNBOX_INT8(x) *(int8_t *)mono_object_unbox(x)
-#define UNBOX_UINT64(x) *(uint64_t *)mono_object_unbox(x)
-#define UNBOX_UINT32(x) *(uint32_t *)mono_object_unbox(x)
-#define UNBOX_UINT16(x) *(uint16_t *)mono_object_unbox(x)
-#define UNBOX_UINT8(x) *(uint8_t *)mono_object_unbox(x)
-#define UNBOX_BOOLEAN(x) *(MonoBoolean *)mono_object_unbox(x)
-#define UNBOX_PTR(x) mono_object_unbox(x)
+template <typename T>
+T unbox(MonoObject *p_obj) {
+ return *(T *)mono_object_unbox(p_obj);
+}
#define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x)
#define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x)