Add a new 'MONO_DEBUGGER_EVENT_TRAMPOLINE' notification for the debugger which also...
[mono.git] / mono / metadata / class.c
index 41fc3291732d04d7596bc9b860e6585245d6aa7b..4521e49c4aadaf0fbdc2b37e60662a806fff898e 100644 (file)
@@ -39,6 +39,7 @@
 #include <mono/metadata/verify-internals.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-string.h>
 
 MonoStats mono_stats;
 
@@ -1071,7 +1072,7 @@ mono_class_setup_fields (MonoClass *class)
        gboolean explicit_size;
        MonoClassField *field;
        MonoGenericContainer *container = NULL;
-       MonoClass *gklass = NULL;
+       MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
 
        if (class->size_inited)
                return;
@@ -1086,12 +1087,16 @@ mono_class_setup_fields (MonoClass *class)
                return;
        }
 
-       if (class->generic_class) {
-               MonoClass *gklass = class->generic_class->container_class;
-               mono_class_setup_fields (gklass);
-               top = gklass->field.count;
-               class->field.first = gklass->field.first;
-               class->field.count = gklass->field.count;
+       if (gtd) {
+               mono_class_setup_fields (gtd);
+               if (gtd->exception_type) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       return;
+               }
+
+               top = gtd->field.count;
+               class->field.first = gtd->field.first;
+               class->field.count = gtd->field.count;
        }
 
        class->instance_size = 0;
@@ -1149,17 +1154,9 @@ mono_class_setup_fields (MonoClass *class)
 
        if (class->generic_container) {
                container = class->generic_container;
-       } else if (class->generic_class) {
-               gklass = class->generic_class->container_class;
-               container = gklass->generic_container;
+       } else if (gtd) {
+               container = gtd->generic_container;
                g_assert (container);
-
-               mono_class_setup_fields (gklass);
-
-               if (gklass->exception_type) {
-                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
-                       return;
-               }
        }
 
        /*
@@ -1171,8 +1168,8 @@ mono_class_setup_fields (MonoClass *class)
 
                field->parent = class;
 
-               if (class->generic_class) {
-                       MonoClassField *gfield = &gklass->fields [i];
+               if (gtd) {
+                       MonoClassField *gfield = &gtd->fields [i];
 
                        field->name = mono_field_get_name (gfield);
                        /*This memory must come from the image mempool as we don't have a chance to free it.*/
@@ -2475,6 +2472,37 @@ find_array_interface (MonoClass *klass, const char *name)
        return -1;
 }
 
+/*
+ * Return the number of virtual methods.
+ * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
+ * FIXME It would be nice if this information could be cached somewhere.
+ */
+static int
+count_virtual_methods (MonoClass *class)
+{
+       int i, count = 0;
+       guint32 flags;
+       class = mono_class_get_generic_type_definition (class); /*We can find this information by looking at the GTD*/
+
+       if (class->methods || !MONO_CLASS_HAS_STATIC_METADATA (class)) {
+               mono_class_setup_methods (class);
+
+               for (i = 0; i < class->method.count; ++i) {
+                       flags = class->methods [i]->flags;
+                       if (flags & METHOD_ATTRIBUTE_VIRTUAL)
+                               ++count;
+               }
+       } else {
+               for (i = 0; i < class->method.count; ++i) {
+                       flags = mono_metadata_decode_table_row_col (class->image, MONO_TABLE_METHOD, class->method.first + i, MONO_METHOD_FLAGS);
+
+                       if (flags & METHOD_ATTRIBUTE_VIRTUAL)
+                               ++count;
+               }
+       }
+       return count;
+}
+
 /*
  * LOCKING: this is supposed to be called with the loader lock held.
  */
@@ -2541,6 +2569,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) {
@@ -2549,30 +2595,11 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
                                continue;
                        interfaces_full [ic->interface_id] = ic;
                        interface_offsets_full [ic->interface_id] = cur_slot;
-                       cur_slot += ic->method.count;
+                       cur_slot += count_virtual_methods (ic);
                }
                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;
@@ -2768,9 +2795,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
@@ -2779,6 +2808,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
@@ -2787,6 +2817,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
@@ -3074,10 +3105,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];
@@ -3097,38 +3127,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;
                }
@@ -3156,13 +3162,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++) {
@@ -3441,6 +3444,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++;
 
@@ -3817,6 +3824,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);
@@ -3918,8 +3935,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 {
@@ -4007,12 +4026,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);
@@ -5662,9 +5689,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) {
@@ -5809,7 +5835,7 @@ find_nocase (gpointer key, gpointer value, gpointer user_data)
        char *name = (char*)key;
        FindUserData *data = (FindUserData*)user_data;
 
-       if (!data->value && (g_strcasecmp (name, (char*)data->key) == 0))
+       if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
                data->value = value;
 }
 
@@ -5878,7 +5904,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
                        continue;
                n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
                nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
-               if (g_strcasecmp (n, name) == 0 && g_strcasecmp (nspace, name_space) == 0)
+               if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
                        return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
        }
        return NULL;
@@ -6229,6 +6255,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
@@ -7706,6 +7793,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);