Merge branch 'sgen-disable-gc'
[mono.git] / mono / metadata / class.c
index 75e42fabf19a50da83bf3442d5e86c956f2a4e92..8ce8fc9b277babd95bab604f8efe7fecf67cb748 100644 (file)
@@ -1217,11 +1217,6 @@ static gpointer
 mono_class_alloc (MonoClass *class, int size)
 {
        if (class->generic_class)
-               /*
-                * This should be freed in free_generic_class () in metadata.c.
-                * FIXME: It would be better to allocate this from the image set mempool, by
-                * adding an image_set field to MonoGenericClass.
-                */
                return mono_image_set_alloc (class->generic_class->owner, size);
        else
                return mono_image_alloc (class->image, size);
@@ -2397,6 +2392,16 @@ mono_unload_interface_ids (MonoBitSet *bitset)
        mono_loader_unlock ();
 }
 
+void
+mono_unload_interface_id (MonoClass *class)
+{
+       if (class->interface_id) {
+               mono_loader_lock ();
+               mono_bitset_clear (global_interface_bitset, class->interface_id);
+               mono_loader_unlock ();
+       }
+}
+
 /*
  * mono_get_unique_iid:
  * @class: interface
@@ -2427,16 +2432,18 @@ mono_get_unique_iid (MonoClass *class)
        }
        mono_bitset_set (global_interface_bitset, iid);
        /* set the bit also in the per-image set */
-       if (class->image->interface_bitset) {
-               if (iid >= mono_bitset_size (class->image->interface_bitset)) {
-                       MonoBitSet *new_set = mono_bitset_clone (class->image->interface_bitset, iid + 1);
-                       mono_bitset_free (class->image->interface_bitset);
-                       class->image->interface_bitset = new_set;
+       if (!class->generic_class) {
+               if (class->image->interface_bitset) {
+                       if (iid >= mono_bitset_size (class->image->interface_bitset)) {
+                               MonoBitSet *new_set = mono_bitset_clone (class->image->interface_bitset, iid + 1);
+                               mono_bitset_free (class->image->interface_bitset);
+                               class->image->interface_bitset = new_set;
+                       }
+               } else {
+                       class->image->interface_bitset = mono_bitset_new (iid + 1, 0);
                }
-       } else {
-               class->image->interface_bitset = mono_bitset_new (iid + 1, 0);
+               mono_bitset_set (class->image->interface_bitset, iid);
        }
-       mono_bitset_set (class->image->interface_bitset, iid);
 
 #ifndef MONO_SMALL_CONFIG
        if (mono_print_vtable) {
@@ -3530,6 +3537,18 @@ print_method_signatures (MonoMethod *im, MonoMethod *cm) {
 }
 
 #endif
+static gboolean
+is_wcf_hack_disabled (void)
+{
+       static gboolean disabled;
+       static gboolean inited = FALSE;
+       if (!inited) {
+               disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
+               inited = TRUE;
+       }
+       return disabled;
+}
+
 static gboolean
 check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty, gboolean security_enabled) {
        MonoMethodSignature *cmsig, *imsig;
@@ -3574,6 +3593,15 @@ check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *c
                if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
                        mono_security_core_clr_check_override (class, cm, im);
                TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
+               if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
+                       char *body_name = mono_method_full_name (cm, TRUE);
+                       char *decl_name = mono_method_full_name (im, TRUE);
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                       g_free (body_name);
+                       g_free (decl_name);
+                       return FALSE;
+               }
+
                return TRUE;
        } else {
                MonoClass *ic = im->klass;
@@ -3651,6 +3679,15 @@ check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *c
                        mono_security_core_clr_check_override (class, cm, im);
                
                TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
+               if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
+                       char *body_name = mono_method_full_name (cm, TRUE);
+                       char *decl_name = mono_method_full_name (im, TRUE);
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                       g_free (body_name);
+                       g_free (decl_name);
+                       return FALSE;
+               }
+               
                return TRUE;
        }
 }
@@ -3795,6 +3832,14 @@ print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, Mono
        }
 }
 
+static MonoMethod*
+mono_method_get_method_definition (MonoMethod *method)
+{
+       while (method->is_inflated)
+               method = ((MonoMethodInflated*)method)->declaring;
+       return method;
+}
+
 static gboolean
 verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
 {
@@ -3829,6 +3874,18 @@ verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
                        mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type"));
                        return FALSE;
                }
+
+               body = mono_method_get_method_definition (body);
+               decl = mono_method_get_method_definition (decl);
+
+               if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
+                       char *body_name = mono_method_full_name (body, TRUE);
+                       char *decl_name = mono_method_full_name (decl, TRUE);
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                       g_free (body_name);
+                       g_free (decl_name);
+                       return FALSE;
+               }
        }
        return TRUE;
 }
@@ -4208,6 +4265,15 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                if (slot == -1)
                                                        goto fail;
 
+                                               if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
+                                                       char *body_name = mono_method_full_name (cm, TRUE);
+                                                       char *decl_name = mono_method_full_name (m1, TRUE);
+                                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                                                       g_free (body_name);
+                                                       g_free (decl_name);
+                                                       goto fail;
+                                               }
+
                                                g_assert (cm->slot < max_vtsize);
                                                if (!override_map)
                                                        override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
@@ -4723,6 +4789,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) {
@@ -4740,12 +4807,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);
@@ -4770,45 +4839,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;
@@ -4892,6 +4922,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)
 {
@@ -5350,6 +5440,8 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        if (class->enumtype) {
                MonoType *enum_basetype = mono_class_find_enum_basetype (class);
                if (!enum_basetype) {
+                       /*set it to a default value as the whole runtime can't handle this to be null*/
+                       class->cast_class = class->element_class = mono_defaults.int32_class;
                        mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
                        mono_loader_unlock ();
                        mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
@@ -5418,14 +5510,16 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
 {
        MonoClass *klass, *gklass;
 
+       if (gclass->cached_class)
+               return gclass->cached_class;
+
        mono_loader_lock ();
        if (gclass->cached_class) {
                mono_loader_unlock ();
                return gclass->cached_class;
        }
 
-       gclass->cached_class = mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
-       klass = gclass->cached_class;
+       klass = mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
 
        gklass = gclass->container_class;
 
@@ -5464,7 +5558,14 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
         */
 
        if (gklass->parent) {
-               klass->parent = mono_class_inflate_generic_class (gklass->parent, mono_generic_class_get_context (gclass));
+               MonoError error;
+               klass->parent = mono_class_inflate_generic_class_checked (gklass->parent, mono_generic_class_get_context (gclass), &error);
+               if (!mono_error_ok (&error)) {
+                       /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
+                       klass->parent = mono_defaults.object_class;
+                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_error_cleanup (&error);
+               }
        }
 
        if (klass->parent)
@@ -5492,6 +5593,9 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
                }
        }
 
+       mono_memory_barrier ();
+       gclass->cached_class = klass;
+
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
 
        inflated_classes ++;
@@ -5593,40 +5697,65 @@ make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is
 }
 
 #define FAST_CACHE_SIZE 16
-static MonoClass *var_cache_fast [FAST_CACHE_SIZE];
-static MonoClass *mvar_cache_fast [FAST_CACHE_SIZE];
-static GHashTable *var_cache_slow;
-static GHashTable *mvar_cache_slow;
 
 static MonoClass *
 get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
 {
        int n = mono_generic_param_num (param);
+       MonoImage *image = param->image;
        GHashTable *ht;
 
-       if (n < FAST_CACHE_SIZE)
-               return (is_mvar ? mvar_cache_fast : var_cache_fast) [n];
-       ht = is_mvar ? mvar_cache_slow : var_cache_slow;
-       return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
+       g_assert (image);
+
+       if (n < FAST_CACHE_SIZE) {
+               if (is_mvar)
+                       return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
+               else
+                       return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
+       } else {
+               ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
+               return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
+       }
 }
 
+/*
+ * LOCKING: Acquires the loader lock.
+ */
 static void
 set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
 {
        int n = mono_generic_param_num (param);
+       MonoImage *image = param->image;
        GHashTable *ht;
 
+       g_assert (image);
+
        if (n < FAST_CACHE_SIZE) {
-               (is_mvar ? mvar_cache_fast : var_cache_fast) [n] = klass;
+               if (is_mvar) {
+                       /* No locking needed */
+                       if (!image->mvar_cache_fast)
+                               image->mvar_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
+                       image->mvar_cache_fast [n] = klass;
+               } else {
+                       if (!image->var_cache_fast)
+                               image->var_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
+                       image->var_cache_fast [n] = klass;
+               }
                return;
        }
-       ht = is_mvar ? mvar_cache_slow : var_cache_slow;
+       ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
        if (!ht) {
-               ht = g_hash_table_new (NULL, NULL);
-               if (is_mvar)
-                       mvar_cache_slow = ht;
-               else
-                       var_cache_slow = ht;
+               mono_loader_lock ();
+               ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
+               if (!ht) {
+                       ht = g_hash_table_new (NULL, NULL);
+                       mono_memory_barrier ();
+                       if (is_mvar)
+                               image->mvar_cache_slow = ht;
+                       else
+                               image->var_cache_slow = ht;
+               }
+               mono_loader_unlock ();
        }
 
        g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
@@ -7016,7 +7145,8 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
                name = buf;
        }
 
-       if (get_class_from_name) {
+       /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
+       if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
                gboolean res = get_class_from_name (image, name_space, name, &class);
                if (res) {
                        if (!class)
@@ -7170,7 +7300,7 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass)
        MonoGenericContainer *container = klass_gtd->generic_container;
 
        /*Viable candidates are instances of the same generic interface*/
-       if (mono_class_get_generic_type_definition (oklass) != klass_gtd)
+       if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
                return FALSE;
 
        klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
@@ -7310,7 +7440,7 @@ mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
        MonoGenericContainer *container = klass_gtd->generic_container;
 
        /*Viable candidates are instances of the same generic interface*/
-       if (mono_class_get_generic_type_definition (oklass) != klass_gtd)
+       if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
                return FALSE;
 
        klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
@@ -7364,7 +7494,12 @@ mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
                        if (tb && tb->interfaces) {
                                for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
                                        MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
-                                       MonoClass *iface_class = mono_class_from_mono_type (iface->type);
+                                       MonoClass *iface_class;
+
+                                       /* we can't realize the type here since it can do pretty much anything. */
+                                       if (!iface->type)
+                                               continue;
+                                       iface_class = mono_class_from_mono_type (iface->type);
                                        if (iface_class == target)
                                                return TRUE;
                                        if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
@@ -7473,7 +7608,7 @@ mono_class_get_finalizer (MonoClass *klass)
 
        if (!klass->inited)
                mono_class_init (klass);
-       if (!klass->has_finalize)
+       if (!mono_class_has_finalizer (klass))
                return NULL;
 
        if (mono_class_get_cached_class_info (klass, &cached_info))
@@ -8046,7 +8181,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                        method++;
                }
                while (method < &klass->methods [klass->method.count]) {
-                       if (((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
+                       if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
                                break;
                        method ++;
                }
@@ -8958,6 +9093,9 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass)
 {
        int access_level;
 
+       if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
+               return TRUE;
+
        if (access_klass->element_class && !access_klass->enumtype)
                access_klass = access_klass->element_class;
 
@@ -9017,6 +9155,9 @@ static gboolean
 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
 {
        MonoClass *member_generic_def;
+       if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
+               return TRUE;
+
        if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
                                        access_klass->generic_container) && 
                        (member_generic_def = get_generic_definition_class (member_klass))) {