Merge pull request #3786 from lambdageek/dev-42584-take2
[mono.git] / mono / metadata / class.c
index 6218589a88e3c47b96ecacfff2701e05e5035e7a..fa67e15b0f1404c942742c410d57ef2a714002a7 100644 (file)
@@ -77,6 +77,10 @@ static guint32 mono_field_resolve_flags (MonoClassField *field);
 static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
 
+static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error);
+static gpointer mono_class_get_exception_data (const MonoClass *klass);
+
+
 /*
 We use gclass recording to allow recursive system f types to be referenced by a parent.
 
@@ -104,6 +108,9 @@ static int record_gclass_instantiation;
 static GSList *gclass_recorded_list;
 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
 
+/* This TLS variable points to a GSList of classes which have setup_fields () executing */
+static MonoNativeTlsKey setup_fields_tls_id;
+
 static inline void
 classes_lock (void)
 {
@@ -1132,6 +1139,15 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
        result->sre_method = FALSE;
        result->signature = NULL;
 
+       if (method->wrapper_type) {
+               MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
+               MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
+               int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
+
+               resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
+               memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
+       }
+
        if (iresult->context.method_inst) {
                /* Set the generic_container of the result to the generic_container of method */
                MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
@@ -1352,7 +1368,7 @@ fail:
 }
 
 /*
- * Checks for MonoClass::exception_type without resolving all MonoType's into MonoClass'es
+ * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
  */
 static gboolean
 mono_type_has_exceptions (MonoType *type)
@@ -1372,49 +1388,11 @@ mono_type_has_exceptions (MonoType *type)
 }
 
 void
-mono_error_set_for_class_failure (MonoError *oerror, MonoClass *klass)
+mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
 {
-       gpointer exception_data = mono_class_get_exception_data (klass);
-
-       switch (mono_class_get_failure(klass)) {
-       case MONO_EXCEPTION_TYPE_LOAD: {
-               mono_error_set_type_load_class (oerror, klass, "Error Loading class");
-               return;
-       }
-       case MONO_EXCEPTION_MISSING_METHOD: {
-               char *class_name = (char *)exception_data;
-               char *member_name = class_name + strlen (class_name) + 1;
-
-               mono_error_set_method_load (oerror, klass, member_name, "Error Loading Method");
-               return;
-       }
-       case MONO_EXCEPTION_MISSING_FIELD: {
-               char *class_name = (char *)exception_data;
-               char *member_name = class_name + strlen (class_name) + 1;
-
-               mono_error_set_field_load (oerror, klass, member_name, "Error Loading Field");
-               return;
-       }
-       case MONO_EXCEPTION_FILE_NOT_FOUND: {
-               char *msg_format = (char *)exception_data;
-               char *assembly_name = msg_format + strlen (msg_format) + 1;
-               char *msg = g_strdup_printf (msg_format, assembly_name);
-
-               mono_error_set_assembly_load (oerror, assembly_name, msg);
-               return;
-       }
-       case MONO_EXCEPTION_BAD_IMAGE: {
-               mono_error_set_bad_image (oerror, NULL, (const char *)exception_data);
-               return;
-       }
-       case MONO_EXCEPTION_INVALID_PROGRAM: {
-               mono_error_set_invalid_program (oerror, (const char *)exception_data);
-               return;
-       }
-       default: {
-               g_assert_not_reached ();
-       }
-       }
+       g_assert (mono_class_has_failure (klass));
+       MonoErrorBoxed *box = (MonoErrorBoxed*)mono_class_get_exception_data (klass);
+       mono_error_set_from_boxed (oerror, box);
 }
 
 
@@ -1424,7 +1402,7 @@ mono_error_set_for_class_failure (MonoError *oerror, MonoClass *klass)
  *   Allocate memory for some data belonging to CLASS, either from its image's mempool,
  * or from the heap.
  */
-static gpointer
+gpointer
 mono_class_alloc (MonoClass *klass, int size)
 {
        if (klass->generic_class)
@@ -1433,7 +1411,7 @@ mono_class_alloc (MonoClass *klass, int size)
                return mono_image_alloc (klass->image, size);
 }
 
-static gpointer
+gpointer
 mono_class_alloc0 (MonoClass *klass, int size)
 {
        gpointer res;
@@ -1450,13 +1428,17 @@ mono_class_alloc0 (MonoClass *klass, int size)
  * mono_class_setup_basic_field_info:
  * @class: The class to initialize
  *
- * Initializes the klass->fields.
- * LOCKING: Assumes the loader lock is held.
+ * Initializes the following fields in MonoClass:
+ * * klass->fields (only field->parent and field->name)
+ * * klass->field.count
+ * * klass->field.first
+ * LOCKING: Acquires the loader lock
  */
 static void
 mono_class_setup_basic_field_info (MonoClass *klass)
 {
        MonoClassField *field;
+       MonoClassField *fields;
        MonoClass *gtd;
        MonoImage *image;
        int i, top;
@@ -1466,7 +1448,6 @@ mono_class_setup_basic_field_info (MonoClass *klass)
 
        gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
        image = klass->image;
-       top = klass->field.count;
 
        if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
                /*
@@ -1481,18 +1462,21 @@ mono_class_setup_basic_field_info (MonoClass *klass)
        if (gtd) {
                mono_class_setup_basic_field_info (gtd);
 
-               top = gtd->field.count;
+               mono_loader_lock ();
                klass->field.first = gtd->field.first;
                klass->field.count = gtd->field.count;
+               mono_loader_unlock ();
        }
 
-       klass->fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
+       top = klass->field.count;
+
+       fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
 
        /*
         * Fetch all the field information.
         */
        for (i = 0; i < top; i++){
-               field = &klass->fields [i];
+               field = &fields [i];
                field->parent = klass;
 
                if (gtd) {
@@ -1505,78 +1489,78 @@ mono_class_setup_basic_field_info (MonoClass *klass)
                        field->name = mono_metadata_string_heap (image, name_idx);
                }
        }
+
+       mono_memory_barrier ();
+
+       mono_loader_lock ();
+       if (!klass->fields)
+               klass->fields = fields;
+       mono_loader_unlock ();
 }
 
+/**
+ * mono_class_set_failure_causedby_class:
+ * @klass: the class that is failing
+ * @caused_by: the class that caused the failure
+ * @msg: Why @klass is failing.
+ * 
+ * If @caused_by has a failure, sets a TypeLoadException failure on
+ * @klass with message "@msg, due to: {@caused_by message}".
+ *
+ * Returns: TRUE if a failiure was set, or FALSE if @caused_by doesn't have a failure.
+ */
+static gboolean
+mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
+{
+       if (mono_class_has_failure (caused_by)) {
+               MonoError cause_error;
+               mono_error_init (&cause_error);
+               mono_error_set_for_class_failure (&cause_error, caused_by);
+               mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (&cause_error));
+               mono_error_cleanup (&cause_error);
+               return TRUE;
+       } else {
+               return FALSE;
+       }
+}
+
+
 /** 
  * mono_class_setup_fields:
- * @class: The class to initialize
+ * @klass: The class to initialize
+ *
+ * Initializes klass->fields, computes class layout and sizes.
+ * typebuilder_setup_fields () is the corresponding function for dynamic classes.
+ * Sets the following fields in @klass:
+ *  - packing_size
+ *  - min_align
+ *  - blittable
+ *  - has_references (if the class contains instance references firled or structs that contain references)
+ *  - has_static_refs (same, but for static fields)
+ *  - instance_size (size of the object in memory)
+ *  - class_size (size needed for the static fields)
+ *  - size_inited (flag set when the instance_size is set)
+ *  - element_class/cast_class (for enums)
+ *  - fields_inited
  *
- * Initializes the klass->fields.
- * LOCKING: Assumes the loader lock is held.
+ * LOCKING: Acquires the loader lock.
  */
-static void
+void
 mono_class_setup_fields (MonoClass *klass)
 {
        MonoError error;
        MonoImage *m = klass->image;
        int top;
        guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
-       int i, blittable = TRUE;
+       int i;
        guint32 real_size = 0;
        guint32 packing_size = 0;
        int instance_size;
        gboolean explicit_size;
        MonoClassField *field;
-       MonoGenericContainer *container = NULL;
-       MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+       MonoClass *gtd;
 
-       /*
-        * FIXME: We have a race condition here.  It's possible that this function returns
-        * to its caller with `instance_size` set to `0` instead of the actual size.  This
-        * is not a problem when the function is called recursively on the same class,
-        * because the size will be initialized by the outer invocation.  What follows is a
-        * description of how it can occur in other cases, too.  There it is a problem,
-        * because it can lead to the GC being asked to allocate an object of size `0`,
-        * which SGen chokes on.  The race condition is triggered infrequently by
-        * `tests/sgen-suspend.cs`.
-        *
-        * This function is called for a class whenever one of its subclasses is inited.
-        * For example, it's called for every subclass of Object.  What it does is this:
-        *
-        *     if (klass->setup_fields_called)
-        *         return;
-        *     ...
-        *     klass->instance_size = 0;
-        *     ...
-        *     klass->setup_fields_called = 1;
-        *     ... critical point
-        *     klass->instance_size = actual_instance_size;
-        *
-        * The last two steps are sometimes reversed, but that only changes the way in which
-        * the race condition works.
-        *
-        * Assume thread A goes through this function and makes it to the critical point.
-        * Now thread B runs the function and, since `setup_fields_called` is set, returns
-        * immediately, but `instance_size` is incorrect.
-        *
-        * The other case looks like this:
-        *
-        *     if (klass->setup_fields_called)
-        *         return;
-        *     ... critical point X
-        *     klass->instance_size = 0;
-        *     ... critical point Y
-        *     klass->instance_size = actual_instance_size;
-        *     ...
-        *     klass->setup_fields_called = 1;
-        *
-        * Assume thread A goes through the function and makes it to critical point X.  Now
-        * thread B runs through the whole of the function, returning, assuming
-        * `instance_size` is set.  At that point thread A gets to run and makes it to
-        * critical point Y, at which time `instance_size` is `0` again, invalidating thread
-        * B's assumption.
-        */
-       if (klass->setup_fields_called)
+       if (klass->fields_inited)
                return;
 
        if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
@@ -1592,101 +1576,53 @@ mono_class_setup_fields (MonoClass *klass)
        mono_class_setup_basic_field_info (klass);
        top = klass->field.count;
 
+       gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
        if (gtd) {
                mono_class_setup_fields (gtd);
-               if (mono_class_has_failure (gtd)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+               if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
                        return;
-               }
        }
 
        instance_size = 0;
-       if (!klass->rank)
-               klass->sizes.class_size = 0;
-
        if (klass->parent) {
                /* For generic instances, klass->parent might not have been initialized */
                mono_class_init (klass->parent);
-               if (!klass->parent->size_inited) {
-                       mono_class_setup_fields (klass->parent);
-                       if (mono_class_has_failure (klass->parent)) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-                               return;
-                       }
-               }
-               instance_size += klass->parent->instance_size;
-               klass->min_align = klass->parent->min_align;
-               /* we use |= since it may have been set already */
-               klass->has_references |= klass->parent->has_references;
-               blittable = klass->parent->blittable;
+               mono_class_setup_fields (klass->parent);
+               if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
+                       return;
+               instance_size = klass->parent->instance_size;
        } else {
                instance_size = sizeof (MonoObject);
-               klass->min_align = 1;
        }
 
-       /* We can't really enable 16 bytes alignment until the GC supports it.
-       The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
-       boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
-       Bug #506144 is an example of this issue.
-
-        if (klass->simd_type)
-               klass->min_align = 16;
-        */
        /* Get the real size */
        explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
+       if (explicit_size)
+               instance_size += real_size;
 
-       if (explicit_size) {
-               if ((packing_size & 0xffffff00) != 0) {
-                       char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
-                       return;
-               }
-               klass->packing_size = packing_size;
-               real_size += instance_size;
-       }
-
-       if (!top) {
-               if (explicit_size && real_size) {
-                       instance_size = MAX (real_size, instance_size);
-               }
-               klass->blittable = blittable;
-               if (!klass->instance_size)
-                       klass->instance_size = instance_size;
-               mono_memory_barrier ();
-               klass->size_inited = 1;
-               klass->fields_inited = 1;
-               klass->setup_fields_called = 1;
+       /*
+        * This function can recursively call itself.
+        * Prevent infinite recursion by using a list in TLS.
+        */
+       GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
+       if (g_slist_find (init_list, klass))
                return;
-       }
-
-       if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")))
-               blittable = FALSE;
-
-       /* Prevent infinite loops if the class references itself */
-       klass->setup_fields_called = 1;
-
-       if (klass->generic_container) {
-               container = klass->generic_container;
-       } else if (gtd) {
-               container = gtd->generic_container;
-               g_assert (container);
-       }
+       init_list = g_slist_prepend (init_list, klass);
+       mono_native_tls_set_value (setup_fields_tls_id, init_list);
 
        /*
         * Fetch all the field information.
         */
-       for (i = 0; i < top; i++){
+       for (i = 0; i < top; i++) {
                int idx = klass->field.first + i;
                field = &klass->fields [i];
 
-               field->parent = klass;
-
                if (!field->type) {
                        mono_field_resolve_type (field, &error);
                        if (!mono_error_ok (&error)) {
                                /*mono_field_resolve_type already failed class*/
                                mono_error_cleanup (&error);
-                               return;
+                               break;
                        }
                        if (!field->type)
                                g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
@@ -1695,58 +1631,29 @@ mono_class_setup_fields (MonoClass *klass)
 
                if (mono_field_is_deleted (field))
                        continue;
-               if (gtd) {
-                       MonoClassField *gfield = &gtd->fields [i];
-                       field->offset = gfield->offset;
-               } else {
-                       if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
-                               guint32 offset;
-                               mono_metadata_field_info (m, idx, &offset, NULL, NULL);
-                               field->offset = offset;
+               if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
+                       guint32 uoffset;
+                       mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
+                       int offset = uoffset;
 
-                               if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
-                                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Missing field layout info for %s", field->name));
-                                       break;
-                               }
-                               if (field->offset < -1) { /*-1 is used to encode special static fields */
-                                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name));
-                                       break;
-                               }
-                               if (klass->generic_container) {
-                                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic class cannot have explicit layout."));
-                                       break;
-                               }
+                       if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+                               mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
+                               break;
                        }
-               }
-
-               /* Only do these checks if we still think this type is blittable */
-               if (blittable && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
-                       if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
-                               blittable = FALSE;
-                       } else {
-                               MonoClass *field_class = mono_class_from_mono_type (field->type);
-                               if (field_class) {
-                                       mono_class_setup_fields (field_class);
-                                       if (mono_class_has_failure (field_class)) {
-                                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-                                               break;
-                                       }
-                               }
-                               if (!field_class || !field_class->blittable)
-                                       blittable = FALSE;
+                       if (offset < -1) { /*-1 is used to encode special static fields */
+                               mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
+                               break;
+                       }
+                       if (klass->generic_container) {
+                               mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
+                               break;
                        }
                }
-
-               if (klass->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
-                       klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
-                       blittable = klass->element_class->blittable;
-               }
-
                if (mono_type_has_exceptions (field->type)) {
                        char *class_name = mono_type_get_full_name (klass);
                        char *type_name = mono_type_full_name (field->type);
 
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_class_set_type_load_failure (klass, "");
                        g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
                        g_free (class_name);
                        g_free (type_name);
@@ -1755,47 +1662,11 @@ mono_class_setup_fields (MonoClass *klass)
                /* The def_value of fields is compute lazily during vtable creation */
        }
 
-       if (klass == mono_defaults.string_class)
-               blittable = FALSE;
-
-       klass->blittable = blittable;
-
-       if (klass->enumtype && !mono_class_enum_basetype (klass)) {
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-               return;
-       }
-       if (explicit_size && real_size) {
-               instance_size = MAX (real_size, instance_size);
-       }
-
-       if (mono_class_has_failure (klass))
-               return;
-       mono_class_layout_fields (klass, instance_size);
-
-       /*valuetypes can't be neither bigger than 1Mb or empty. */
-       if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-
-       mono_memory_barrier ();
-       klass->fields_inited = 1;
-}
+       if (!mono_class_has_failure (klass))
+               mono_class_layout_fields (klass, instance_size, packing_size, FALSE);
 
-/** 
- * mono_class_setup_fields_locking:
- * @class: The class to initialize
- *
- * Initializes the klass->fields array of fields.
- * Aquires the loader lock.
- */
-void
-mono_class_setup_fields_locking (MonoClass *klass)
-{
-       /* This can be checked without locks */
-       if (klass->fields_inited)
-               return;
-       mono_loader_lock ();
-       mono_class_setup_fields (klass);
-       mono_loader_unlock ();
+       init_list = g_slist_remove (init_list, klass);
+       mono_native_tls_set_value (setup_fields_tls_id, init_list);
 }
 
 /*
@@ -1851,20 +1722,17 @@ type_has_references (MonoClass *klass, MonoType *ftype)
 /*
  * mono_class_layout_fields:
  * @class: a class
- * @instance_size: base instance size
+ * @base_instance_size: base instance size
+ * @packing_size:
  *
- * Compute the placement of fields inside an object or struct, according to
- * the layout rules and set the following fields in @class:
- *  - has_references (if the class contains instance references firled or structs that contain references)
- *  - has_static_refs (same, but for static fields)
- *  - instance_size (size of the object in memory)
- *  - class_size (size needed for the static fields)
- *  - size_inited (flag set when the instance_size is set)
+ * This contains the common code for computing the layout of classes and sizes.
+ * This should only be called from mono_class_setup_fields () and
+ * typebuilder_setup_fields ().
  *
- * LOCKING: this is supposed to be called with the loader lock held.
+ * LOCKING: Acquires the loader lock
  */
 void
-mono_class_layout_fields (MonoClass *klass, int instance_size)
+mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre)
 {
        int i;
        const int top = klass->field.count;
@@ -1872,7 +1740,41 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
        guint32 pass, passes, real_size;
        gboolean gc_aware_layout = FALSE;
        gboolean has_static_fields = FALSE;
+       gboolean has_references = FALSE;
+       gboolean has_static_refs = FALSE;
        MonoClassField *field;
+       gboolean blittable;
+       int instance_size = base_instance_size;
+       int class_size, min_align;
+       int *field_offsets;
+
+       /*
+        * We want to avoid doing complicated work inside locks, so we compute all the required
+        * information and write it to @klass inside a lock.
+        */
+       if (klass->fields_inited)
+               return;
+
+       if ((packing_size & 0xffffff00) != 0) {
+               mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
+               return;
+       }
+
+       if (klass->parent) {
+               min_align = klass->parent->min_align;
+               /* we use | since it may have been set already */
+               has_references = klass->has_references | klass->parent->has_references;
+       } else {
+               min_align = 1;
+       }
+       /* We can't really enable 16 bytes alignment until the GC supports it.
+       The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
+       boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
+       Bug #506144 is an example of this issue.
+
+        if (klass->simd_type)
+               min_align = 16;
+        */
 
        /*
         * When we do generic sharing we need to have layout
@@ -1881,6 +1783,21 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
         * container), so we don't return in that case anymore.
         */
 
+       if (klass->enumtype) {
+               for (i = 0; i < top; i++) {
+                       field = &klass->fields [i];
+                       if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+                               klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
+                               break;
+                       }
+               }
+
+               if (!mono_class_enum_basetype (klass)) {
+                       mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
+                       return;
+               }
+       }
+
        /*
         * Enable GC aware auto layout: in this mode, reference
         * fields are grouped together inside objects, increasing collector 
@@ -1896,59 +1813,72 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
                        gc_aware_layout = TRUE;
        }
 
-       /* Compute klass->has_references */
-       /* 
-        * Process non-static fields first, since static fields might recursively
-        * refer to the class itself.
-        */
+       /* Compute klass->blittable */
+       blittable = TRUE;
+       if (klass->parent)
+               blittable = klass->parent->blittable;
+       if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
+               blittable = FALSE;
        for (i = 0; i < top; i++) {
-               MonoType *ftype;
-
                field = &klass->fields [i];
 
-               if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
-                       ftype = mono_type_get_underlying_type (field->type);
-                       ftype = mono_type_get_basic_type_from_generic (ftype);
-                       if (type_has_references (klass, ftype))
-                               klass->has_references = TRUE;
+               if (mono_field_is_deleted (field))
+                       continue;
+               if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+                       continue;
+               if (blittable) {
+                       if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
+                               blittable = FALSE;
+                       } else {
+                               MonoClass *field_class = mono_class_from_mono_type (field->type);
+                               if (field_class) {
+                                       mono_class_setup_fields (field_class);
+                                       if (mono_class_has_failure (field_class)) {
+                                               MonoError field_error;
+                                               mono_error_init (&field_error);
+                                               mono_error_set_for_class_failure (&field_error, field_class);
+                                               mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
+                                               mono_error_cleanup (&field_error);
+                                               break;
+                                       }
+                               }
+                               if (!field_class || !field_class->blittable)
+                                       blittable = FALSE;
+                       }
                }
+               if (klass->enumtype)
+                       blittable = klass->element_class->blittable;
        }
+       if (mono_class_has_failure (klass))
+               return;
+       if (klass == mono_defaults.string_class)
+               blittable = FALSE;
 
+       /* Compute klass->has_references */
+       /* 
+        * Process non-static fields first, since static fields might recursively
+        * refer to the class itself.
+        */
        for (i = 0; i < top; i++) {
                MonoType *ftype;
 
                field = &klass->fields [i];
 
-               if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+               if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
                        ftype = mono_type_get_underlying_type (field->type);
                        ftype = mono_type_get_basic_type_from_generic (ftype);
                        if (type_has_references (klass, ftype))
-                               klass->has_static_refs = TRUE;
-               }
-       }
-
-       for (i = 0; i < top; i++) {
-               MonoType *ftype;
-
-               field = &klass->fields [i];
-
-               ftype = mono_type_get_underlying_type (field->type);
-               ftype = mono_type_get_basic_type_from_generic (ftype);
-               if (type_has_references (klass, ftype)) {
-                       if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
-                               klass->has_static_refs = TRUE;
-                       else
-                               klass->has_references = TRUE;
+                               has_references = TRUE;
                }
        }
 
        /*
         * Compute field layout and total size (not considering static fields)
         */
+       field_offsets = g_new0 (int, top);
        switch (layout) {
        case TYPE_ATTRIBUTE_AUTO_LAYOUT:
        case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
-
                if (gc_aware_layout)
                        passes = 2;
                else
@@ -1959,10 +1889,8 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
 
                if (klass->parent) {
                        mono_class_setup_fields (klass->parent);
-                       if (mono_class_has_failure (klass->parent)) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
                                return;
-                       }
                        real_size = klass->parent->instance_size;
                } else {
                        real_size = sizeof (MonoObject);
@@ -1993,7 +1921,7 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
                                        }
                                }
 
-                               if ((top == 1) && (klass->instance_size == sizeof (MonoObject)) &&
+                               if ((top == 1) && (instance_size == sizeof (MonoObject)) &&
                                        (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
                                        /* This field is a hack inserted by MCS to empty structures */
                                        continue;
@@ -2002,29 +1930,29 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
                                size = mono_type_size (field->type, &align);
                        
                                /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
-                               align = klass->packing_size ? MIN (klass->packing_size, align): align;
+                               align = packing_size ? MIN (packing_size, align): align;
                                /* if the field has managed references, we need to force-align it
                                 * see bug #77788
                                 */
                                if (type_has_references (klass, ftype))
                                        align = MAX (align, sizeof (gpointer));
 
-                               klass->min_align = MAX (align, klass->min_align);
-                               field->offset = real_size;
+                               min_align = MAX (align, min_align);
+                               field_offsets [i] = real_size;
                                if (align) {
-                                       field->offset += align - 1;
-                                       field->offset &= ~(align - 1);
+                                       field_offsets [i] += align - 1;
+                                       field_offsets [i] &= ~(align - 1);
                                }
                                /*TypeBuilders produce all sort of weird things*/
-                               g_assert (image_is_dynamic (klass->image) || field->offset > 0);
-                               real_size = field->offset + size;
+                               g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
+                               real_size = field_offsets [i] + size;
                        }
 
                        instance_size = MAX (real_size, instance_size);
        
-                       if (instance_size & (klass->min_align - 1)) {
-                               instance_size += klass->min_align - 1;
-                               instance_size &= ~(klass->min_align - 1);
+                       if (instance_size & (min_align - 1)) {
+                               instance_size += min_align - 1;
+                               instance_size &= ~(min_align - 1);
                        }
                }
                break;
@@ -2049,28 +1977,30 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
                                continue;
 
                        size = mono_type_size (field->type, &align);
-                       align = klass->packing_size ? MIN (klass->packing_size, align): align;
-                       klass->min_align = MAX (align, klass->min_align);
+                       align = packing_size ? MIN (packing_size, align): align;
+                       min_align = MAX (align, min_align);
 
-                       /*
-                        * When we get here, field->offset is already set by the
-                        * loader (for either runtime fields or fields loaded from metadata).
-                        * The offset is from the start of the object: this works for both
-                        * classes and valuetypes.
-                        */
-                       field->offset += sizeof (MonoObject);
+                       if (sre) {
+                               /* Already set by typebuilder_setup_fields () */
+                               field_offsets [i] = field->offset + sizeof (MonoObject);
+                       } else {
+                               int idx = klass->field.first + i;
+                               guint32 offset;
+                               mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
+                               field_offsets [i] = offset + sizeof (MonoObject);
+                       }
                        ftype = mono_type_get_underlying_type (field->type);
                        ftype = mono_type_get_basic_type_from_generic (ftype);
                        if (type_has_references (klass, ftype)) {
-                               if (field->offset % sizeof (gpointer)) {
-                                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                               if (field_offsets [i] % sizeof (gpointer)) {
+                                       mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
                                }
                        }
 
                        /*
                         * Calc max size.
                         */
-                       real_size = MAX (real_size, size + field->offset);
+                       real_size = MAX (real_size, size + field_offsets [i]);
                }
 
                if (klass->has_references) {
@@ -2088,7 +2018,7 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
                                        continue;
                                ftype = mono_type_get_underlying_type (field->type);
                                if (MONO_TYPE_IS_REFERENCE (ftype))
-                                       ref_bitmap [field->offset / sizeof (gpointer)] = 1;
+                                       ref_bitmap [field_offsets [i] / sizeof (gpointer)] = 1;
                        }
                        for (i = 0; i < top; i++) {
                                field = &klass->fields [i];
@@ -2100,9 +2030,8 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
 
                                // FIXME: Too much code does this
 #if 0
-                               if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field->offset / sizeof (gpointer)]) {
-                                       char *err_msg = g_strdup_printf ("Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field->offset);
-                                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+                               if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / sizeof (gpointer)]) {
+                                       mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field_offsets [i]);
                                }
 #endif
                        }
@@ -2110,9 +2039,9 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
                }
 
                instance_size = MAX (real_size, instance_size);
-               if (instance_size & (klass->min_align - 1)) {
-                       instance_size += klass->min_align - 1;
-                       instance_size &= ~(klass->min_align - 1);
+               if (instance_size & (min_align - 1)) {
+                       instance_size += min_align - 1;
+                       instance_size &= ~(min_align - 1);
                }
                break;
        }
@@ -2127,25 +2056,46 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
                 * performance, and since the JIT memset/memcpy code assumes this and generates 
                 * unaligned accesses otherwise. See #78990 for a testcase.
                 */
-               if (mono_align_small_structs) {
+               if (mono_align_small_structs && top) {
                        if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
-                               klass->min_align = MAX (klass->min_align, instance_size - sizeof (MonoObject));
+                               min_align = MAX (min_align, instance_size - sizeof (MonoObject));
                }
        }
 
+       if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+               instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
+       else if (klass->byval_arg.type == MONO_TYPE_PTR)
+               instance_size = sizeof (MonoObject) + sizeof (gpointer);
+
+       /* Publish the data */
+       mono_loader_lock ();
        if (klass->instance_size && !klass->image->dynamic) {
                /* Might be already set using cached info */
                g_assert (klass->instance_size == instance_size);
        } else {
                klass->instance_size = instance_size;
        }
+       klass->blittable = blittable;
+       klass->has_references = has_references;
+       klass->packing_size = packing_size;
+       klass->min_align = min_align;
+       for (i = 0; i < top; ++i) {
+               field = &klass->fields [i];
+               if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+                       klass->fields [i].offset = field_offsets [i];
+       }
+
        mono_memory_barrier ();
        klass->size_inited = 1;
+       mono_loader_unlock ();
 
        /*
         * Compute static field layout and size
+        * Static fields can reference the class itself, so this has to be
+        * done after instance_size etc. are initialized.
         */
-       for (i = 0; i < top; i++){
+       class_size = 0;
+       for (i = 0; i < top; i++) {
                gint32 align;
                guint32 size;
 
@@ -2157,23 +2107,60 @@ mono_class_layout_fields (MonoClass *klass, int instance_size)
                        continue;
 
                if (mono_type_has_exceptions (field->type)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
                        break;
                }
 
                has_static_fields = TRUE;
 
                size = mono_type_size (field->type, &align);
-               field->offset = klass->sizes.class_size;
+               field_offsets [i] = class_size;
                /*align is always non-zero here*/
-               field->offset += align - 1;
-               field->offset &= ~(align - 1);
-               klass->sizes.class_size = field->offset + size;
+               field_offsets [i] += align - 1;
+               field_offsets [i] &= ~(align - 1);
+               class_size = field_offsets [i] + size;
        }
 
-       if (has_static_fields && klass->sizes.class_size == 0)
+       if (has_static_fields && class_size == 0)
                /* Simplify code which depends on class_size != 0 if the class has static fields */
-               klass->sizes.class_size = 8;
+               class_size = 8;
+
+       /* Compute klass->has_static_refs */
+       has_static_refs = FALSE;
+       for (i = 0; i < top; i++) {
+               MonoType *ftype;
+
+               field = &klass->fields [i];
+
+               if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+                       ftype = mono_type_get_underlying_type (field->type);
+                       ftype = mono_type_get_basic_type_from_generic (ftype);
+                       if (type_has_references (klass, ftype))
+                               has_static_refs = TRUE;
+               }
+       }
+
+       /*valuetypes can't be neither bigger than 1Mb or empty. */
+       if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
+               mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
+
+       /* Publish the data */
+       mono_loader_lock ();
+       if (!klass->rank)
+               klass->sizes.class_size = class_size;
+       klass->has_static_refs = has_static_refs;
+       for (i = 0; i < top; ++i) {
+               field = &klass->fields [i];
+
+               if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+                       field->offset = field_offsets [i];
+       }
+
+       mono_memory_barrier ();
+       klass->fields_inited = 1;
+       mono_loader_unlock ();
+
+       g_free (field_offsets);
 }
 
 static MonoMethod*
@@ -2207,7 +2194,7 @@ create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *si
  * Methods belonging to an interface are assigned a sequential slot starting
  * from 0.
  *
- * On failure this function sets klass->exception_type
+ * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
  */
 void
 mono_class_setup_methods (MonoClass *klass)
@@ -2225,11 +2212,8 @@ mono_class_setup_methods (MonoClass *klass)
                mono_class_init (gklass);
                if (!mono_class_has_failure (gklass))
                        mono_class_setup_methods (gklass);
-               if (mono_class_has_failure (gklass)) {
-                       /* FIXME make exception_data less opaque so it's possible to dup it here */
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+               if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
                        return;
-               }
 
                /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
                count = gklass->method.count;
@@ -2240,7 +2224,7 @@ mono_class_setup_methods (MonoClass *klass)
                                gklass->methods [i], klass, mono_class_get_context (klass), &error);
                        if (!mono_error_ok (&error)) {
                                char *method = mono_method_full_name (gklass->methods [i], TRUE);
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not inflate method %s due to %s", method, mono_error_get_message (&error)));
+                               mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (&error));
 
                                g_free (method);
                                mono_error_cleanup (&error);
@@ -2346,7 +2330,7 @@ mono_class_setup_methods (MonoClass *klass)
                        int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1);
                        methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error);
                        if (!methods [i]) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load method %d due to %s", i, mono_error_get_message (&error)));
+                               mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error));
                                mono_error_cleanup (&error);
                        }
                }
@@ -2523,10 +2507,8 @@ mono_class_setup_properties (MonoClass *klass)
 
                mono_class_init (gklass);
                mono_class_setup_properties (gklass);
-               if (mono_class_has_failure (gklass)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+               if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
                        return;
-               }
 
                properties = mono_class_new0 (klass, MonoProperty, gklass->ext->property.count + 1);
 
@@ -2656,10 +2638,8 @@ mono_class_setup_events (MonoClass *klass)
                MonoGenericContext *context = NULL;
 
                mono_class_setup_events (gklass);
-               if (mono_class_has_failure (gklass)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+               if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
                        return;
-               }
 
                first = gklass->ext->event.first;
                count = gklass->ext->event.count;
@@ -2697,7 +2677,6 @@ mono_class_setup_events (MonoClass *klass)
                if (count) {
                        mono_class_setup_methods (klass);
                        if (mono_class_has_failure (klass)) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
                                return;
                        }
                }
@@ -3515,7 +3494,7 @@ mono_class_interface_match (const uint8_t *bitmap, int id)
 
 /*
  * LOCKING: this is supposed to be called with the loader lock held.
- * Return -1 on failure and set exception_type
+ * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
  */
 static int
 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
@@ -3559,7 +3538,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                ifaces = mono_class_get_implemented_interfaces (k, &error);
                if (!mono_error_ok (&error)) {
                        char *name = mono_type_get_full_name (k);
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error)));
+                       mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error));
                        g_free (name);
                        mono_error_cleanup (&error);
                        cur_slot = -1;
@@ -3626,7 +3605,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                        count = count_virtual_methods (ic);
                        if (count == -1) {
                                char *name = mono_type_get_full_name (ic);
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error calculating interface offset of %s", name));
+                               mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
                                g_free (name);
                                cur_slot = -1;
                                goto end;
@@ -3802,10 +3781,8 @@ mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
        }
 
        mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
-       if (mono_class_has_failure (klass->generic_class->container_class)) {
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to load generic definition vtable"));
+       if (mono_class_set_type_load_failure_causedby_class (klass, klass->generic_class->container_class, "Failed to load generic definition vtable"))
                return FALSE;
-       }
 
        ginst = klass->generic_class->context.class_inst;
        for (i = 0; i < ginst->type_argc; ++i) {
@@ -3817,7 +3794,7 @@ mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
                if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
                        continue;
                if (!mono_class_check_vtable_constraints (arg, in_setup)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Failed to load generic parameter %d", i));
+                       mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
                        return FALSE;
                }
        }
@@ -3832,7 +3809,8 @@ mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
  * - vtable
  * - vtable_size
  * Plus all the fields initialized by setup_interface_offsets ().
- * If there is an error during vtable construction, klass->exception_type is set.
+ * If there is an error during vtable construction, klass->has_failure
+ * is set and details are stored in a MonoErrorBoxed.
  *
  * LOCKING: Acquires the loader lock.
  */
@@ -3900,7 +3878,7 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
                if (!is_ok (&error)) {
                        mono_loader_unlock ();
                        g_list_remove (in_setup, klass);
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf("Could not load list of method overrides due to %s", mono_error_get_message (&error)));
+                       mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error));
                        mono_error_cleanup (&error);
                        return;
                }
@@ -3913,7 +3891,7 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
        if (ok)
                mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
        else
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load list of method overrides"));
+               mono_class_set_type_load_failure (klass, "Could not load list of method overrides");
                
        g_free (overrides);
 
@@ -4029,7 +4007,7 @@ check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *c
                cmsig = mono_method_signature (cm);
                imsig = mono_method_signature (im);
                if (!cmsig || !imsig) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
+                       mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
                        return FALSE;
                }
 
@@ -4047,7 +4025,7 @@ check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *c
                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 (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                       mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
                        g_free (body_name);
                        g_free (decl_name);
                        return FALSE;
@@ -4071,7 +4049,7 @@ check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *c
                cmsig = mono_method_signature (cm);
                imsig = mono_method_signature (im);
                if (!cmsig || !imsig) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
+                       mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
                        return FALSE;
                }
 
@@ -4128,7 +4106,7 @@ check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *c
                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 (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                       mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
                        g_free (body_name);
                        g_free (decl_name);
                        return FALSE;
@@ -4295,28 +4273,28 @@ verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
                MonoMethod *body = overrides [i * 2 + 1];
 
                if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
+                       mono_class_set_type_load_failure (klass, "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 (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
+                               mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
                        else
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
+                               mono_class_set_type_load_failure (klass, "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 (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
+                               mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
                        else
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
+                               mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
                        return FALSE;
                }
 
                if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that is not extended or implemented by this type"));
+                       mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
                        return FALSE;
                }
 
@@ -4326,7 +4304,7 @@ verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
                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 (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                       mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
                        g_free (body_name);
                        g_free (decl_name);
                        return FALSE;
@@ -4369,7 +4347,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
        ifaces = mono_class_get_implemented_interfaces (klass, &error);
        if (!mono_error_ok (&error)) {
                char *name = mono_type_get_full_name (klass);
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error)));
+               mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error));
                g_free (name);
                mono_error_cleanup (&error);
                return;
@@ -4386,12 +4364,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                mono_class_init (klass->parent);
                mono_class_setup_vtable_full (klass->parent, in_setup);
 
-               if (mono_class_has_failure (klass->parent)) {
-                       char *name = mono_type_get_full_name (klass->parent);
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Parent %s failed to load", name));
-                       g_free (name);
+               if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
                        return;
-               }
 
                max_vtsize += klass->parent->vtable_size;
                cur_slot = klass->parent->vtable_size;
@@ -4425,10 +4399,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                MonoMethod **tmp;
 
                mono_class_setup_vtable_full (gklass, in_setup);
-               if (mono_class_has_failure (gklass)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+               if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
                        return;
-               }
 
                tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
                klass->vtable_size = gklass->vtable_size;
@@ -4436,9 +4408,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                        if (gklass->vtable [i]) {
                                MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), &error);
                                if (!mono_error_ok (&error)) {
-                                       char *err_msg = g_strdup_printf ("Could not inflate method due to %s", mono_error_get_message (&error));
-                                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
-                                       g_free (err_msg);
+                                       mono_class_set_type_load_failure (klass, "Could not inflate method due to %s", mono_error_get_message (&error));
                                        mono_error_cleanup (&error);
                                        return;
                                }
@@ -4511,7 +4481,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                        int dslot;
                        dslot = mono_method_get_vtable_slot (decl);
                        if (dslot == -1) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                               mono_class_set_type_load_failure (klass, "");
                                return;
                        }
 
@@ -4688,7 +4658,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                                        m1sig = mono_method_signature (m1);
 
                                        if (!cmsig || !m1sig) {
-                                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                                               /* FIXME proper error message */
+                                               mono_class_set_type_load_failure (klass, "");
                                                return;
                                        }
 
@@ -4705,7 +4676,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                                                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 (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                                                       mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
                                                        g_free (body_name);
                                                        g_free (decl_name);
                                                        goto fail;
@@ -4790,7 +4761,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                        if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
                                char *type_name = mono_type_get_full_name (klass);
                                char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name));
+                               mono_class_set_type_load_failure (klass, "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;
@@ -4874,7 +4845,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
 fail:
        {
        char *name = mono_type_get_full_name (klass);
-       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("VTable setup of type %s failed", name));
+       mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
        g_free (name);
        if (override_map)
                g_hash_table_destroy (override_map);
@@ -5114,14 +5085,14 @@ mono_class_init (MonoClass *klass)
        }
 
        if (klass->init_pending) {
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Recursive type definition detected"));
+               mono_class_set_type_load_failure (klass, "Recursive type definition detected");
                goto leave;
        }
 
        klass->init_pending = 1;
 
        if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
+               mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
                goto leave;
        }
 
@@ -5130,10 +5101,8 @@ mono_class_init (MonoClass *klass)
                MonoClass *element_class = klass->element_class;
                if (!element_class->inited) 
                        mono_class_init (element_class);
-               if (mono_class_has_failure (element_class)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+               if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
                        goto leave;
-               }
        }
 
        mono_stats.initialized_class_count++;
@@ -5150,10 +5119,8 @@ mono_class_init (MonoClass *klass)
                // FIXME: Why is this needed ?
                if (!mono_class_has_failure (gklass))
                        mono_class_setup_methods (gklass);
-               if (mono_class_has_failure (gklass)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic Type Defintion failed to init"));
+               if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
                        goto leave;
-               }
 
                if (MONO_CLASS_IS_INTERFACE (klass))
                        klass->interface_id = mono_get_unique_iid (klass);
@@ -5237,10 +5204,8 @@ mono_class_init (MonoClass *klass)
                klass->has_cctor = gklass->has_cctor;
 
                mono_class_setup_vtable (gklass);
-               if (mono_class_has_failure (gklass)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+               if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
                        goto leave;
-               }
 
                klass->vtable_size = gklass->vtable_size;
        } else {
@@ -5285,18 +5250,18 @@ mono_class_init (MonoClass *klass)
        }
 
        if (klass->parent) {
+               MonoError parent_error;
+               mono_error_init (&parent_error);
                int first_iface_slot;
                /* This will compute klass->parent->vtable_size for some classes */
                mono_class_init (klass->parent);
-               if (mono_class_has_failure (klass->parent)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+               if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to initialize")) {
                        goto leave;
                }
                if (!klass->parent->vtable_size) {
                        /* FIXME: Get rid of this somehow */
                        mono_class_setup_vtable (klass->parent);
-                       if (mono_class_has_failure (klass->parent)) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize")) {
                                goto leave;
                        }
                }
@@ -5312,7 +5277,7 @@ mono_class_init (MonoClass *klass)
                mono_security_core_clr_check_inheritance (klass);
 
        if (klass->generic_class && !mono_verifier_class_is_valid_generic_instantiation (klass))
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Invalid generic instantiation"));
+               mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
 
        goto leave;
 
@@ -5395,11 +5360,7 @@ mono_class_has_finalizer (MonoClass *klass)
 gboolean
 mono_is_corlib_image (MonoImage *image)
 {
-       /* FIXME: allow the dynamic case for our compilers and with full trust */
-       if (image_is_dynamic (image))
-               return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib");
-       else
-               return image == mono_defaults.corlib;
+       return image == mono_defaults.corlib;
 }
 
 /*
@@ -5548,7 +5509,7 @@ init_com_from_comimport (MonoClass *klass)
                        /* 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 (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_class_set_type_load_failure (klass, "");
                        return;
                }
        }
@@ -5592,7 +5553,8 @@ mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
                if (!parent) {
                        /* set the parent to something useful and safe, but mark the type as broken */
                        parent = mono_defaults.object_class;
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_class_set_type_load_failure (klass, "");
+                       g_assert (parent);
                }
 
                klass->parent = parent;
@@ -5710,8 +5672,8 @@ fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
 static void
 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
 {
-       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (msg));
-       mono_error_set_type_load_class (error, klass, msg);
+       mono_class_set_type_load_failure (klass, "%s", msg);
+       mono_error_set_type_load_class (error, klass, "%s", msg);
 }
 
 /**
@@ -5805,7 +5767,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                        parent = mono_class_inflate_generic_class_checked (parent, context, error);
 
                if (parent == NULL) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+                       mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        goto parent_failure;
                }
 
@@ -5837,7 +5799,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
                if (!mono_error_ok (error)) {
                        /*FIXME implement a mono_class_set_failure_from_mono_error */
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+                       mono_class_set_type_load_failure (klass, "%s",  mono_error_get_message (error));
                        mono_loader_unlock ();
                        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
                        return NULL;
@@ -5858,7 +5820,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                if (!mono_metadata_interfaces_from_typedef_full (
                            image, type_token, &interfaces, &icount, FALSE, context, error)){
 
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+                       mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        mono_loader_unlock ();
                        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
                        return NULL;
@@ -5908,7 +5870,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                if (!enum_basetype) {
                        /*set it to a default value as the whole runtime can't handle this to be null*/
                        klass->cast_class = klass->element_class = mono_defaults.int32_class;
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+                       mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        mono_loader_unlock ();
                        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
                        return NULL;
@@ -5922,7 +5884,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
         * work.
         */
        if (klass->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, klass->generic_container, error)) {
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load generic parameter constrains due to %s", mono_error_get_message (error)));
+               mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
                mono_loader_unlock ();
                mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
                return NULL;
@@ -5974,7 +5936,7 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
                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_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (&error));
                        mono_error_cleanup (&error);
                }
        }
@@ -6212,14 +6174,13 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
        klass->instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
        mono_memory_barrier ();
        klass->size_inited = 1;
-       klass->setup_fields_called = 1;
 
        mono_class_setup_supertypes (klass);
 
        if (count - pos > 0) {
                mono_class_setup_vtable (klass->parent);
                if (mono_class_has_failure (klass->parent))
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
+                       mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
                else
                        setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
        }
@@ -6434,8 +6395,7 @@ mono_ptr_class_get (MonoType *type)
        result->image = el_class->image;
        result->inited = TRUE;
        result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
-       /* Can pointers get boxed? */
-       result->instance_size = sizeof (gpointer);
+       result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
        result->cast_class = result->element_class = el_class;
        result->blittable = TRUE;
 
@@ -6493,8 +6453,7 @@ mono_fnptr_class_get (MonoMethodSignature *sig)
        result->image = mono_defaults.corlib; /* need to fix... */
        result->inited = TRUE;
        result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
-       /* Can pointers get boxed? */
-       result->instance_size = sizeof (gpointer);
+       result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
        result->cast_class = result->element_class = result;
        result->blittable = TRUE;
 
@@ -6655,7 +6614,6 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
        GSList *list, *rootlist = NULL;
        int nsize;
        char *name;
-       gboolean corlib_type = FALSE;
 
        g_assert (rank <= 255);
 
@@ -6697,15 +6655,9 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
                }
        }
 
-       /* for the building corlib use System.Array from it */
-       if (image->assembly && assembly_is_dynamic (image->assembly) && image->assembly_name && strcmp (image->assembly_name, "mscorlib") == 0) {
-               parent = mono_class_load_from_name (image, "System", "Array");
-               corlib_type = TRUE;
-       } else {
-               parent = mono_defaults.array_class;
-               if (!parent->inited)
-                       mono_class_init (parent);
-       }
+       parent = mono_defaults.array_class;
+       if (!parent->inited)
+               mono_class_init (parent);
 
        klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
 
@@ -6736,7 +6688,11 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
                /*Arrays of those two types are invalid.*/
-               mono_class_set_failure (klass, MONO_EXCEPTION_INVALID_PROGRAM, NULL);
+               MonoError prepared_error;
+               mono_error_init (&prepared_error);
+               mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
+               mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
+               mono_error_cleanup (&prepared_error);
        } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
                if (!eclass->ref_info_handle || eclass->wastypebuilder) {
                        g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
@@ -6753,8 +6709,8 @@ 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 (mono_class_has_failure (eclass)) /*FIXME we fail the array type, but we have to let other fields be set.*/
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+       mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
+       /*FIXME we fail the array type, but we have to let other fields be set.*/
 
        klass->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
 
@@ -6805,9 +6761,6 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
        }
        klass->this_arg = klass->byval_arg;
        klass->this_arg.byref = 1;
-       if (corlib_type) {
-               klass->inited = 1;
-       }
 
        klass->generic_container = eclass->generic_container;
 
@@ -6922,7 +6875,7 @@ mono_class_data_size (MonoClass *klass)
                mono_class_init (klass);
        /* This can happen with dynamically created types */
        if (!klass->fields_inited)
-               mono_class_setup_fields_locking (klass);
+               mono_class_setup_fields (klass);
 
        /* in arrays, sizes.class_size is unioned with element_size
         * and arrays have no static fields
@@ -6940,7 +6893,7 @@ mono_class_data_size (MonoClass *klass)
 static MonoClassField *
 mono_class_get_field_idx (MonoClass *klass, int idx)
 {
-       mono_class_setup_fields_locking (klass);
+       mono_class_setup_fields (klass);
        if (mono_class_has_failure (klass))
                return NULL;
 
@@ -7022,7 +6975,7 @@ mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoTyp
 {
        int i;
 
-       mono_class_setup_fields_locking (klass);
+       mono_class_setup_fields (klass);
        if (mono_class_has_failure (klass))
                return NULL;
 
@@ -7060,7 +7013,7 @@ mono_class_get_field_token (MonoClassField *field)
        MonoClass *klass = field->parent;
        int i;
 
-       mono_class_setup_fields_locking (klass);
+       mono_class_setup_fields (klass);
 
        while (klass) {
                if (!klass->fields)
@@ -9140,7 +9093,7 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter)
        if (!iter)
                return NULL;
        if (!*iter) {
-               mono_class_setup_fields_locking (klass);
+               mono_class_setup_fields (klass);
                if (mono_class_has_failure (klass))
                        return NULL;
                /* start from the first */
@@ -9927,21 +9880,63 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p
  *
  * LOCKING: Acquires the loader lock.
  */
-gboolean
-mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
+static gboolean
+mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error)
 {
+       g_assert (boxed_error != NULL);
+
        if (mono_class_has_failure (klass))
                return FALSE;
 
        mono_loader_lock ();
-       klass->exception_type = ex_type;
-       if (ex_data)
-               mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
+       klass->has_failure = 1;
+       mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, boxed_error);
        mono_loader_unlock ();
 
        return TRUE;
 }
 
+gboolean
+mono_class_has_failure (const MonoClass *klass)
+{
+       g_assert (klass != NULL);
+       return klass->has_failure != 0;
+}
+
+
+/**
+ * mono_class_set_type_load_failure:
+ * @klass: class in which the failure was detected
+ * @fmt: Printf-style error message string.
+ *
+ * Collect detected failure informaion in the class for later processing.
+ * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class ()
+ * Note that only the first failure is kept.
+ *
+ * Returns FALSE if a failure was already set on the class, or TRUE otherwise.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
+gboolean
+mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
+{
+       MonoError prepare_error;
+       va_list args;
+
+       if (mono_class_has_failure (klass))
+               return FALSE;
+       
+       mono_error_init (&prepare_error);
+       
+       va_start (args, fmt);
+       mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
+       va_end (args);
+
+       MonoErrorBoxed *box = mono_error_box (&prepare_error, klass->image);
+       mono_error_cleanup (&prepare_error);
+       return mono_class_set_failure (klass, box);
+}
+
 /*
  * mono_class_get_exception_data:
  *
@@ -9949,10 +9944,10 @@ mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
  *
  * LOCKING: Acquires the loader lock.
  */
-gpointer
-mono_class_get_exception_data (MonoClass *klass)
+static gpointer
+mono_class_get_exception_data (const MonoClass *klass)
 {
-       return mono_image_property_lookup (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
+       return mono_image_property_lookup (klass->image, (MonoClass*)klass, MONO_CLASS_PROP_EXCEPTION_DATA);
 }
 
 /**
@@ -9965,6 +9960,8 @@ mono_classes_init (void)
 {
        mono_os_mutex_init (&classes_mutex);
 
+       mono_native_tls_alloc (&setup_fields_tls_id, NULL);
+
        mono_counters_register ("Inflated methods size",
                                                        MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
        mono_counters_register ("Inflated classes",
@@ -9985,6 +9982,8 @@ mono_classes_init (void)
 void
 mono_classes_cleanup (void)
 {
+       mono_native_tls_free (setup_fields_tls_id);
+
        if (global_interface_bitset)
                mono_bitset_free (global_interface_bitset);
        global_interface_bitset = NULL;
@@ -10002,55 +10001,12 @@ mono_classes_cleanup (void)
 MonoException*
 mono_class_get_exception_for_failure (MonoClass *klass)
 {
-       gpointer exception_data = mono_class_get_exception_data (klass);
-
-       switch (mono_class_get_failure(klass)) {
-       case MONO_EXCEPTION_TYPE_LOAD: {
-               MonoString *name;
-               MonoException *ex;
-               char *str = mono_type_get_full_name (klass);
-               char *astr = klass->image->assembly? mono_stringify_assembly_name (&klass->image->assembly->aname): NULL;
-               name = mono_string_new (mono_domain_get (), str);
-               g_free (str);
-               ex = mono_get_exception_type_load (name, astr);
-               g_free (astr);
-               return ex;
-       }
-       case MONO_EXCEPTION_MISSING_METHOD: {
-               char *class_name = (char *)exception_data;
-               char *assembly_name = class_name + strlen (class_name) + 1;
-
-               return mono_get_exception_missing_method (class_name, assembly_name);
-       }
-       case MONO_EXCEPTION_MISSING_FIELD: {
-               char *class_name = (char *)exception_data;
-               char *member_name = class_name + strlen (class_name) + 1;
-
-               return mono_get_exception_missing_field (class_name, member_name);
-       }
-       case MONO_EXCEPTION_FILE_NOT_FOUND: {
-               char *msg_format = (char *)exception_data;
-               char *assembly_name = msg_format + strlen (msg_format) + 1;
-               char *msg = g_strdup_printf (msg_format, assembly_name);
-               MonoException *ex;
-
-               ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), assembly_name));
-
-               g_free (msg);
-
-               return ex;
-       }
-       case MONO_EXCEPTION_BAD_IMAGE: {
-               return mono_get_exception_bad_image_format ((const char *)exception_data);
-       }
-       case MONO_EXCEPTION_INVALID_PROGRAM: {
-               return mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", "");
-       }
-       default: {
-               /* TODO - handle other class related failures */
-               return mono_get_exception_execution_engine ("Unknown class failure");
-       }
-       }
+       if (!mono_class_has_failure (klass))
+               return NULL;
+       MonoError unboxed_error;
+       mono_error_init (&unboxed_error);
+       mono_error_set_for_class_failure (&unboxed_error, klass);
+       return mono_error_convert_to_exception (&unboxed_error);
 }
 
 static gboolean
@@ -10636,7 +10592,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
 
                mono_class_setup_interfaces (gklass, error);
                if (!mono_error_ok (error)) {
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
+                       mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
                        return;
                }
 
@@ -10645,7 +10601,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
                for (i = 0; i < interface_count; i++) {
                        interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
                        if (!mono_error_ok (error)) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
+                               mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
                                return;
                        }
                }
@@ -10682,14 +10638,12 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error)
                MonoClassField *gfield = &gtd->fields [field_idx];
                MonoType *gtype = mono_field_get_type_checked (gfield, error);
                if (!mono_error_ok (error)) {
-                       char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+                       mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
                }
 
                field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
                if (!mono_error_ok (error)) {
-                       char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+                       mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
                }
        } else {
                const char *sig;
@@ -10712,7 +10666,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error)
 
                if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
                        mono_error_set_type_load_class (error, klass, "Could not verify field %s signature", field->name);;
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+                       mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        return;
                }
 
@@ -10724,8 +10678,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error)
 
                field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
                if (!field->type) {
-                       char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+                       mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
                }
        }
 }
@@ -10752,21 +10705,6 @@ mono_field_resolve_flags (MonoClassField *field)
        }
 }
 
-/**
- * mono_class_setup_basic_field_info:
- * @class: The class to initialize
- *
- * Initializes the klass->fields array of fields.
- * Aquires the loader lock.
- */
-static void
-mono_class_setup_basic_field_info_locking (MonoClass *klass)
-{
-       mono_loader_lock ();
-       mono_class_setup_basic_field_info (klass);
-       mono_loader_unlock ();
-}
-
 /**
  * mono_class_get_fields_lazy:
  * @klass: the MonoClass to act on
@@ -10788,7 +10726,7 @@ mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
        if (!iter)
                return NULL;
        if (!*iter) {
-               mono_class_setup_basic_field_info_locking (klass);
+               mono_class_setup_basic_field_info (klass);
                if (!klass->fields)
                        return NULL;
                /* start from the first */