Initialize klass->has_finalizer lazily. This allows us to remove the find_method_in_m...
authorZoltan Varga <vargaz@gmail.com>
Fri, 21 Jan 2011 20:51:26 +0000 (21:51 +0100)
committerZoltan Varga <vargaz@gmail.com>
Fri, 21 Jan 2011 20:52:54 +0000 (21:52 +0100)
mono/metadata/class-internals.h
mono/metadata/class.c
mono/metadata/object.c
mono/metadata/reflection.c

index 710891c2ec1e7d80f67f9286ec154387c529c64d..d9e5bcf2cc3b3f93d381248090d5ca0480ee811c 100644 (file)
@@ -350,6 +350,8 @@ struct _MonoClass {
        guint simd_type : 1; /* class is a simd intrinsic type */
        guint is_generic : 1; /* class is a generic type definition */
        guint is_inflated : 1; /* class is a generic instance */
+       /* next byte */
+       guint has_finalize_inited    : 1; /* has_finalize is initialized */
 
        guint8     exception_type;      /* MONO_EXCEPTION_* */
 
@@ -1297,4 +1299,7 @@ mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter) MONO_INTERNAL;
 gboolean
 mono_class_check_vtable_constraints (MonoClass *class, GList *in_setup) MONO_INTERNAL;
 
+gboolean
+mono_class_has_finalizer (MonoClass *klass) MONO_INTERNAL;
+
 #endif /* __MONO_METADATA_CLASS_INTERBALS_H__ */
index 999bcb0328b4589c2bf2a68bce20d09a4f3d585d..e00aace953a8ac94ba659c707fb2f64db57c41de 100644 (file)
@@ -4718,6 +4718,7 @@ mono_class_init (MonoClass *class)
                /* AOT case */
                class->vtable_size = cached_info.vtable_size;
                class->has_finalize = cached_info.has_finalize;
+               class->has_finalize_inited = TRUE;
                class->ghcimpl = cached_info.ghcimpl;
                class->has_cctor = cached_info.has_cctor;
        } else if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) {
@@ -4735,12 +4736,14 @@ mono_class_init (MonoClass *class)
                } else {
                        class->vtable_size = szarray_vtable_size[slot];
                }
+               class->has_finalize_inited = TRUE;
        } else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) {
                MonoClass *gklass = class->generic_class->container_class;
 
                /* Generic instance case */
                class->ghcimpl = gklass->ghcimpl;
-               class->has_finalize = gklass->has_finalize;
+               class->has_finalize = mono_class_has_finalizer (gklass);
+               class->has_finalize_inited = TRUE;
                class->has_cctor = gklass->has_cctor;
 
                mono_class_setup_vtable (gklass);
@@ -4765,45 +4768,6 @@ mono_class_init (MonoClass *class)
                }
                */
 
-               /* Interfaces and valuetypes are not supposed to have finalizers */
-               if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
-                       MonoMethod *cmethod = NULL;
-
-                       if (class->parent && class->parent->has_finalize) {
-                               class->has_finalize = 1;
-                       } else {
-                               if (class->type_token) {
-                                       cmethod = find_method_in_metadata (class, "Finalize", 0, METHOD_ATTRIBUTE_VIRTUAL);
-                               } else if (class->parent) {
-                                       /* FIXME: Optimize this */
-                                       mono_class_setup_vtable (class);
-                                       if (class->exception_type || mono_loader_get_last_error ())
-                                               goto leave;
-                                       cmethod = class->vtable [finalize_slot];
-                               }
-
-                               if (cmethod) {
-                                       /* Check that this is really the finalizer method */
-                                       mono_class_setup_vtable (class);
-                                       if (class->exception_type || mono_loader_get_last_error ())
-                                               goto leave;
-
-                                       g_assert (class->vtable_size > finalize_slot);
-
-                                       class->has_finalize = 0;
-                                       if (class->parent) { 
-                                               cmethod = class->vtable [finalize_slot];
-                                               g_assert (cmethod);
-                                               if (cmethod->is_inflated)
-                                                       cmethod = ((MonoMethodInflated*)cmethod)->declaring;
-                                               if (cmethod != default_finalize) {
-                                                       class->has_finalize = 1;
-                                               }
-                                       }
-                               }
-                       }
-               }
-
                /* C# doesn't allow interfaces to have cctors */
                if (!MONO_CLASS_IS_INTERFACE (class) || class->image != mono_defaults.corlib) {
                        MonoMethod *cmethod = NULL;
@@ -4887,6 +4851,66 @@ mono_class_init (MonoClass *class)
        return class->exception_type == MONO_EXCEPTION_NONE;
 }
 
+/*
+ * mono_class_has_finalizer:
+ *
+ *   Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
+ * process.
+ */
+gboolean
+mono_class_has_finalizer (MonoClass *klass)
+{
+       if (!klass->has_finalize_inited) {
+               MonoClass *class = klass;
+
+               mono_loader_lock ();
+
+               /* Interfaces and valuetypes are not supposed to have finalizers */
+               if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
+                       MonoMethod *cmethod = NULL;
+
+                       if (class->parent && class->parent->has_finalize) {
+                               class->has_finalize = 1;
+                       } else {
+                               if (class->parent) {
+                                       /*
+                                        * Can't search in metadata for a method named Finalize, because that
+                                        * ignores overrides.
+                                        */
+                                       mono_class_setup_vtable (class);
+                                       if (class->exception_type || mono_loader_get_last_error ())
+                                               goto leave;
+                                       cmethod = class->vtable [finalize_slot];
+                               }
+
+                               if (cmethod) {
+                                       g_assert (class->vtable_size > finalize_slot);
+
+                                       class->has_finalize = 0;
+                                       if (class->parent) { 
+                                               if (cmethod->is_inflated)
+                                                       cmethod = ((MonoMethodInflated*)cmethod)->declaring;
+                                               if (cmethod != default_finalize) {
+                                                       class->has_finalize = 1;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               mono_memory_barrier ();
+               klass->has_finalize_inited = TRUE;
+
+               mono_loader_unlock ();
+       }
+
+       return klass->has_finalize;
+
+ leave:
+       mono_loader_unlock ();
+       return FALSE;
+}
+
 gboolean
 mono_is_corlib_image (MonoImage *image)
 {
index 565285f5b14be303b2c164f5abbcdf6e19de70c4..26bd8efffdc1386393b827665ffe447cfeb9371a 100644 (file)
@@ -1851,6 +1851,9 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
        if (class->generic_class && !class->vtable)
                mono_class_check_vtable_constraints (class, NULL);
 
+       /* Initialize klass->has_finalize */
+       mono_class_has_finalizer (class);
+
        if (class->exception_type) {
                mono_domain_unlock (domain);
                mono_loader_unlock ();
index 255bf9671c775ac05357b837503a7bdeb1f5e81d..e267172ccd9b02da65b97865a4610cb782a1dd2b 100644 (file)
@@ -11238,6 +11238,7 @@ mono_reflection_create_runtime_class (MonoReflectionTypeBuilder *tb)
        klass->flags = tb->attrs;
        klass->has_cctor = 1;
        klass->has_finalize = 1;
+       klass->has_finalize_inited = 1;
 
        /* fool mono_class_setup_parent */
        klass->supertypes = NULL;