2009-11-18 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mono / metadata / class.c
index eb1e6a16b5b842d1770a5afa534324801d187a53..717f93c7b8ce1558c4944335b1099534e26f6e34 100644 (file)
@@ -39,6 +39,8 @@
 #include <mono/metadata/verify-internals.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-string.h>
+#include <mono/utils/mono-error-internals.h>
 
 MonoStats mono_stats;
 
@@ -491,8 +493,10 @@ mono_class_is_open_constructed_type (MonoType *t)
 }
 
 static MonoType*
-inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context)
+inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
 {
+       mono_error_init (error);
+
        switch (type->type) {
        case MONO_TYPE_MVAR: {
                MonoType *nt;
@@ -502,8 +506,9 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
                        return NULL;
                if (num >= inst->type_argc) {
                        MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
-                       g_error ("MVAR %d (%s) cannot be expanded in this context with %d instantiations",
+                       mono_error_set_bad_image (error, image->module_name, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
                                num, info ? info->name : "", inst->type_argc);
+                       return NULL;
                }
 
                /*
@@ -524,8 +529,9 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
                        return NULL;
                if (num >= inst->type_argc) {
                        MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
-                       g_error ("VAR %d (%s) cannot be expanded in this context with %d instantiations",
+                       mono_error_set_bad_image (error, image->module_name, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
                                num, info ? info->name : "", inst->type_argc);
+                       return NULL;
                }
                nt = mono_metadata_type_dup (image, inst->type_argv [num]);
                nt->byref = type->byref;
@@ -534,8 +540,8 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
        }
        case MONO_TYPE_SZARRAY: {
                MonoClass *eclass = type->data.klass;
-               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
-               if (!inflated)
+               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
+               if (!inflated || !mono_error_ok (error))
                        return NULL;
                nt = mono_metadata_type_dup (image, type);
                nt->data.klass = mono_class_from_mono_type (inflated);
@@ -544,8 +550,8 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
        }
        case MONO_TYPE_ARRAY: {
                MonoClass *eclass = type->data.array->eklass;
-               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
-               if (!inflated)
+               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
+               if (!inflated || !mono_error_ok (error))
                        return NULL;
                nt = mono_metadata_type_dup (image, type);
                nt->data.array = g_memdup (nt->data.array, sizeof (MonoArrayType));
@@ -643,6 +649,7 @@ mono_class_get_generic_class (MonoClass *klass)
  * @mempool: a mempool
  * @type: a type
  * @context: a generics context
+ * @error: error context
  *
  * The same as mono_class_inflate_generic_type, but allocates the MonoType
  * from mempool if it is non-NULL.  If it is NULL, the MonoType is
@@ -651,12 +658,15 @@ mono_class_get_generic_class (MonoClass *klass)
  * modified by the caller, and it should be freed using mono_metadata_free_type ().
  */
 MonoType*
-mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context)
+mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
 {
-       MonoType *inflated = NULL; 
+       MonoType *inflated = NULL;
+       mono_error_init (error);
 
        if (context)
-               inflated = inflate_generic_type (image, type, context);
+               inflated = inflate_generic_type (image, type, context, error);
+       if (!mono_error_ok (error))
+               return NULL;
 
        if (!inflated) {
                MonoType *shared = mono_metadata_get_shared_type (type);
@@ -681,12 +691,40 @@ mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type,
  * generics context @context.
  *
  * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
- * on the heap and is owned by the caller.
+ * on the heap and is owned by the caller. Returns NULL on error.
+ *
+ * @deprecated Please use mono_class_inflate_generic_type_checked instead
  */
 MonoType*
 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
 {
-       return mono_class_inflate_generic_type_with_mempool (NULL, type, context);
+       MonoError error;
+       MonoType *result;
+       result = mono_class_inflate_generic_type_checked (type, context, &error);
+
+       if (!mono_error_ok (&error)) {
+               mono_error_cleanup (&error);
+               return NULL;
+       }
+       return result;
+}
+
+/*
+ * mono_class_inflate_generic_type:
+ * @type: a type
+ * @context: a generics context
+ * @error: error context to use
+ *
+ * If @type is a generic type and @context is not NULL, instantiate it using the 
+ * generics context @context.
+ *
+ * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
+ * on the heap and is owned by the caller.
+ */
+MonoType*
+mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
+{
+       return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
 }
 
 /*
@@ -698,10 +736,13 @@ mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
 static MonoType*
 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context)
 {
+       MonoError error;
        MonoType *inflated = NULL; 
 
-       if (context)
-               inflated = inflate_generic_type (image, type, context);
+       if (context) {
+               inflated = inflate_generic_type (image, type, context, &error);
+               g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+       }
 
        if (!inflated)
                return type;
@@ -718,10 +759,12 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG
 MonoClass*
 mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
 {
+       MonoError error;
        MonoClass *res;
        MonoType *inflated;
 
-       inflated = mono_class_inflate_generic_type (&gklass->byval_arg, context);
+       inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, &error);
+       g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
 
        res = mono_class_from_mono_type (inflated);
        mono_metadata_free_type (inflated);
@@ -891,7 +934,11 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
                result->klass = klass_hint;
 
        if (!result->klass) {
-               MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context);
+               MonoError error;
+               MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, &error);
+
+               g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+
                result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
                if (inflated)
                        mono_metadata_free_type (inflated);
@@ -1071,7 +1118,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 +1133,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;
@@ -1101,8 +1152,13 @@ mono_class_setup_fields (MonoClass *class)
        if (class->parent) {
                /* For generic instances, class->parent might not have been initialized */
                mono_class_init (class->parent);
-               if (!class->parent->size_inited)
+               if (!class->parent->size_inited) {
                        mono_class_setup_fields (class->parent);
+                       if (class->parent->exception_type) {
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                               return;
+                       }
+               }
                class->instance_size += class->parent->instance_size;
                class->min_align = class->parent->min_align;
                /* we use |= since it may have been set already */
@@ -1149,17 +1205,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 +1219,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.*/
@@ -1220,8 +1268,13 @@ mono_class_setup_fields (MonoClass *class)
                                blittable = FALSE;
                        } else {
                                MonoClass *field_class = mono_class_from_mono_type (field->type);
-                               if (field_class)
+                               if (field_class) {
                                        mono_class_setup_fields (field_class);
+                                       if (field_class->exception_type) {
+                                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                                               break;
+                                       }
+                               }
                                if (!field_class || !field_class->blittable)
                                        blittable = FALSE;
                        }
@@ -1701,9 +1754,14 @@ mono_class_setup_methods (MonoClass *class)
                }
        }
 
-       if (MONO_CLASS_IS_INTERFACE (class))
-               for (i = 0; i < class->method.count; ++i)
-                       methods [i]->slot = i;
+       if (MONO_CLASS_IS_INTERFACE (class)) {
+               int slot = 0;
+               /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
+               for (i = 0; i < class->method.count; ++i) {
+                       if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
+                               methods [i]->slot = slot++;
+               }
+       }
 
        /* Needed because of the double-checking locking pattern */
        mono_memory_barrier ();
@@ -2475,6 +2533,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,36 +2630,37 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
                interface_offsets_full [i] = -1;
        }
 
-       ifaces = mono_class_get_implemented_interfaces (class);
-       if (ifaces) {
-               for (i = 0; i < ifaces->len; ++i) {
-                       ic = g_ptr_array_index (ifaces, i);
-                       interfaces_full [ic->interface_id] = ic;
-                       interface_offsets_full [ic->interface_id] = cur_slot;
-                       cur_slot += ic->method.count;
-               }
-               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) {
+                               int io;
                                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;
-                               }
+                               
+                               /*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) {
+                       ic = g_ptr_array_index (ifaces, i);
+                       if (interfaces_full [ic->interface_id] != NULL)
+                               continue;
+                       interfaces_full [ic->interface_id] = ic;
+                       interface_offsets_full [ic->interface_id] = cur_slot;
+                       cur_slot += count_virtual_methods (ic);
+               }
+               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;
@@ -2766,9 +2856,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
@@ -2777,6 +2869,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
@@ -2785,6 +2878,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
@@ -3071,6 +3165,43 @@ print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, Mono
        }
 }
 
+static gboolean
+verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
+{
+       int i;
+
+       for (i = 0; i < onum; ++i) {
+               MonoMethod *decl = overrides [i * 2];
+               MonoMethod *body = overrides [i * 2 + 1];
+
+               if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (class)) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
+                       return FALSE;
+               }
+
+               if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
+                       if (body->flags & METHOD_ATTRIBUTE_STATIC)
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
+                       else
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
+                       return FALSE;
+               }
+
+               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;
+               }
+
+               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;
+               }
+       }
+       return TRUE;
+}
 /*
  * LOCKING: this is supposed to be called with the loader lock held.
  */
@@ -3092,7 +3223,11 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
        if (class->vtable)
                return;
 
+       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++) {
                        MonoClass *ic = g_ptr_array_index (ifaces, i);
@@ -3164,7 +3299,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                for (i = 0; i < parent->interface_offsets_count; i++) {
                        MonoClass *parent_interface = parent->interfaces_packed [i];
                        int interface_offset = mono_class_interface_offset (class, parent_interface);
-                       
+                       /*FIXME this is now dead code as this condition will never hold true.
+                       Since interface offsets are inherited then the offset of an interface implemented
+                       by a parent will never be the out of it's vtable boundary.
+                       */
                        if (interface_offset >= parent->vtable_size) {
                                int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
                                int j;
@@ -3370,6 +3508,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++;
 
@@ -3408,6 +3550,20 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                g_hash_table_destroy (override_map);
        }
 
+       /* Ensure that all vtable slots are filled with concrete instance methods */
+       if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+               for (i = 0; i < cur_slot; ++i) {
+                       if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
+                               char *type_name = mono_type_get_full_name (class);
+                               char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name));
+                               g_free (type_name);
+                               g_free (method_name);
+                               return;
+                       }
+               }
+       }
+
        if (class->generic_class) {
                MonoClass *gklass = class->generic_class->container_class;
 
@@ -3445,7 +3601,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&class->byval_arg), 
                        class->vtable_size, icount); 
 
-               for (i = 0; i < class->vtable_size; ++i) {
+               for (i = 0; i < cur_slot; ++i) {
                        MonoMethod *cm;
               
                        cm = vtable [i];
@@ -3464,15 +3620,15 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                ic = class->interfaces [i];
                                printf ("  slot offset: %03d, method count: %03d, iid: %03d %s\n",  
                                        mono_class_interface_offset (class, ic),
-                                       ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg));
+                                       count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
                        }
 
                        for (k = class->parent; k ; k = k->parent) {
                                for (i = 0; i < k->interface_count; i++) {
                                        ic = k->interfaces [i]; 
-                                       printf ("  slot offset: %03d, method count: %03d, iid: %03d %s\n",  
+                                       printf ("  parent slot offset: %03d, method count: %03d, iid: %03d %s\n",  
                                                mono_class_interface_offset (class, ic),
-                                               ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg));
+                                               count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
                                }
                        }
                }
@@ -3732,6 +3888,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);
@@ -3833,8 +3999,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 {
@@ -3922,12 +4090,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);
@@ -4107,6 +4283,30 @@ mono_class_setup_mono_type (MonoClass *class)
 
 }
 
+/*
+ * COM initialization (using mono_init_com_types) is delayed until needed. 
+ * However when a [ComImport] attribute is present on a type it will trigger
+ * the initialization. This is not a problem unless the BCL being executed 
+ * lacks the types that COM depends on (e.g. Variant on Silverlight).
+ */
+static void
+init_com_from_comimport (MonoClass *class)
+{
+       /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
+       if ((mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)) {
+               /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
+               if (!mono_security_core_clr_determine_platform_image (class->image)) {
+                       /* but it can not be made available for application (i.e. user code) since all COM calls
+                        * are considered native calls. In this case we fail with a TypeLoadException (just like
+                        * Silverlight 2 does */
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       return;
+               }
+       }
+       /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
+       mono_init_com_types ();
+}
+
 /*
  * LOCKING: this assumes the loader lock is held
  */
@@ -4133,7 +4333,7 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
        if (!MONO_CLASS_IS_INTERFACE (class)) {
                /* Imported COM Objects always derive from __ComObject. */
                if (MONO_CLASS_IS_IMPORT (class)) {
-                       mono_init_com_types ();
+                       init_com_from_comimport (class);
                        if (parent == mono_defaults.object_class)
                                parent = mono_defaults.com_object_class;
                }
@@ -4184,7 +4384,7 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
        } else {
                /* initialize com types if COM interfaces are present */
                if (MONO_CLASS_IS_IMPORT (class))
-                       mono_init_com_types ();
+                       init_com_from_comimport (class);
                class->parent = NULL;
        }
 
@@ -4321,6 +4521,16 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
        mono_class_setup_mono_type (class);
 
+       if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
+               class->unicode = 1;
+
+#ifdef PLATFORM_WIN32
+       if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
+               class->unicode = 1;
+#endif
+
+       class->cast_class = class->element_class = class;
+
        if (!class->enumtype) {
                if (!mono_metadata_interfaces_from_typedef_full (
                            image, type_token, &interfaces, &icount, FALSE, context)){
@@ -4334,16 +4544,6 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
                class->interfaces_inited = 1;
        }
 
-       if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
-               class->unicode = 1;
-
-#if PLATFORM_WIN32
-       if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
-               class->unicode = 1;
-#endif
-
-       class->cast_class = class->element_class = class;
-
        /*g_print ("Load class %s\n", name);*/
 
        /*
@@ -4383,6 +4583,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
                if (!enum_basetype) {
                        mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
                        mono_loader_unlock ();
+                       mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
                        return NULL;
                }
                class->cast_class = class->element_class = mono_class_from_mono_type (enum_basetype);
@@ -4399,6 +4600,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
                mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, error);
                g_free (class_name);
                mono_loader_unlock ();
+               mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
                return NULL;
        }
 
@@ -4869,11 +5071,14 @@ mono_class_from_mono_type (MonoType *type)
 static MonoType *
 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate)
 {
+       MonoError error;
        MonoType *t = mono_type_create_from_typespec (image, type_spec);
        if (!t)
                return NULL;
        if (context && (context->class_inst || context->method_inst)) {
-               MonoType *inflated = inflate_generic_type (NULL, t, context);
+               MonoType *inflated = inflate_generic_type (NULL, t, context, &error);
+               g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+
                if (inflated) {
                        t = inflated;
                        *did_inflate = TRUE;
@@ -5016,6 +5221,9 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
                mono_class_init (eclass);
        if (!eclass->size_inited)
                mono_class_setup_fields (eclass);
+       if (eclass->exception_type) /*FIXME we fail the array type, but we have to let other fields be set.*/
+               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+
        class->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
 
        class->rank = rank;
@@ -5169,6 +5377,8 @@ static MonoClassField *
 mono_class_get_field_idx (MonoClass *class, int idx)
 {
        mono_class_setup_fields_locking (class);
+       if (class->exception_type)
+               return NULL;
 
        while (class) {
                if (class->image->uncompressed_metadata) {
@@ -5249,6 +5459,9 @@ mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoTyp
        int i;
 
        mono_class_setup_fields_locking (klass);
+       if (klass->exception_type)
+               return NULL;
+
        while (klass) {
                for (i = 0; i < klass->field.count; ++i) {
                        MonoClassField *field = &klass->fields [i];
@@ -5284,6 +5497,9 @@ mono_class_get_field_token (MonoClassField *field)
        int i;
 
        mono_class_setup_fields_locking (klass);
+       if (klass->exception_type)
+               return 0;
+
        while (klass) {
                for (i = 0; i < klass->field.count; ++i) {
                        if (&klass->fields [i] == field) {
@@ -5575,9 +5791,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) {
@@ -5695,6 +5910,7 @@ mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
 {
        GHashTable *nspace_table;
        GHashTable *name_cache;
+       guint32 old_index;
 
        mono_image_lock (image);
 
@@ -5706,6 +5922,10 @@ mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
                nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
                g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
        }
+
+       if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
+               g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
+
        g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
 
        mono_image_unlock (image);
@@ -5722,7 +5942,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;
 }
 
@@ -5791,7 +6011,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;
@@ -6142,6 +6362,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
@@ -7530,6 +7811,14 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
                return TRUE;
        if (!accessed || !accessing)
                return FALSE;
+
+       /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
+        * anywhere so untrusted friends are not safe to access platform's code internals */
+       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
+               if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
+                       return FALSE;
+       }
+
        mono_assembly_load_friends (accessed);
        for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
                MonoAssemblyName *friend = tmp->data;
@@ -7619,6 +7908,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);