From 270af6fa089ccfb93ace68ada8d476bd902b10fa Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Wed, 3 Jul 2019 09:44:53 +0200 Subject: Re-write mono module editor code in C# Make the build system automatically build the C# Api assemblies to be shipped with the editor. Make the editor, editor player and debug export templates use Api assemblies built with debug symbols. Always run MSBuild to build the editor tools and Api assemblies when building Godot. Several bugs fixed related to assembly hot reloading and restoring state. Fix StringExtensions internal calls not being registered correctly, resulting in MissingMethodException. --- modules/mono/mono_gd/gd_mono_utils.cpp | 114 +++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 47 deletions(-) (limited to 'modules/mono/mono_gd/gd_mono_utils.cpp') diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 1b32f1126e..5987fa8ebb 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -125,6 +125,7 @@ void MonoCache::clear_godot_api_cache() { class_Array = NULL; class_Dictionary = NULL; class_MarshalUtils = NULL; + class_ISerializationListener = NULL; #ifdef DEBUG_ENABLED class_DebuggingUtils = NULL; @@ -242,6 +243,7 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)); CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)); CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils)); + CACHE_CLASS_AND_CHECK(ISerializationListener, GODOT_API_CLASS(ISerializationListener)); #ifdef DEBUG_ENABLED CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils)); @@ -302,7 +304,7 @@ void update_godot_api_cache() { #endif // TODO Move to CSharpLanguage::init() and do handle disposal - MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr()); + MonoObject *task_scheduler = mono_object_new(mono_domain_get(), GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr()); GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler)); mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler); @@ -371,7 +373,6 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) { // 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) - ref->reference(); } @@ -384,7 +385,7 @@ void set_main_thread(MonoThread *p_thread) { void attach_current_thread() { ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized()); - MonoThread *mono_thread = mono_thread_attach(SCRIPTS_DOMAIN); + MonoThread *mono_thread = mono_thread_attach(mono_domain_get()); ERR_FAIL_NULL(mono_thread); } @@ -448,17 +449,12 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class) { } MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) { - String object_type = p_object->get_class_name(); - - if (object_type[0] == '_') - object_type = object_type.substr(1, object_type.length()); - - if (!ClassDB::is_parent_class(object_type, p_native)) { + if (!ClassDB::is_parent_class(p_object->get_class_name(), p_native)) { ERR_EXPLAIN("Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'"); ERR_FAIL_V(NULL); } - MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr()); + MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); ERR_FAIL_NULL_V(mono_object, NULL); CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object); @@ -470,7 +466,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa } MonoObject *create_managed_from(const NodePath &p_from) { - MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(NodePath)); + MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(NodePath)); ERR_FAIL_NULL_V(mono_object, NULL); // Construct @@ -482,7 +478,7 @@ MonoObject *create_managed_from(const NodePath &p_from) { } MonoObject *create_managed_from(const RID &p_from) { - MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(RID)); + MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(RID)); ERR_FAIL_NULL_V(mono_object, NULL); // Construct @@ -494,7 +490,7 @@ MonoObject *create_managed_from(const RID &p_from) { } MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) { - MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr()); + MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); ERR_FAIL_NULL_V(mono_object, NULL); // Search constructor that takes a pointer as parameter @@ -518,13 +514,13 @@ MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) { MonoException *exc = NULL; GDMonoUtils::runtime_invoke(m, mono_object, args, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + UNHANDLED_EXCEPTION(exc); return mono_object; } MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) { - MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr()); + MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); ERR_FAIL_NULL_V(mono_object, NULL); // Search constructor that takes a pointer as parameter @@ -548,7 +544,7 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) MonoException *exc = NULL; GDMonoUtils::runtime_invoke(m, mono_object, args, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + UNHANDLED_EXCEPTION(exc); return mono_object; } @@ -667,7 +663,10 @@ void print_unhandled_exception(MonoException *p_exc) { } void set_pending_exception(MonoException *p_exc) { -#ifdef HAS_PENDING_EXCEPTIONS +#ifdef NO_PENDING_EXCEPTIONS + debug_unhandled_exception(p_exc); + GD_UNREACHABLE(); +#else if (get_runtime_invoke_count() == 0) { debug_unhandled_exception(p_exc); GD_UNREACHABLE(); @@ -677,9 +676,6 @@ void set_pending_exception(MonoException *p_exc) { ERR_PRINTS("Exception thrown from managed code, but it could not be set as pending:"); GDMonoUtils::debug_print_unhandled_exception(p_exc); } -#else - debug_unhandled_exception(p_exc); - GD_UNREACHABLE(); #endif } @@ -755,113 +751,137 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc) { namespace Marshal { -MonoBoolean type_is_generic_array(MonoReflectionType *p_reftype) { +#ifdef MONO_GLUE_ENABLED +#ifdef TOOLS_ENABLED +#define NO_GLUE_RET(m_ret) \ + { \ + if (!mono_cache.godot_api_cache_updated) return m_ret; \ + } +#else +#define NO_GLUE_RET(m_ret) \ + {} +#endif +#else +#define NO_GLUE_RET(m_ret) \ + { return m_ret; } +#endif + +bool type_is_generic_array(MonoReflectionType *p_reftype) { + NO_GLUE_RET(false); TypeIsGenericArray thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray); MonoException *exc = NULL; MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return res; + UNHANDLED_EXCEPTION(exc); + return (bool)res; } -MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype) { +bool type_is_generic_dictionary(MonoReflectionType *p_reftype) { + NO_GLUE_RET(false); TypeIsGenericDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary); MonoException *exc = NULL; MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return res; + UNHANDLED_EXCEPTION(exc); + return (bool)res; } void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) { ArrayGetElementType thunk = CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType); MonoException *exc = NULL; invoke_method_thunk(thunk, p_array_reftype, r_elem_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + UNHANDLED_EXCEPTION(exc); } void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { DictionaryGetKeyValueTypes thunk = CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes); MonoException *exc = NULL; invoke_method_thunk(thunk, p_dict_reftype, r_key_reftype, r_value_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + UNHANDLED_EXCEPTION(exc); } -MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) { +bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) { + NO_GLUE_RET(false); GenericIEnumerableIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType); MonoException *exc = NULL; MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return res; + UNHANDLED_EXCEPTION(exc); + return (bool)res; } -MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) { +bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) { + NO_GLUE_RET(false); GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType); MonoException *exc = NULL; MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return res; + UNHANDLED_EXCEPTION(exc); + return (bool)res; } -MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) { +bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) { + NO_GLUE_RET(false); GenericIEnumerableIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info); MonoException *exc = NULL; MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_elem_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return res; + UNHANDLED_EXCEPTION(exc); + return (bool)res; } -MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { +bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { + NO_GLUE_RET(false); GenericIDictionaryIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info); MonoException *exc = NULL; MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_key_reftype, r_value_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return res; + UNHANDLED_EXCEPTION(exc); + return (bool)res; } Array enumerable_to_array(MonoObject *p_enumerable) { + NO_GLUE_RET(Array()); Array result; EnumerableToArray thunk = CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray); MonoException *exc = NULL; invoke_method_thunk(thunk, p_enumerable, &result, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + UNHANDLED_EXCEPTION(exc); return result; } Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) { + NO_GLUE_RET(Dictionary()); Dictionary result; IDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary); MonoException *exc = NULL; invoke_method_thunk(thunk, p_idictionary, &result, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + UNHANDLED_EXCEPTION(exc); return result; } Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) { + NO_GLUE_RET(Dictionary()); Dictionary result; GenericIDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary); MonoException *exc = NULL; invoke_method_thunk(thunk, p_generic_idictionary, &result, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + UNHANDLED_EXCEPTION(exc); return result; } GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) { + NO_GLUE_RET(NULL); MakeGenericArrayType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType); MonoException *exc = NULL; MonoReflectionType *reftype = invoke_method_thunk(thunk, p_elem_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + UNHANDLED_EXCEPTION(exc); return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); } GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) { + NO_GLUE_RET(NULL); MakeGenericDictionaryType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType); MonoException *exc = NULL; MonoReflectionType *reftype = invoke_method_thunk(thunk, p_key_reftype, p_value_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + UNHANDLED_EXCEPTION(exc); return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); } } // namespace Marshal -// namespace Marshal - } // namespace GDMonoUtils -- cgit v1.2.3