void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { #ifdef DEBUG_ENABLED CRASH_COND(p_ptr == NULL); #endif if (p_ptr->get_script_instance()) { CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance()); if (cs_instance) { if (!cs_instance->is_destructing_script_instance()) { cs_instance->mono_object_disposed(p_obj); p_ptr->set_script_instance(NULL); } return; } } void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); if (script_binding.inited) { Ref<MonoGCHandle> &gchandle = script_binding.gchandle; if (gchandle.is_valid()) { CSharpLanguage::release_script_gchandle(p_obj, gchandle); } } } }
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 the owner does not have a CSharpInstance... void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value(); Ref<MonoGCHandle> &gchandle = script_binding.gchandle; ERR_FAIL_COND_V(gchandle.is_null(), NULL); MonoObject *target = gchandle->get_target(); if (target) return target; CSharpLanguage::get_singleton()->release_script_gchandle(gchandle); // Create a new one #ifdef DEBUG_ENABLED CRASH_COND(script_binding.type_name == StringName()); CRASH_COND(script_binding.wrapper_class == 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); // Tie managed to unmanaged Reference *ref = Object::cast_to<Reference>(unmanaged); 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) ref->reference(); } return mono_object; } } return NULL; }
void _GodotSharp::_dispose_object(Object *p_object) { if (p_object->get_script_instance()) { CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_object->get_script_instance()); if (cs_instance) { cs_instance->mono_object_disposed(); return; } } // Unsafe refcount decrement. The managed instance also counts as a reference. // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object) if (Object::cast_to<Reference>(p_object)->unreference()) { memdelete(p_object); } }
void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { #ifdef DEBUG_ENABLED CRASH_COND(p_ptr == NULL); // This is only called with Reference derived classes CRASH_COND(!Object::cast_to<Reference>(p_ptr)); #endif Reference *ref = static_cast<Reference *>(p_ptr); if (ref->get_script_instance()) { CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance()); if (cs_instance) { if (!cs_instance->is_destructing_script_instance()) { bool delete_owner; bool remove_script_instance; cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance); if (delete_owner) { memdelete(ref); } else if (remove_script_instance) { ref->set_script_instance(NULL); } } return; } } // Unsafe refcount decrement. The managed instance also counts as a reference. // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object) if (ref->unreference()) { memdelete(ref); } else { void *data = ref->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); if (script_binding.inited) { Ref<MonoGCHandle> &gchandle = script_binding.gchandle; if (gchandle.is_valid()) { CSharpLanguage::release_script_gchandle(p_obj, gchandle); } } } } }
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(); } } // Only called if the owner does not have a CSharpInstance void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { return ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->value()->get_target(); } } return NULL; }
void _GodotSharp::queue_dispose(MonoObject *p_mono_object, Object *p_object) { if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) { _dispose_object(p_object); } else { #ifndef NO_THREADS queue_mutex->lock(); #endif // This is our last chance to invoke notification predelete (this is being called from the finalizer) // We must use the MonoObject* passed by the finalizer, because the weak GC handle target returns NULL at this point CSharpInstance *si = CAST_CSHARP_INSTANCE(p_object->get_script_instance()); if (si) { si->call_notification_no_check(p_mono_object, Object::NOTIFICATION_PREDELETE); } ENQUEUE_FOR_DISPOSAL(obj_delete_queue, p_object); #ifndef NO_THREADS queue_mutex->unlock(); #endif } }