Example #1
0
/* 
 * actually, we might want to queue the finalize requests in a separate thread,
 * but we need to be careful about the execution domain of the thread...
 */
void
mono_gc_run_finalize (void *obj, void *data)
{
	MonoObject *exc = NULL;
	MonoObject *o;
#ifndef HAVE_SGEN_GC
	MonoObject *o2;
#endif
	MonoMethod* finalizer = NULL;
	MonoDomain *caller_domain = mono_domain_get ();
	MonoDomain *domain;
	RuntimeInvokeFunction runtime_invoke;
	GSList *l, *refs = NULL;

	o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));

	if (suspend_finalizers)
		return;

	domain = o->vtable->domain;

#ifndef HAVE_SGEN_GC
	mono_domain_finalizers_lock (domain);

	o2 = g_hash_table_lookup (domain->finalizable_objects_hash, o);

	refs = mono_gc_remove_weak_track_object (domain, o);

	mono_domain_finalizers_unlock (domain);

	if (!o2)
		/* Already finalized somehow */
		return;
#endif

	if (refs) {
		/*
		 * Support for GCHandles of type WeakTrackResurrection:
		 *
		 *   Its not exactly clear how these are supposed to work, or how their
		 * semantics can be implemented. We only implement one crucial thing:
		 * these handles are only cleared after the finalizer has ran.
		 */
		for (l = refs; l; l = l->next) {
			guint32 gchandle = GPOINTER_TO_UINT (l->data);

			mono_gchandle_set_target (gchandle, o);
		}

		g_slist_free (refs);
	}
		
	/* make sure the finalizer is not called again if the object is resurrected */
	object_register_finalizer (obj, NULL);

	if (o->vtable->klass == mono_defaults.internal_thread_class) {
		MonoInternalThread *t = (MonoInternalThread*)o;

		if (mono_gc_is_finalizer_internal_thread (t))
			/* Avoid finalizing ourselves */
			return;

		if (t->threadpool_thread && finalizing_root_domain) {
			/* Don't finalize threadpool threads when
			   shutting down - they're finalized when the
			   threadpool shuts down. */
			add_thread_to_finalize (t);
			return;
		}
	}

	if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
		/*
		 * These can't be finalized during unloading/shutdown, since that would
		 * free the native code which can still be referenced by other
		 * finalizers.
		 * FIXME: This is not perfect, objects dying at the same time as 
		 * dynamic methods can still reference them even when !shutdown.
		 */
		return;
	}

	if (mono_runtime_get_no_exec ())
		return;

	/* speedup later... and use a timeout */
	/* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */

	/* Use _internal here, since this thread can enter a doomed appdomain */
	mono_domain_set_internal (mono_object_domain (o));

	/* delegates that have a native function pointer allocated are
	 * registered for finalization, but they don't have a Finalize
	 * method, because in most cases it's not needed and it's just a waste.
	 */
	if (o->vtable->klass->delegate) {
		MonoDelegate* del = (MonoDelegate*)o;
		if (del->delegate_trampoline)
			mono_delegate_free_ftnptr ((MonoDelegate*)o);
		mono_domain_set_internal (caller_domain);
		return;
	}

	finalizer = mono_class_get_finalizer (o->vtable->klass);

#ifndef DISABLE_COM
	/* If object has a CCW but has no finalizer, it was only
	 * registered for finalization in order to free the CCW.
	 * Else it needs the regular finalizer run.
	 * FIXME: what to do about ressurection and suppression
	 * of finalizer on object with CCW.
	 */
	if (mono_marshal_free_ccw (o) && !finalizer) {
		mono_domain_set_internal (caller_domain);
		return;
	}
#endif

	/* 
	 * To avoid the locking plus the other overhead of mono_runtime_invoke (),
	 * create and precompile a wrapper which calls the finalize method using
	 * a CALLVIRT.
	 */
	if (!domain->finalize_runtime_invoke) {
		MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);

		domain->finalize_runtime_invoke = mono_compile_method (invoke);
	}

	runtime_invoke = domain->finalize_runtime_invoke;

	mono_runtime_class_init (o->vtable);

	runtime_invoke (o, NULL, &exc, NULL);

	if (exc) {
		/* fixme: do something useful */
	}

	mono_domain_set_internal (caller_domain);
}
Example #2
0
File: gc.c Project: Numpsy/mono
/* 
 * actually, we might want to queue the finalize requests in a separate thread,
 * but we need to be careful about the execution domain of the thread...
 */
void
mono_gc_run_finalize (void *obj, void *data)
{
	MonoError error;
	MonoObject *exc = NULL;
	MonoObject *o;
#ifndef HAVE_SGEN_GC
	MonoObject *o2;
#endif
	MonoMethod* finalizer = NULL;
	MonoDomain *caller_domain = mono_domain_get ();
	MonoDomain *domain;
	RuntimeInvokeFunction runtime_invoke;

	// This function is called from the innards of the GC, so our best alternative for now is to do polling here
	mono_threads_safepoint ();

	o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));

	if (mono_do_not_finalize) {
		if (!mono_do_not_finalize_class_names)
			return;

		size_t namespace_len = strlen (o->vtable->klass->name_space);
		for (int i = 0; mono_do_not_finalize_class_names [i]; ++i) {
			const char *name = mono_do_not_finalize_class_names [i];
			if (strncmp (name, o->vtable->klass->name_space, namespace_len))
				break;
			if (name [namespace_len] != '.')
				break;
			if (strcmp (name + namespace_len + 1, o->vtable->klass->name))
				break;
			return;
		}
	}

	if (log_finalizers)
		g_log ("mono-gc-finalizers", G_LOG_LEVEL_DEBUG, "<%s at %p> Starting finalizer checks.", o->vtable->klass->name, o);

	if (suspend_finalizers)
		return;

	domain = o->vtable->domain;

#ifndef HAVE_SGEN_GC
	mono_domain_finalizers_lock (domain);

	o2 = (MonoObject *)g_hash_table_lookup (domain->finalizable_objects_hash, o);

	mono_domain_finalizers_unlock (domain);

	if (!o2)
		/* Already finalized somehow */
		return;
#endif

	/* make sure the finalizer is not called again if the object is resurrected */
	object_register_finalizer ((MonoObject *)obj, NULL);

	if (log_finalizers)
		g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Registered finalizer as processed.", o->vtable->klass->name, o);

	if (o->vtable->klass == mono_defaults.internal_thread_class) {
		MonoInternalThread *t = (MonoInternalThread*)o;

		if (mono_gc_is_finalizer_internal_thread (t))
			/* Avoid finalizing ourselves */
			return;

		if (t->threadpool_thread && finalizing_root_domain) {
			/* Don't finalize threadpool threads when
			   shutting down - they're finalized when the
			   threadpool shuts down. */
			if (!add_thread_to_finalize (t, &error))
				goto unhandled_error;
			return;
		}
	}

	if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
		/*
		 * These can't be finalized during unloading/shutdown, since that would
		 * free the native code which can still be referenced by other
		 * finalizers.
		 * FIXME: This is not perfect, objects dying at the same time as 
		 * dynamic methods can still reference them even when !shutdown.
		 */
		return;
	}

	if (mono_runtime_get_no_exec ())
		return;

	/* speedup later... and use a timeout */
	/* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */

	/* Use _internal here, since this thread can enter a doomed appdomain */
	mono_domain_set_internal (mono_object_domain (o));

	/* delegates that have a native function pointer allocated are
	 * registered for finalization, but they don't have a Finalize
	 * method, because in most cases it's not needed and it's just a waste.
	 */
	if (o->vtable->klass->delegate) {
		MonoDelegate* del = (MonoDelegate*)o;
		if (del->delegate_trampoline)
			mono_delegate_free_ftnptr ((MonoDelegate*)o);
		mono_domain_set_internal (caller_domain);
		return;
	}

	finalizer = mono_class_get_finalizer (o->vtable->klass);

	/* If object has a CCW but has no finalizer, it was only
	 * registered for finalization in order to free the CCW.
	 * Else it needs the regular finalizer run.
	 * FIXME: what to do about ressurection and suppression
	 * of finalizer on object with CCW.
	 */
	if (mono_marshal_free_ccw (o) && !finalizer) {
		mono_domain_set_internal (caller_domain);
		return;
	}

	/* 
	 * To avoid the locking plus the other overhead of mono_runtime_invoke_checked (),
	 * create and precompile a wrapper which calls the finalize method using
	 * a CALLVIRT.
	 */
	if (log_finalizers)
		g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o->vtable->klass->name, o);

	if (!domain->finalize_runtime_invoke) {
		MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);

		domain->finalize_runtime_invoke = mono_compile_method_checked (invoke, &error);
		mono_error_assert_ok (&error); /* expect this not to fail */
	}

	runtime_invoke = (RuntimeInvokeFunction)domain->finalize_runtime_invoke;

	mono_runtime_class_init_full (o->vtable, &error);
	if (!is_ok (&error))
		goto unhandled_error;

	if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
		MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
				o->vtable->klass->name_space, o->vtable->klass->name);
	}

	if (log_finalizers)
		g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Calling finalizer.", o->vtable->klass->name, o);

	runtime_invoke (o, NULL, &exc, NULL);

	if (log_finalizers)
		g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o->vtable->klass->name, o);

unhandled_error:
	if (!is_ok (&error))
		exc = (MonoObject*)mono_error_convert_to_exception (&error);
	if (exc)
		mono_thread_internal_unhandled_exception (exc);

	mono_domain_set_internal (caller_domain);
}