2009-09-17 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / class.c
index ee5743c9ddbd40999174500999bb8bf5ead32b0e..06bac2ec1f1593f681ceb42db45efa4b61596749 100644 (file)
@@ -2568,6 +2568,24 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
                interface_offsets_full [i] = -1;
        }
 
+       for (k = class->parent; k ; k = k->parent) {
+               ifaces = mono_class_get_implemented_interfaces (k);
+               if (ifaces) {
+                       for (i = 0; i < ifaces->len; ++i) {
+                               int io;
+                               ic = g_ptr_array_index (ifaces, i);
+                               
+                               /*Force the sharing of interface offsets between parent and subtypes.*/
+                               io = mono_class_interface_offset (k, ic);
+                               g_assert (io >= 0);
+                               interfaces_full [ic->interface_id] = ic;
+                               interface_offsets_full [ic->interface_id] = io;
+                       }
+                       g_ptr_array_free (ifaces, TRUE);
+               }
+       }
+
+
        ifaces = mono_class_get_implemented_interfaces (class);
        if (ifaces) {
                for (i = 0; i < ifaces->len; ++i) {
@@ -2581,25 +2599,6 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
                g_ptr_array_free (ifaces, TRUE);
        }
 
-       for (k = class->parent; k ; k = k->parent) {
-               ifaces = mono_class_get_implemented_interfaces (k);
-               if (ifaces) {
-                       for (i = 0; i < ifaces->len; ++i) {
-                               ic = g_ptr_array_index (ifaces, i);
-
-                               if (interface_offsets_full [ic->interface_id] == -1) {
-                                       int io = mono_class_interface_offset (k, ic);
-
-                                       g_assert (io >= 0);
-
-                                       interfaces_full [ic->interface_id] = ic;
-                                       interface_offsets_full [ic->interface_id] = io;
-                               }
-                       }
-                       g_ptr_array_free (ifaces, TRUE);
-               }
-       }
-
        if (MONO_CLASS_IS_INTERFACE (class)) {
                interfaces_full [class->interface_id] = class;
                interface_offsets_full [class->interface_id] = cur_slot;
@@ -2795,9 +2794,11 @@ mono_class_setup_vtable (MonoClass *class)
 #define DEBUG_INTERFACE_VTABLE_CODE 0
 #define TRACE_INTERFACE_VTABLE_CODE 0
 #define VERIFY_INTERFACE_VTABLE_CODE 0
+#define VTABLE_SELECTOR (1)
 
 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
+       if (!(VTABLE_SELECTOR)) break; \
        stmt;\
 } while (0)
 #else
@@ -2806,6 +2807,7 @@ mono_class_setup_vtable (MonoClass *class)
 
 #if TRACE_INTERFACE_VTABLE_CODE
 #define TRACE_INTERFACE_VTABLE(stmt) do {\
+       if (!(VTABLE_SELECTOR)) break; \
        stmt;\
 } while (0)
 #else
@@ -2814,6 +2816,7 @@ mono_class_setup_vtable (MonoClass *class)
 
 #if VERIFY_INTERFACE_VTABLE_CODE
 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
+       if (!(VTABLE_SELECTOR)) break; \
        stmt;\
 } while (0)
 #else
@@ -3101,10 +3104,9 @@ print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, Mono
 }
 
 static gboolean
-verify_class_overrides (MonoClass *class, GPtrArray *ifaces, MonoMethod **overrides, int onum)
+verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
 {
        int i;
-       gboolean found;
 
        for (i = 0; i < onum; ++i) {
                MonoMethod *decl = overrides [i * 2];
@@ -3124,38 +3126,14 @@ verify_class_overrides (MonoClass *class, GPtrArray *ifaces, MonoMethod **overri
                }
 
                if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
-                               if (body->flags & METHOD_ATTRIBUTE_STATIC)
-                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
-                               else
-                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
-                               return FALSE;
-                       }
-                       
-               found = FALSE;
-               /*We can't use mono_class_is_assignable_from since it requires the class to be fully initialized*/
-               if (ifaces) {
-                       int j;
-                       for (j = 0; j < ifaces->len; j++) {
-                               MonoClass *ic = g_ptr_array_index (ifaces, j);
-                               if (decl->klass == ic) {
-                                       found = TRUE;
-                                       break;
-                               }
-                       }
-               }
-
-               if (!found) {
-                       MonoClass *parent = class;
-                       while (parent) {
-                               if (decl->klass == parent) {
-                                       found = TRUE;
-                                       break;
-                               }
-                               parent = parent->parent;
-                       }
+                       if (body->flags & METHOD_ATTRIBUTE_STATIC)
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
+                       else
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
+                       return FALSE;
                }
 
-               if (!found) {
+               if (!mono_class_is_assignable_from_slow (decl->klass, class)) {
                        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;
                }
@@ -3183,13 +3161,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
        if (class->vtable)
                return;
 
-       ifaces = mono_class_get_implemented_interfaces (class);
-
-       if (overrides && !verify_class_overrides (class, ifaces, overrides, onum)) {
-               if (ifaces)
-                       g_ptr_array_free (ifaces, TRUE);
+       if (overrides && !verify_class_overrides (class, overrides, onum))
                return;
-       }
+
+       ifaces = mono_class_get_implemented_interfaces (class);
 
        if (ifaces) {
                for (i = 0; i < ifaces->len; i++) {
@@ -3468,6 +3443,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                cm->slot = slot;
                }
 
+               /*Non final newslot methods must be given a non-interface vtable slot*/
+               if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
+                       cm->slot = -1;
+
                if (cm->slot < 0)
                        cm->slot = cur_slot++;
 
@@ -3844,6 +3823,16 @@ mono_class_init (MonoClass *class)
 
        class->init_pending = 1;
 
+       if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
+               MonoClass *element_class = class->element_class;
+               if (!element_class->inited) 
+                       mono_class_init (element_class);
+               if (element_class->exception_type != MONO_EXCEPTION_NONE) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       goto fail;
+               }
+       }
+
        /* CAS - SecurityAction.InheritanceDemand */
        if (mono_is_security_manager_active () && class->parent && (class->parent->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) {
                mono_secman_inheritancedemand_class (class, class->parent);
@@ -3945,8 +3934,10 @@ mono_class_init (MonoClass *class)
                class->has_cctor = gklass->has_cctor;
 
                mono_class_setup_vtable (gklass);
-               if (gklass->exception_type)
+               if (gklass->exception_type) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
                        goto fail;
+               }
 
                class->vtable_size = gklass->vtable_size;
        } else {
@@ -4034,12 +4025,20 @@ mono_class_init (MonoClass *class)
                if (class->parent) {
                        /* This will compute class->parent->vtable_size for some classes */
                        mono_class_init (class->parent);
-                       if (class->parent->exception_type || mono_loader_get_last_error ())
+                       if (class->parent->exception_type) {
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                               goto fail;
+                       }
+                       if (mono_loader_get_last_error ())
                                goto fail;
                        if (!class->parent->vtable_size) {
                                /* FIXME: Get rid of this somehow */
                                mono_class_setup_vtable (class->parent);
-                               if (class->parent->exception_type || mono_loader_get_last_error ())
+                               if (class->parent->exception_type) {
+                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                                       goto fail;
+                               }
+                               if (mono_loader_get_last_error ())
                                        goto fail;
                        }
                        setup_interface_offsets (class, class->parent->vtable_size);
@@ -5689,9 +5688,8 @@ mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *co
        if (!type) {
                char *name = mono_class_name_from_token (image, type_token);
                char *assembly = mono_assembly_name_from_token (image, type_token);
-               if (inflated)
-                       mono_metadata_free_type (type);
                mono_loader_set_error_type_load (name, assembly);
+               return NULL;
        }
 
        if (inflated) {
@@ -6256,6 +6254,67 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
        return mono_class_has_parent (oklass, klass);
 }      
 
+/*Check if @candidate implements the interface @target*/
+static gboolean
+mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
+{
+       int i;
+
+       do {
+               if (candidate == target)
+                       return TRUE;
+
+               /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
+               if (candidate->image->dynamic && !candidate->wastypebuilder) {
+                       MonoReflectionTypeBuilder *tb = candidate->reflection_info;
+                       int j;
+                       if (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);
+                                       if (iface_class == target || mono_class_implement_interface_slow (target, iface_class))
+                                               return TRUE;
+                               }
+                       }
+               } else {
+                       /*setup_interfaces don't mono_class_init anything*/
+                       mono_class_setup_interfaces (candidate);
+                       for (i = 0; i < candidate->interface_count; ++i) {
+                               if (candidate->interfaces [i] == target || mono_class_implement_interface_slow (target, candidate->interfaces [i]))
+                                       return TRUE;
+                       }
+               }
+               candidate = candidate->parent;
+       } while (candidate);
+
+       return FALSE;
+}
+
+/*
+ * Check if @oklass can be assigned to @klass.
+ * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
+ */
+gboolean
+mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
+{
+       if (candidate == target)
+               return TRUE;
+       if (target == mono_defaults.object_class)
+               return TRUE;
+
+       /*setup_supertypes don't mono_class_init anything */
+       mono_class_setup_supertypes (candidate);
+       mono_class_setup_supertypes (target);
+
+       if (mono_class_has_parent (candidate, target))
+               return TRUE;
+
+       /*If target is not an interface there is no need to check them.*/
+       if (!MONO_CLASS_IS_INTERFACE (target))
+                       return FALSE;
+       return mono_class_implement_interface_slow (target, candidate);
+}
+
 /**
  * mono_class_get_cctor:
  * @klass: A MonoClass pointer
@@ -7733,6 +7792,10 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass)
        if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
                return FALSE;
 
+       /*Non nested type with nested visibility. We just fail it.*/
+       if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
+               return FALSE;
+
        switch (access_level) {
        case TYPE_ATTRIBUTE_NOT_PUBLIC:
                return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);