| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | /*  gd_mono_internals.cpp                                                */ | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							|  |  |  | /*                      https://godotengine.org                          */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2020-01-01 11:16:22 +01:00
										 |  |  | /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */ | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* 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.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | #include "gd_mono_internals.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "../csharp_script.h"
 | 
					
						
							|  |  |  | #include "../mono_gc_handle.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-26 21:03:42 +02:00
										 |  |  | #include "../utils/macros.h"
 | 
					
						
							|  |  |  | #include "../utils/thread_local.h"
 | 
					
						
							| 
									
										
										
										
											2019-02-04 20:39:02 +01:00
										 |  |  | #include "gd_mono_class.h"
 | 
					
						
							|  |  |  | #include "gd_mono_marshal.h"
 | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | #include "gd_mono_utils.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 21:03:42 +02:00
										 |  |  | #include <mono/metadata/exception.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | namespace GDMonoInternals { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// This method should not fail
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CRASH_COND(!unmanaged); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-09 03:39:45 +02:00
										 |  |  | 	// All mono objects created from the managed world (e.g.: 'new Player()')
 | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | 	// need to have a CSharpScript in order for their methods to be callable from the unmanaged side
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Reference *ref = Object::cast_to<Reference>(unmanaged); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	GDMonoClass *klass = GDMonoUtils::get_object_class(managed); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CRASH_COND(!klass); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 20:39:02 +01:00
										 |  |  | 	GDMonoClass *native = GDMonoUtils::get_class_native_base(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; | 
					
						
							| 
									
										
										
										
											2019-12-25 19:33:59 +01:00
										 |  |  | 		script_binding.gchandle = ref ? MonoGCHandle::create_weak(managed) : MonoGCHandle::create_strong(managed); | 
					
						
							| 
									
										
										
										
											2019-07-03 09:44:53 +02:00
										 |  |  | 		script_binding.owner = unmanaged; | 
					
						
							| 
									
										
										
										
											2019-02-04 20:39:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-03 09:44:53 +02:00
										 |  |  | 		if (ref) { | 
					
						
							| 
									
										
										
										
											2019-02-04 20:39:02 +01:00
										 |  |  | 			// 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)
 | 
					
						
							| 
									
										
										
										
											2019-12-25 19:33:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// May not me referenced yet, so we must use init_ref() instead of reference()
 | 
					
						
							| 
									
										
										
										
											2020-01-13 21:00:07 +01:00
										 |  |  | 			if (ref->init_ref()) { | 
					
						
							|  |  |  | 				CSharpLanguage::get_singleton()->post_unsafe_reference(ref); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-02-04 20:39:02 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// 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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 21:10:08 +01:00
										 |  |  | 	Ref<MonoGCHandle> gchandle = ref ? MonoGCHandle::create_weak(managed) : MonoGCHandle::create_strong(managed); | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 20:39:02 +01:00
										 |  |  | 	Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native); | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	CRASH_COND(script.is_null()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ScriptInstance *si = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-13 16:03:10 -03:00
										 |  |  | 	unmanaged->set_script_and_instance(script, si); | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-06-26 21:03:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | void unhandled_exception(MonoException *p_exc) { | 
					
						
							|  |  |  | 	mono_unhandled_exception((MonoObject *)p_exc); // prints the exception as well
 | 
					
						
							| 
									
										
										
										
											2019-07-24 23:13:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (GDMono::get_singleton()->get_unhandled_exception_policy() == GDMono::POLICY_TERMINATE_APP) { | 
					
						
							|  |  |  | 		// Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders
 | 
					
						
							|  |  |  | 		GDMono::unhandled_exception_hook((MonoObject *)p_exc, NULL); | 
					
						
							|  |  |  | 		GD_UNREACHABLE(); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | #ifdef DEBUG_ENABLED
 | 
					
						
							|  |  |  | 		GDMonoUtils::debug_send_unhandled_exception_error((MonoException *)p_exc); | 
					
						
							|  |  |  | 		if (ScriptDebugger::get_singleton()) | 
					
						
							|  |  |  | 			ScriptDebugger::get_singleton()->idle_poll(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-26 21:03:42 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-06 21:36:34 +01:00
										 |  |  | } // namespace GDMonoInternals
 |