Merge pull request #3936 from kumpera/monoclass_reorg2
[mono.git] / mono / metadata / class.c
index 6218589a88e3c47b96ecacfff2701e05e5035e7a..3f54ba7397c04d4e32e998a530b0d2a32b7bfd1c 100644 (file)
@@ -54,8 +54,9 @@ gboolean mono_print_vtable = FALSE;
 gboolean mono_align_small_structs = FALSE;
 
 /* Statistics */
-guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
-guint32 classes_size, class_ext_size;
+guint32 inflated_classes_size, inflated_methods_size;
+guint32 classes_size, class_ext_size, class_ext_count;
+guint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
 
 /* Low level lock which protects data structures in this module */
 static mono_mutex_t classes_mutex;
@@ -77,6 +78,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 +109,11 @@ 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 MonoNativeTlsKey init_pending_tls_id;
+
 static inline void
 classes_lock (void)
 {
@@ -235,9 +245,10 @@ mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError
                enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error); 
                return_val_if_nok (error, NULL);
 
-               if (enclosing->nested_classes_inited && enclosing->ext) {
+               MonoClassExt *ext = mono_class_get_ext (enclosing);
+               if (enclosing->nested_classes_inited && ext) {
                        /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
-                       for (tmp = enclosing->ext->nested_classes; tmp; tmp = tmp->next) {
+                       for (tmp = ext->nested_classes; tmp; tmp = tmp->next) {
                                res = (MonoClass *)tmp->data;
                                if (strcmp (res->name, name) == 0)
                                        return res;
@@ -497,8 +508,8 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                }
                if (is_recursed)
                        break;
-               if (klass->generic_class) {
-                       MonoGenericClass *gclass = klass->generic_class;
+               if (mono_class_is_ginst (klass)) {
+                       MonoGenericClass *gclass = mono_class_get_generic_class (klass);
                        MonoGenericInst *inst = gclass->context.class_inst;
                        MonoTypeNameFormat nested_format;
                        int i;
@@ -527,7 +538,7 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                                g_string_append_c (str, '>');
                        else
                                g_string_append_c (str, ']');
-               } else if (klass->generic_container &&
+               } else if (mono_class_is_gtd (klass) &&
                           (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
                           (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
                        int i;
@@ -536,10 +547,10 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                                g_string_append_c (str, '<');
                        else
                                g_string_append_c (str, '[');
-                       for (i = 0; i < klass->generic_container->type_argc; i++) {
+                       for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
                                if (i)
                                        g_string_append_c (str, ',');
-                               g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
+                               g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
                        }
                        if (format == MONO_TYPE_NAME_FORMAT_IL) 
                                g_string_append_c (str, '>');
@@ -658,7 +669,7 @@ mono_class_is_open_constructed_type (MonoType *t)
                return t->data.generic_class->context.class_inst->is_open;
        case MONO_TYPE_CLASS:
        case MONO_TYPE_VALUETYPE:
-               return t->data.klass->generic_container != NULL;
+               return mono_class_is_gtd (t->data.klass);
        default:
                return FALSE;
        }
@@ -781,7 +792,7 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
        case MONO_TYPE_CLASS:
        case MONO_TYPE_VALUETYPE: {
                MonoClass *klass = type->data.klass;
-               MonoGenericContainer *container = klass->generic_container;
+               MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
                MonoGenericInst *inst;
                MonoGenericClass *gclass = NULL;
                MonoType *nt;
@@ -818,33 +829,8 @@ mono_generic_class_get_context (MonoGenericClass *gclass)
 MonoGenericContext *
 mono_class_get_context (MonoClass *klass)
 {
-       return klass->generic_class ? mono_generic_class_get_context (klass->generic_class) : NULL;
-}
-
-/*
- * mono_class_get_generic_container:
- *
- *   Return the generic container of KLASS which should be a generic type definition.
- */
-MonoGenericContainer*
-mono_class_get_generic_container (MonoClass *klass)
-{
-       g_assert (klass->is_generic);
-
-       return klass->generic_container;
-}
-
-/*
- * mono_class_get_generic_class:
- *
- *   Return the MonoGenericClass of KLASS, which should be a generic instance.
- */
-MonoGenericClass*
-mono_class_get_generic_class (MonoClass *klass)
-{
-       g_assert (klass->is_inflated);
-
-       return klass->generic_class;
+       MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+       return gklass ? mono_generic_class_get_context (gklass) : NULL;
 }
 
 /*
@@ -1075,7 +1061,7 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
         * 
         */
        if (!((method->is_generic && context->method_inst) || 
-               (method->klass->generic_container && context->class_inst)))
+               (mono_class_is_gtd (method->klass) && context->class_inst)))
                return method;
 
        iresult = g_new0 (MonoMethodInflated, 1);
@@ -1086,14 +1072,12 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
                iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
 
        if (!context->class_inst) {
-               g_assert (!iresult->declaring->klass->generic_class);
-               if (iresult->declaring->klass->generic_container)
-                       iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
-               else if (iresult->declaring->klass->generic_class)
-                       iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
+               g_assert (!mono_class_is_ginst (iresult->declaring->klass));
+               if (mono_class_is_gtd (iresult->declaring->klass))
+                       iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
        }
        /* This can happen with some callers like mono_object_get_virtual_method () */
-       if (!iresult->declaring->klass->generic_container && !iresult->declaring->klass->generic_class)
+       if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
                iresult->context.class_inst = NULL;
 
        MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
@@ -1132,6 +1116,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);
@@ -1142,12 +1135,13 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
                }
        }
 
-       if (!klass_hint || !klass_hint->generic_class ||
-           klass_hint->generic_class->container_class != method->klass ||
-           klass_hint->generic_class->context.class_inst != context->class_inst)
-               klass_hint = NULL;
+       if (klass_hint) {
+               MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
+               if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
+                       klass_hint = NULL;
+       }
 
-       if (method->klass->generic_container)
+       if (mono_class_is_gtd (method->klass))
                result->klass = klass_hint;
 
        if (!result->klass) {
@@ -1222,8 +1216,8 @@ mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
                return NULL;
        if (method->is_generic)
                return &(mono_method_get_generic_container (method)->context);
-       if (method->klass->generic_container)
-               return &method->klass->generic_container->context;
+       if (mono_class_is_gtd (method->klass))
+               return &mono_class_get_generic_container (method->klass)->context;
        return NULL;
 }
 
@@ -1287,32 +1281,32 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
 {
        MonoGenericContainer *container = NULL;
        MonoImage *m = klass->image;
-       const int top = klass->field.count;
-       int i;
+       const int top = mono_class_get_field_count (klass);
+       int i, first_field_idx;
 
        g_assert (klass->enumtype);
 
        mono_error_init (error);
 
-       if (klass->generic_container)
-               container = klass->generic_container;
-       else if (klass->generic_class) {
-               MonoClass *gklass = klass->generic_class->container_class;
+       container = mono_class_try_get_generic_container (klass);
+       if (mono_class_is_ginst (klass)) {
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 
-               container = gklass->generic_container;
+               container = mono_class_get_generic_container (gklass);
                g_assert (container);
        }
 
        /*
         * Fetch all the field information.
         */
+       first_field_idx = mono_class_get_first_field_idx (klass);
        for (i = 0; i < top; i++){
                const char *sig;
                guint32 cols [MONO_FIELD_SIZE];
-               int idx = klass->field.first + i;
+               int idx = first_field_idx + i;
                MonoType *ftype;
 
-               /* klass->field.first and idx points into the fieldptr table */
+               /* first_field_idx and idx points into the fieldptr table */
                mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
 
                if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
@@ -1335,7 +1329,7 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
                if (!ftype)
                        goto fail;
 
-               if (klass->generic_class) {
+               if (mono_class_is_ginst (klass)) {
                        //FIXME do we leak here?
                        ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
                        if (!mono_error_ok (error))
@@ -1352,7 +1346,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 +1366,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,16 +1380,17 @@ 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)
-               return mono_image_set_alloc (klass->generic_class->owner, size);
+       MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+       if (gklass)
+               return mono_image_set_alloc (gklass->owner, size);
        else
                return mono_image_alloc (klass->image, size);
 }
 
-static gpointer
+gpointer
 mono_class_alloc0 (MonoClass *klass, int size)
 {
        gpointer res;
@@ -1450,13 +1407,18 @@ 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->first_field_idx
+ * LOCKING: Acquires the loader lock
  */
 static void
 mono_class_setup_basic_field_info (MonoClass *klass)
 {
+       MonoGenericClass *gklass;
        MonoClassField *field;
+       MonoClassField *fields;
        MonoClass *gtd;
        MonoImage *image;
        int i, top;
@@ -1464,11 +1426,12 @@ mono_class_setup_basic_field_info (MonoClass *klass)
        if (klass->fields)
                return;
 
-       gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+       gklass = mono_class_try_get_generic_class (klass);
+       gtd = gklass ? 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) {
+
+       if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
                /*
                 * This happens when a generic instance of an unfinished generic typebuilder
                 * is used as an element type for creating an array type. We can't initialize
@@ -1481,105 +1444,103 @@ mono_class_setup_basic_field_info (MonoClass *klass)
        if (gtd) {
                mono_class_setup_basic_field_info (gtd);
 
-               top = gtd->field.count;
-               klass->field.first = gtd->field.first;
-               klass->field.count = gtd->field.count;
+               mono_loader_lock ();
+               mono_class_set_field_count (klass, mono_class_get_field_count (gtd));
+               mono_loader_unlock ();
        }
 
-       klass->fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
+       top = mono_class_get_field_count (klass);
+
+       fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
 
        /*
         * Fetch all the field information.
         */
-       for (i = 0; i < top; i++){
-               field = &klass->fields [i];
+       int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
+       for (i = 0; i < top; i++) {
+               field = &fields [i];
                field->parent = klass;
 
                if (gtd) {
                        field->name = mono_field_get_name (&gtd->fields [i]);
                } else {
-                       int idx = klass->field.first + i;
-                       /* klass->field.first and idx points into the fieldptr table */
+                       int idx = first_field_idx + i;
+                       /* first_field_idx and idx points into the fieldptr table */
                        guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
                        /* The name is needed for fieldrefs */
                        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 the klass->fields.
- * LOCKING: Assumes the loader lock is held.
+ * Initializes klass->fields, computes class layout and sizes.
+ * typebuilder_setup_fields () is the corresponding function for dynamic classes.
+ * Sets the following fields in @klass:
+ *  - all the fields initialized by mono_class_init_sizes ()
+ *  - element_class/cast_class (for enums)
+ *  - field->type/offset for all fields
+ *  - fields_inited
+ *
+ * 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;
+       guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
+       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;
+       MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+       MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
 
-       /*
-        * 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) {
+       if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
                /*
                 * This happens when a generic instance of an unfinished generic typebuilder
                 * is used as an element type for creating an array type. We can't initialize
@@ -1590,103 +1551,55 @@ mono_class_setup_fields (MonoClass *klass)
        }
 
        mono_class_setup_basic_field_info (klass);
-       top = klass->field.count;
+       top = mono_class_get_field_count (klass);
 
        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++){
-               int idx = klass->field.first + i;
+       int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
+       for (i = 0; i < top; i++) {
+               int idx = first_field_idx + 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 +1608,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 (mono_class_is_gtd (klass)) {
+                               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,66 +1639,58 @@ 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;
+       if (!mono_class_has_failure (klass))
+               mono_class_layout_fields (klass, instance_size, packing_size, FALSE);
 
-       klass->blittable = blittable;
+       init_list = g_slist_remove (init_list, klass);
+       mono_native_tls_set_value (setup_fields_tls_id, init_list);
+}
 
-       if (klass->enumtype && !mono_class_enum_basetype (klass)) {
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-               return;
+static void
+init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
+{
+       if (cached_info) {
+               klass->instance_size = cached_info->instance_size;
+               klass->sizes.class_size = cached_info->class_size;
+               klass->packing_size = cached_info->packing_size;
+               klass->min_align = cached_info->min_align;
+               klass->blittable = cached_info->blittable;
+               klass->has_references = cached_info->has_references;
+               klass->has_static_refs = cached_info->has_static_refs;
+               klass->no_special_static_fields = cached_info->no_special_static_fields;
        }
-       if (explicit_size && real_size) {
-               instance_size = MAX (real_size, instance_size);
+       else {
+               if (!klass->size_inited)
+                       mono_class_setup_fields (klass);
        }
-
-       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;
 }
+/*
 
-/** 
- * mono_class_setup_fields_locking:
- * @class: The class to initialize
+ * mono_class_init_sizes:
  *
- * 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 ();
-}
-
-/*
- * mono_class_has_references:
+ *   Initializes the size related fields of @klass without loading all field data if possible.
+ * Sets the following fields in @klass:
+ * - instance_size
+ * - sizes.class_size
+ * - packing_size
+ * - min_align
+ * - blittable
+ * - has_references
+ * - has_static_refs
+ * - size_inited
+ * Can fail the class.
  *
- *   Returns whenever @klass->has_references is set, initializing it if needed.
- * Aquires the loader lock.
+ * LOCKING: Acquires the loader lock.
  */
-static gboolean
-mono_class_has_references (MonoClass *klass)
+static void
+mono_class_init_sizes (MonoClass *klass)
 {
-       if (klass->init_pending) {
-               /* Be conservative */
-               return TRUE;
-       } else {
-               mono_class_init (klass);
+       MonoCachedClassInfo cached_info;
+       gboolean has_cached_info;
 
-               return klass->has_references;
-       }
+       has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
+
+       init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
 }
 
 /*
@@ -1834,16 +1710,29 @@ mono_type_get_basic_type_from_generic (MonoType *type)
        return type;
 }
 
+static gboolean
+class_has_references (MonoClass *klass)
+{
+       mono_class_init_sizes (klass);
+
+       /*
+        * has_references is not set if this is called recursively, but this is not a problem since this is only used
+        * during field layout, and instance fields are initialized before static fields, and instance fields can't
+        * embed themselves.
+        */
+       return klass->has_references;
+}
+
 static gboolean
 type_has_references (MonoClass *klass, MonoType *ftype)
 {
-       if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+       if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type (ftype)))))
                return TRUE;
        if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
                MonoGenericParam *gparam = ftype->data.generic_param;
 
                if (gparam->gshared_constraint)
-                       return mono_class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
+                       return class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
        }
        return FALSE;
 }
@@ -1851,28 +1740,59 @@ 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;
-       guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
+       const int top = mono_class_get_field_count (klass);
+       guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
        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 +1801,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 +1831,73 @@ 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);
+       int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
        switch (layout) {
        case TYPE_ATTRIBUTE_AUTO_LAYOUT:
        case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
-
                if (gc_aware_layout)
                        passes = 2;
                else
@@ -1959,10 +1908,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 +1940,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 +1949,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 +1996,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 = first_field_idx + 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 +2037,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 +2049,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 +2058,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 +2075,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 +2126,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 +2213,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)
@@ -2218,21 +2224,18 @@ mono_class_setup_methods (MonoClass *klass)
        if (klass->methods)
                return;
 
-       if (klass->generic_class) {
+       if (mono_class_is_ginst (klass)) {
                MonoError error;
-               MonoClass *gklass = klass->generic_class->container_class;
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 
                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;
+               count = mono_class_get_method_count (gklass);
                methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
 
                for (i = 0; i < count; i++) {
@@ -2240,7 +2243,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);
@@ -2262,7 +2265,7 @@ mono_class_setup_methods (MonoClass *klass)
 
                if (klass->rank == 1 && klass->element_class->rank) {
                        jagged_ctor = TRUE;
-                       klass->method.count ++;
+                       count ++;
                }
 
                if (klass->interface_count) {
@@ -2337,19 +2340,23 @@ mono_class_setup_methods (MonoClass *klass)
 
                for (i = 0; i < klass->interface_count; i++)
                        setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
-       } else {
+       } else if (mono_class_has_static_metadata (klass)) {
                MonoError error;
+               int first_idx = mono_class_get_first_method_idx (klass);
 
-               count = klass->method.count;
+               count = mono_class_get_method_count (klass);
                methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
                for (i = 0; i < count; ++i) {
-                       int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1);
+                       int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + 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);
                        }
                }
+       } else {
+               methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
+               count = 0;
        }
 
        if (MONO_CLASS_IS_INTERFACE (klass)) {
@@ -2364,7 +2371,7 @@ mono_class_setup_methods (MonoClass *klass)
        mono_image_lock (klass->image);
 
        if (!klass->methods) {
-               klass->method.count = count;
+               mono_class_set_method_count (klass, count);
 
                /* Needed because of the double-checking locking pattern */
                mono_memory_barrier ();
@@ -2386,13 +2393,14 @@ MonoMethod*
 mono_class_get_method_by_index (MonoClass *klass, int index)
 {
        MonoError error;
+
+       MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
        /* Avoid calling setup_methods () if possible */
-       if (klass->generic_class && !klass->methods) {
-               MonoClass *gklass = klass->generic_class->container_class;
+       if (gklass && !klass->methods) {
                MonoMethod *m;
 
                m = mono_class_inflate_generic_method_full_checked (
-                               gklass->methods [index], klass, mono_class_get_context (klass), &error);
+                               gklass->container_class->methods [index], klass, mono_class_get_context (klass), &error);
                g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
                /*
                 * If setup_methods () is called later for this class, no duplicates are created,
@@ -2408,7 +2416,7 @@ mono_class_get_method_by_index (MonoClass *klass, int index)
                mono_class_setup_methods (klass);
                if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
                        return NULL;
-               g_assert (index >= 0 && index < klass->method.count);
+               g_assert (index >= 0 && index < mono_class_get_method_count (klass));
                return klass->methods [index];
        }
 }      
@@ -2422,15 +2430,16 @@ mono_class_get_method_by_index (MonoClass *klass, int index)
 MonoMethod*
 mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method)
 {
-       MonoClass *gklass = klass->generic_class->container_class;
-       int i;
+       MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
+       int i, mcount;
 
        g_assert (method->klass == gklass);
 
        mono_class_setup_methods (gklass);
        g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/
 
-       for (i = 0; i < gklass->method.count; ++i) {
+       mcount = mono_class_get_method_count (gklass);
+       for (i = 0; i < mcount; ++i) {
                if (gklass->methods [i] == method) {
                        if (klass->methods) {
                                return klass->methods [i];
@@ -2467,9 +2476,9 @@ mono_class_get_vtable_entry (MonoClass *klass, int offset)
                        return klass->parent->vtable [offset];
        }
 
-       if (klass->generic_class) {
+       if (mono_class_is_ginst (klass)) {
                MonoError error;
-               MonoClass *gklass = klass->generic_class->container_class;
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
                mono_class_setup_vtable (gklass);
                m = gklass->vtable [offset];
 
@@ -2515,26 +2524,26 @@ mono_class_setup_properties (MonoClass *klass)
        guint32 last;
        int first, count;
 
-       if (klass->ext && klass->ext->properties)
+       MonoClassExt *ext = mono_class_get_ext (klass);
+       if (ext && ext->properties)
                return;
 
-       if (klass->generic_class) {
-               MonoClass *gklass = klass->generic_class->container_class;
+       if (mono_class_is_ginst (klass)) {
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 
                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);
+               MonoClassExt *gext = mono_class_get_ext (gklass);
+               properties = mono_class_new0 (klass, MonoProperty, gext->property.count + 1);
 
-               for (i = 0; i < gklass->ext->property.count; i++) {
+               for (i = 0; i < gext->property.count; i++) {
                        MonoError error;
                        MonoProperty *prop = &properties [i];
 
-                       *prop = gklass->ext->properties [i];
+                       *prop = gext->properties [i];
 
                        if (prop->get)
                                prop->get = mono_class_inflate_generic_method_full_checked (
@@ -2547,8 +2556,8 @@ mono_class_setup_properties (MonoClass *klass)
                        prop->parent = klass;
                }
 
-               first = gklass->ext->property.first;
-               count = gklass->ext->property.count;
+               first = gext->property.first;
+               count = gext->property.count;
        } else {
                first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
                count = last - first;
@@ -2567,6 +2576,7 @@ mono_class_setup_properties (MonoClass *klass)
                        properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
 
                        startm = mono_metadata_methods_from_property (klass->image, i, &endm);
+                       int first_idx = mono_class_get_first_method_idx (klass);
                        for (j = startm; j < endm; ++j) {
                                MonoMethod *method;
 
@@ -2578,7 +2588,7 @@ mono_class_setup_properties (MonoClass *klass)
                                        method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
                                        mono_error_cleanup (&error); /* FIXME don't swallow this error */
                                } else {
-                                       method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
+                                       method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
                                }
 
                                switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
@@ -2596,23 +2606,24 @@ mono_class_setup_properties (MonoClass *klass)
        }
 
        mono_class_alloc_ext (klass);
+       ext = mono_class_get_ext (klass);
 
        mono_image_lock (klass->image);
 
-       if (klass->ext->properties) {
+       if (ext->properties) {
                /* We leak 'properties' which was allocated from the image mempool */
                mono_image_unlock (klass->image);
                return;
        }
 
-       klass->ext->property.first = first;
-       klass->ext->property.count = count;
+       ext->property.first = first;
+       ext->property.count = count;
 
        /* Flush any pending writes as we do double checked locking on klass->ext->properties */
        mono_memory_barrier ();
 
        /* Leave this assignment as the last op in the function */
-       klass->ext->properties = properties;
+       ext->properties = properties;
 
        mono_image_unlock (klass->image);
 }
@@ -2648,21 +2659,21 @@ mono_class_setup_events (MonoClass *klass)
        guint32 last;
        MonoEvent *events;
 
-       if (klass->ext && klass->ext->events)
+       MonoClassExt *ext = mono_class_get_ext (klass);
+       if (ext && ext->events)
                return;
 
-       if (klass->generic_class) {
-               MonoClass *gklass = klass->generic_class->container_class;
+       if (mono_class_is_ginst (klass)) {
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
                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;
+               MonoClassExt *gext = mono_class_get_ext (gklass);
+               first = gext->event.first;
+               count = gext->event.count;
 
                events = mono_class_new0 (klass, MonoEvent, count);
 
@@ -2672,7 +2683,7 @@ mono_class_setup_events (MonoClass *klass)
                for (i = 0; i < count; i++) {
                        MonoError error;
                        MonoEvent *event = &events [i];
-                       MonoEvent *gevent = &gklass->ext->events [i];
+                       MonoEvent *gevent = &gext->events [i];
 
                        mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok
 
@@ -2697,7 +2708,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;
                        }
                }
@@ -2712,6 +2722,7 @@ mono_class_setup_events (MonoClass *klass)
                        event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
 
                        startm = mono_metadata_methods_from_event (klass->image, i, &endm);
+                       int first_idx = mono_class_get_first_method_idx (klass);
                        for (j = startm; j < endm; ++j) {
                                MonoMethod *method;
 
@@ -2723,7 +2734,7 @@ mono_class_setup_events (MonoClass *klass)
                                        method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
                                        mono_error_cleanup (&error); /* FIXME don't swallow this error */
                                } else {
-                                       method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
+                                       method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
                                }
 
                                switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
@@ -2761,22 +2772,23 @@ mono_class_setup_events (MonoClass *klass)
        }
 
        mono_class_alloc_ext (klass);
+       ext = mono_class_get_ext (klass);
 
        mono_image_lock (klass->image);
 
-       if (klass->ext->events) {
+       if (ext->events) {
                mono_image_unlock (klass->image);
                return;
        }
 
-       klass->ext->event.first = first;
-       klass->ext->event.count = count;
+       ext->event.first = first;
+       ext->event.count = count;
 
        /* Flush any pending writes as we do double checked locking on klass->ext.events */
        mono_memory_barrier ();
 
        /* Leave this assignment as the last op in the function */
-       klass->ext->events = events;
+       ext->events = events;
 
        mono_image_unlock (klass->image);
 }
@@ -2822,7 +2834,7 @@ mono_unload_interface_id (MonoClass *klass)
  * LOCKING: Acquires the classes lock.
  * Returns: The new ID.
  */
-static guint
+static guint32
 mono_get_unique_iid (MonoClass *klass)
 {
        int iid;
@@ -2845,7 +2857,7 @@ mono_get_unique_iid (MonoClass *klass)
        }
        mono_bitset_set (global_interface_bitset, iid);
        /* set the bit also in the per-image set */
-       if (!klass->generic_class) {
+       if (!mono_class_is_ginst (klass)) {
                if (klass->image->interface_bitset) {
                        if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
                                MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
@@ -2864,8 +2876,9 @@ mono_get_unique_iid (MonoClass *klass)
        if (mono_print_vtable) {
                int generic_id;
                char *type_name = mono_type_full_name (&klass->byval_arg);
-               if (klass->generic_class && !klass->generic_class->context.class_inst->is_open) {
-                       generic_id = klass->generic_class->context.class_inst->id;
+               MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+               if (gklass && !gklass->context.class_inst->is_open) {
+                       generic_id = gklass->context.class_inst->id;
                        g_assert (generic_id != 0);
                } else {
                        generic_id = 0;
@@ -2875,7 +2888,9 @@ mono_get_unique_iid (MonoClass *klass)
        }
 #endif
 
-       g_assert (iid <= 65535);
+       /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
+        * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
+       g_assert (iid < INT_MAX);
        return iid;
 }
 
@@ -2989,7 +3004,7 @@ print_implemented_interfaces (MonoClass *klass) {
                printf ("  [%03d][UUID %03d][SLOT %03d][SIZE  %03d] interface %s.%s\n", i,
                                klass->interfaces_packed [i]->interface_id,
                                klass->interface_offsets_packed [i],
-                               klass->interfaces_packed [i]->method.count,
+                               mono_class_get_method_count (klass->interfaces_packed [i]),
                                klass->interfaces_packed [i]->name_space,
                                klass->interfaces_packed [i]->name );
        printf ("Interface flags: ");
@@ -3028,7 +3043,7 @@ print_implemented_interfaces (MonoClass *klass) {
                                printf ("  [%03d][UUID %03d][SLOT %03d][SIZE  %03d] interface %s.%s\n", i,
                                                ic->interface_id,
                                                mono_class_interface_offset (klass, ic),
-                                               ic->method.count,
+                                               mono_class_get_method_count (ic),
                                                ic->name_space,
                                                ic->name );
                        }
@@ -3078,6 +3093,12 @@ fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *ecla
                valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
 }
 
+static GENERATE_GET_CLASS_WITH_CACHE (generic_icollection, System.Collections.Generic, ICollection`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerable, System.Collections.Generic, IEnumerable`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerator, System.Collections.Generic, IEnumerator`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlylist, System.Collections.Generic, IReadOnlyList`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlycollection, System.Collections.Generic, IReadOnlyCollection`1)
+
 /* this won't be needed once bug #325495 is completely fixed
  * though we'll need something similar to know which interfaces to allow
  * in arrays when they'll be lazyly created
@@ -3095,11 +3116,11 @@ static MonoClass**
 get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator)
 {
        MonoClass *eclass = klass->element_class;
-       static MonoClass* generic_icollection_class = NULL;
-       static MonoClass* generic_ienumerable_class = NULL;
-       static MonoClass* generic_ienumerator_class = NULL;
-       static MonoClass* generic_ireadonlylist_class = NULL;
-       static MonoClass* generic_ireadonlycollection_class = NULL;
+       MonoClass* generic_icollection_class;
+       MonoClass* generic_ienumerable_class;
+       MonoClass* generic_ienumerator_class;
+       MonoClass* generic_ireadonlylist_class;
+       MonoClass* generic_ireadonlycollection_class;
        MonoClass *valuetype_types[2] = { NULL, NULL };
        MonoClass **interfaces = NULL;
        int i, nifaces, interface_count, real_count, original_rank;
@@ -3115,11 +3136,12 @@ get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enume
        eclass_is_valuetype = FALSE;
        original_rank = eclass->rank;
        if (klass->byval_arg.type != MONO_TYPE_SZARRAY) {
-               if (klass->generic_class && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0)  {
+               MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+               if (gklass && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0)        {
                        /*
                         * For a Enumerator<T[]> we need to get the list of interfaces for T.
                         */
-                       eclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+                       eclass = mono_class_from_mono_type (gklass->context.class_inst->type_argv [0]);
                        original_rank = eclass->rank;
                        if (!eclass->rank)
                                eclass = eclass->element_class;
@@ -3137,18 +3159,11 @@ get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enume
         */
        all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
 
-       if (!generic_icollection_class) {
-               generic_icollection_class = mono_class_load_from_name (mono_defaults.corlib,
-                       "System.Collections.Generic", "ICollection`1");
-               generic_ienumerable_class = mono_class_load_from_name (mono_defaults.corlib,
-                       "System.Collections.Generic", "IEnumerable`1");
-               generic_ienumerator_class = mono_class_load_from_name (mono_defaults.corlib,
-                       "System.Collections.Generic", "IEnumerator`1");
-               generic_ireadonlylist_class = mono_class_load_from_name (mono_defaults.corlib,
-                       "System.Collections.Generic", "IReadOnlyList`1");
-               generic_ireadonlycollection_class = mono_class_load_from_name (mono_defaults.corlib,
-                       "System.Collections.Generic", "IReadOnlyCollection`1");
-       }
+       generic_icollection_class = mono_class_get_generic_icollection_class ();
+       generic_ienumerable_class = mono_class_get_generic_ienumerable_class ();
+       generic_ienumerator_class = mono_class_get_generic_ienumerator_class ();
+       generic_ireadonlylist_class = mono_class_get_generic_ireadonlylist_class ();
+       generic_ireadonlycollection_class = mono_class_get_generic_ireadonlycollection_class ();
 
        mono_class_init (eclass);
 
@@ -3324,7 +3339,7 @@ find_array_interface (MonoClass *klass, const char *name)
 static int
 count_virtual_methods (MonoClass *klass)
 {
-       int i, count = 0;
+       int i, mcount, vcount = 0;
        guint32 flags;
        klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
 
@@ -3333,20 +3348,23 @@ count_virtual_methods (MonoClass *klass)
                if (mono_class_has_failure (klass))
                        return -1;
 
-               for (i = 0; i < klass->method.count; ++i) {
+               mcount = mono_class_get_method_count (klass);
+               for (i = 0; i < mcount; ++i) {
                        flags = klass->methods [i]->flags;
                        if (flags & METHOD_ATTRIBUTE_VIRTUAL)
-                               ++count;
+                               ++vcount;
                }
        } else {
-               for (i = 0; i < klass->method.count; ++i) {
-                       flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
+               int first_idx = mono_class_get_first_method_idx (klass);
+               mcount = mono_class_get_method_count (klass);
+               for (i = 0; i < mcount; ++i) {
+                       flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
 
                        if (flags & METHOD_ATTRIBUTE_VIRTUAL)
-                               ++count;
+                               ++vcount;
                }
        }
-       return count;
+       return vcount;
 }
 
 static int
@@ -3514,15 +3532,16 @@ mono_class_interface_match (const uint8_t *bitmap, int id)
 #endif
 
 /*
- * 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.
+ * LOCKING: Acquires the loader lock.
  */
 static int
 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
 {
        MonoError error;
        MonoClass *k, *ic;
-       int i, j, max_iid, num_ifaces;
+       int i, j, num_ifaces;
+       guint32 max_iid;
        MonoClass **interfaces_full = NULL;
        int *interface_offsets_full = NULL;
        GPtrArray *ifaces;
@@ -3532,6 +3551,8 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
        int num_array_interfaces;
        int is_enumerator = FALSE;
 
+       mono_loader_lock ();
+
        mono_class_setup_supertypes (klass);
        /* 
         * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
@@ -3546,12 +3567,12 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
        ifaces_array = g_new0 (GPtrArray *, klass->idepth);
        for (j = 0; j < klass->idepth; j++) {
                k = klass->supertypes [j];
+               g_assert (k);
                num_ifaces += k->interface_count;
                for (i = 0; i < k->interface_count; i++) {
                        ic = k->interfaces [i];
 
-                       if (!ic->inited)
-                               mono_class_init (ic);
+                       mono_class_init (ic);
 
                        if (max_iid < ic->interface_id)
                                max_iid = ic->interface_id;
@@ -3559,7 +3580,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;
@@ -3588,14 +3609,13 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                if (max_iid < klass->interface_id)
                        max_iid = klass->interface_id;
        }
-       klass->max_interface_id = max_iid;
+
        /* compute vtable offset for interfaces */
        interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
        interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
 
-       for (i = 0; i < num_ifaces; i++) {
+       for (i = 0; i < num_ifaces; i++)
                interface_offsets_full [i] = -1;
-       }
 
        /* skip the current class */
        for (j = 0; j < klass->idepth - 1; j++) {
@@ -3626,7 +3646,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;
@@ -3669,7 +3689,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                        for (i = 0; i < num_array_interfaces; ++i) {
                                int offset;
                                ic = array_interfaces [i];
-                               if (ic->generic_class->container_class == mono_defaults.generic_ilist_class)
+                               if (mono_class_get_generic_class (ic)->container_class == mono_defaults.generic_ilist_class)
                                        offset = ilist_offset;
                                else if (strcmp (ic->name, "ICollection`1") == 0)
                                        offset = icollection_offset;
@@ -3688,11 +3708,12 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
        }
 
        for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
-               if (interface_offsets_full [i] != -1) {
+               if (interface_offsets_full [i] != -1)
                        interface_offsets_count ++;
-               }
        }
 
+       /* Publish the data */
+       klass->max_interface_id = max_iid;
        /*
         * We might get called multiple times:
         * - mono_class_init ()
@@ -3717,7 +3738,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
 #endif
                for (i = 0; i < interface_offsets_count; i++) {
-                       int id = interfaces_full [i]->interface_id;
+                       guint32 id = interfaces_full [i]->interface_id;
                        bitmap [id >> 3] |= (1 << (id & 7));
                        klass->interfaces_packed [i] = interfaces_full [i];
                        klass->interface_offsets_packed [i] = interface_offsets_full [i];
@@ -3733,8 +3754,9 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                klass->interface_bitmap = bitmap;
 #endif
        }
-
 end:
+       mono_loader_unlock ();
+
        g_free (interfaces_full);
        g_free (interface_offsets_full);
        g_free (array_interfaces);
@@ -3747,7 +3769,7 @@ end:
        
        //printf ("JUST DONE: ");
        //print_implemented_interfaces (klass);
+
        return cur_slot;
 }
 
@@ -3765,11 +3787,7 @@ end:
 void
 mono_class_setup_interface_offsets (MonoClass *klass)
 {
-       mono_loader_lock ();
-
        setup_interface_offsets (klass, 0, FALSE);
-
-       mono_loader_unlock ();
 }
 
 /*Checks if @klass has @parent as one of it's parents type gtd
@@ -3796,18 +3814,17 @@ mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
 {
        MonoGenericInst *ginst;
        int i;
-       if (!klass->generic_class) {
+
+       if (!mono_class_is_ginst (klass)) {
                mono_class_setup_vtable_full (klass, in_setup);
                return !mono_class_has_failure (klass);
        }
 
        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, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
                return FALSE;
-       }
 
-       ginst = klass->generic_class->context.class_inst;
+       ginst = mono_class_get_generic_class (klass)->context.class_inst;
        for (i = 0; i < ginst->type_argc; ++i) {
                MonoClass *arg;
                if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
@@ -3817,7 +3834,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 +3849,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.
  */
@@ -3877,7 +3895,7 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
        mono_stats.generic_vtable_count ++;
        in_setup = g_list_prepend (in_setup, klass);
 
-       if (klass->generic_class) {
+       if (mono_class_is_ginst (klass)) {
                if (!mono_class_check_vtable_constraints (klass, in_setup)) {
                        mono_loader_unlock ();
                        g_list_remove (in_setup, klass);
@@ -3885,9 +3903,9 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
                }
 
                context = mono_class_get_context (klass);
-               type_token = klass->generic_class->container_class->type_token;
+               type_token = mono_class_get_generic_class (klass)->container_class->type_token;
        } else {
-               context = (MonoGenericContext *) klass->generic_container;
+               context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
                type_token = klass->type_token;
        }
 
@@ -3900,7 +3918,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 +3931,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 +4047,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 +4065,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 +4089,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 +4146,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;
@@ -4206,7 +4224,7 @@ mono_method_try_get_vtable_index (MonoMethod *method)
 static void
 mono_class_verify_vtable (MonoClass *klass)
 {
-       int i;
+       int i, count;
        char *full_name = mono_type_full_name (&klass->byval_arg);
 
        printf ("*** Verifying VTable of class '%s' \n", full_name);
@@ -4216,7 +4234,8 @@ mono_class_verify_vtable (MonoClass *klass)
        if (!klass->methods)
                return;
 
-       for (i = 0; i < klass->method.count; ++i) {
+       count = mono_class_method_count (klass);
+       for (i = 0; i < count; ++i) {
                MonoMethod *cm = klass->methods [i];
                int slot;
 
@@ -4246,8 +4265,9 @@ mono_class_verify_vtable (MonoClass *klass)
 #endif
 
 static void
-print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
-       int index;
+print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
+{
+       int index, mcount;
        char *method_signature;
        char *type_name;
        
@@ -4268,7 +4288,8 @@ print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, Mono
                g_free (name);
                return;
        }
-       for (index = 0; index < klass->method.count; ++index) {
+       mcount = mono_class_get_method_count (klass);
+       for (index = 0; index < mcount; ++index) {
                MonoMethod *cm = klass->methods [index];
                method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
 
@@ -4295,28 +4316,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 +4347,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;
@@ -4350,7 +4371,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
        MonoError error;
        MonoClass *k, *ic;
        MonoMethod **vtable;
-       int i, max_vtsize = 0, max_iid, cur_slot = 0;
+       int i, max_vtsize = 0, cur_slot = 0;
+       guint32 max_iid;
        GPtrArray *ifaces = NULL;
        GHashTable *override_map = NULL;
        MonoMethod *cm;
@@ -4369,14 +4391,14 @@ 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;
        } else if (ifaces) {
                for (i = 0; i < ifaces->len; i++) {
                        MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
-                       max_vtsize += ic->method.count;
+                       max_vtsize += mono_class_get_method_count (ic);
                }
                g_ptr_array_free (ifaces, TRUE);
                ifaces = NULL;
@@ -4386,18 +4408,14 @@ 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;
        }
 
-       max_vtsize += klass->method.count;
+       max_vtsize += mono_class_get_method_count (klass);
 
        /*Array have a slot for stelemref*/
        if (mono_class_need_stelemref_method (klass)) {
@@ -4419,16 +4437,14 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
        DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
 
        /* Optimized version for generic instances */
-       if (klass->generic_class) {
+       if (mono_class_is_ginst (klass)) {
                MonoError error;
-               MonoClass *gklass = klass->generic_class->container_class;
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
                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 +4452,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;
                                }
@@ -4450,7 +4464,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
 
                /* Have to set method->slot for abstract virtual methods */
                if (klass->methods && gklass->methods) {
-                       for (i = 0; i < klass->method.count; ++i)
+                       int mcount = mono_class_get_method_count (klass);
+                       for (i = 0; i < mcount; ++i)
                                if (klass->methods [i]->slot == -1)
                                        klass->methods [i]->slot = gklass->methods [i]->slot;
                }
@@ -4481,7 +4496,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                                
                                mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
                                TRACE_INTERFACE_VTABLE (printf ("    +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
-                               for (j = 0; j < parent_interface->method.count && !mono_class_has_failure (klass); j++) {
+                               int mcount = mono_class_get_method_count (parent_interface);
+                               for (j = 0; j < mcount && !mono_class_has_failure (klass); j++) {
                                        vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
                                        TRACE_INTERFACE_VTABLE (printf ("    --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
                                                        parent_interface_offset + j, parent_interface_offset, j,
@@ -4511,7 +4527,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;
                        }
 
@@ -4576,7 +4592,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                }
                
                // Loop on all interface methods...
-               for (im_index = 0; im_index < ic->method.count; im_index++) {
+               int mcount = mono_class_get_method_count (ic);
+               for (im_index = 0; im_index < mcount; im_index++) {
                        MonoMethod *im = ic->methods [im_index];
                        int im_slot = ic_offset + im->slot;
                        MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
@@ -4642,7 +4659,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
        // it can happen (for injected generic array interfaces) that the same slot is
        // processed multiple times (those interfaces have overlapping slots), and it
        // will not always be the first pass the one that fills the slot.
-       if (! (klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+       if (!mono_class_is_abstract (klass)) {
                for (i = 0; i < klass->interface_offsets_count; i++) {
                        int ic_offset;
                        int im_index;
@@ -4650,7 +4667,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                        ic = klass->interfaces_packed [i];
                        ic_offset = mono_class_interface_offset (klass, ic);
                        
-                       for (im_index = 0; im_index < ic->method.count; im_index++) {
+                       int mcount = mono_class_get_method_count (ic);
+                       for (im_index = 0; im_index < mcount; im_index++) {
                                MonoMethod *im = ic->methods [im_index];
                                int im_slot = ic_offset + im->slot;
                                
@@ -4688,7 +4706,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 +4724,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;
@@ -4785,12 +4804,12 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
        virt_methods = NULL;
 
        /* Ensure that all vtable slots are filled with concrete instance methods */
-       if (!(klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+       if (!mono_class_is_abstract (klass)) {
                for (i = 0; i < cur_slot; ++i) {
                        if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
                                char *type_name = mono_type_get_full_name (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;
@@ -4798,8 +4817,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                }
        }
 
-       if (klass->generic_class) {
-               MonoClass *gklass = klass->generic_class->container_class;
+       if (mono_class_is_ginst (klass)) {
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 
                mono_class_init (gklass);
 
@@ -4874,7 +4893,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);
@@ -4900,23 +4919,24 @@ mono_method_get_vtable_slot (MonoMethod *method)
                        return -1;
                if (method->slot == -1) {
                        MonoClass *gklass;
-                       int i;
+                       int i, mcount;
 
-                       if (!method->klass->generic_class) {
+                       if (!mono_class_is_ginst (method->klass)) {
                                g_assert (method->is_inflated);
                                return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
                        }
 
                        /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
-                       g_assert (method->klass->generic_class);
-                       gklass = method->klass->generic_class->container_class;
+                       g_assert (mono_class_is_ginst (method->klass));
+                       gklass = mono_class_get_generic_class (method->klass)->container_class;
                        mono_class_setup_methods (method->klass);
                        g_assert (method->klass->methods);
-                       for (i = 0; i < method->klass->method.count; ++i) {
+                       mcount = mono_class_get_method_count (method->klass);
+                       for (i = 0; i < mcount; ++i) {
                                if (method->klass->methods [i] == method)
                                        break;
                        }
-                       g_assert (i < method->klass->method.count);
+                       g_assert (i < mcount);
                        g_assert (gklass->methods);
                        method->slot = gklass->methods [i]->slot;
                }
@@ -4987,13 +5007,14 @@ static GenericArrayMethodInfo *generic_array_method_info = NULL;
 static int
 generic_array_methods (MonoClass *klass)
 {
-       int i, count_generic = 0;
+       int i, count_generic = 0, mcount;
        GList *list = NULL, *tmp;
        if (generic_array_method_num)
                return generic_array_method_num;
        mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
        g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
-       for (i = 0; i < klass->parent->method.count; i++) {
+       mcount = mono_class_get_method_count (klass->parent);
+       for (i = 0; i < mcount; i++) {
                MonoMethod *m = klass->parent->methods [i];
                if (!strncmp (m->name, "InternalArray__", 15)) {
                        count_generic++;
@@ -5050,7 +5071,7 @@ setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **met
        int i;
 
        tmp_context.class_inst = NULL;
-       tmp_context.method_inst = iface->generic_class->context.class_inst;
+       tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
        //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
 
        for (i = 0; i < generic_array_method_num; i++) {
@@ -5080,21 +5101,30 @@ concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
 
 /**
  * mono_class_init:
- * @class: the class to initialize
+ * @klass: the class to initialize
  *
  *   Compute the instance_size, class_size and other infos that cannot be 
  * computed at mono_class_get() time. Also compute vtable_size if possible. 
  * Returns TRUE on success or FALSE if there was a problem in loading
- * the type (incorrect assemblies, missing assemblies, methods, etc). 
+ * the type (incorrect assemblies, missing assemblies, methods, etc).
+ * Initializes the following fields in @klass:
+ * - all the fields initialized by mono_class_init_sizes ()
+ * - has_cctor
+ * - ghcimpl
+ * - inited
  *
  * LOCKING: Acquires the loader lock.
  */
 gboolean
 mono_class_init (MonoClass *klass)
 {
-       int i;
+       int i, vtable_size = 0, array_method_count = 0;
        MonoCachedClassInfo cached_info;
        gboolean has_cached_info;
+       gboolean locked = FALSE;
+       gboolean ghcimpl = FALSE;
+       gboolean has_cctor = FALSE;
+       int first_iface_slot = 0;
        
        g_assert (klass);
 
@@ -5104,59 +5134,45 @@ mono_class_init (MonoClass *klass)
 
        /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
 
-       /* We do everything inside the lock to prevent races */
-       mono_loader_lock ();
-
-       if (klass->inited || mono_class_has_failure (klass)) {
-               mono_loader_unlock ();
-               /* Somebody might have gotten in before us */
-               return !mono_class_has_failure (klass);
-       }
-
-       if (klass->init_pending) {
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Recursive type definition detected"));
+       /*
+        * This function can recursively call itself.
+        */
+       GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
+       if (g_slist_find (init_list, klass)) {
+               mono_class_set_type_load_failure (klass, "Recursive type definition detected");
                goto leave;
        }
+       init_list = g_slist_prepend (init_list, klass);
+       mono_native_tls_set_value (init_pending_tls_id, init_list);
 
-       klass->init_pending = 1;
+       /*
+        * 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 (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;
        }
 
-
        if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
                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++;
 
-       if (klass->generic_class && !klass->generic_class->is_dynamic) {
-               MonoClass *gklass = klass->generic_class->container_class;
-
-               mono_stats.generic_class_count++;
-
-               klass->method = gklass->method;
-               klass->field = gklass->field;
+       if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 
                mono_class_init (gklass);
-               // 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);
+               mono_class_setup_interface_id (klass);
        }
 
        if (klass->parent && !klass->parent->inited)
@@ -5164,38 +5180,10 @@ mono_class_init (MonoClass *klass)
 
        has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
 
-       if (klass->generic_class || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
-               klass->nested_classes_inited = TRUE;
-
-       /*
-        * Computes the size used by the fields, and their locations
-        */
-       if (has_cached_info) {
-               klass->instance_size = cached_info.instance_size;
-               klass->sizes.class_size = cached_info.class_size;
-               klass->packing_size = cached_info.packing_size;
-               klass->min_align = cached_info.min_align;
-               klass->blittable = cached_info.blittable;
-               klass->has_references = cached_info.has_references;
-               klass->has_static_refs = cached_info.has_static_refs;
-               klass->no_special_static_fields = cached_info.no_special_static_fields;
-       }
-       else
-               if (!klass->size_inited){
-                       mono_class_setup_fields (klass);
-                       if (mono_class_has_failure (klass))
-                               goto leave;
-               }
-                               
-       /* Initialize arrays */
-       if (klass->rank) {
-               klass->method.count = 3 + (klass->rank > 1? 2: 1);
-
-               if (klass->interface_count) {
-                       int count_generic = generic_array_methods (klass);
-                       klass->method.count += klass->interface_count * count_generic;
-               }
-       }
+       /* Compute instance size etc. */
+       init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
+       if (mono_class_has_failure (klass))
+               goto leave;
 
        mono_class_setup_supertypes (klass);
 
@@ -5209,11 +5197,9 @@ mono_class_init (MonoClass *klass)
         */
        if (has_cached_info) {
                /* AOT case */
-               klass->vtable_size = cached_info.vtable_size;
-               klass->has_finalize = cached_info.has_finalize;
-               klass->has_finalize_inited = TRUE;
-               klass->ghcimpl = cached_info.ghcimpl;
-               klass->has_cctor = cached_info.has_cctor;
+               vtable_size = cached_info.vtable_size;
+               ghcimpl = cached_info.ghcimpl;
+               has_cctor = cached_info.has_cctor;
        } else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
                /* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
                 * The first slot if for array with.
@@ -5226,23 +5212,22 @@ mono_class_init (MonoClass *klass)
                if (!szarray_vtable_size [slot]) {
                        mono_class_setup_vtable (klass);
                        szarray_vtable_size [slot] = klass->vtable_size;
+                       vtable_size = klass->vtable_size;
                } else {
-                       klass->vtable_size = szarray_vtable_size[slot];
+                       vtable_size = szarray_vtable_size[slot];
                }
-       } else if (klass->generic_class && !MONO_CLASS_IS_INTERFACE (klass)) {
-               MonoClass *gklass = klass->generic_class->container_class;
+       } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE (klass)) {
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 
                /* Generic instance case */
-               klass->ghcimpl = gklass->ghcimpl;
-               klass->has_cctor = gklass->has_cctor;
+               ghcimpl = gklass->ghcimpl;
+               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;
+               vtable_size = gklass->vtable_size;
        } else {
                /* General case */
 
@@ -5262,21 +5247,28 @@ mono_class_init (MonoClass *klass)
                if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) {
                        MonoMethod *cmethod = NULL;
 
-                       if (klass->type_token && !image_is_dynamic(klass->image)) {
+                       if (mono_class_is_ginst (klass)) {
+                               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
+
+                               /* Generic instance case */
+                               ghcimpl = gklass->ghcimpl;
+                               has_cctor = gklass->has_cctor;
+                       } else if (klass->type_token && !image_is_dynamic(klass->image)) {
                                cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
                                /* The find_method function ignores the 'flags' argument */
                                if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
-                                       klass->has_cctor = 1;
+                                       has_cctor = 1;
                        } else {
                                mono_class_setup_methods (klass);
                                if (mono_class_has_failure (klass))
                                        goto leave;
 
-                               for (i = 0; i < klass->method.count; ++i) {
+                               int mcount = mono_class_get_method_count (klass);
+                               for (i = 0; i < mcount; ++i) {
                                        MonoMethod *method = klass->methods [i];
                                        if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
                                                (strcmp (".cctor", method->name) == 0)) {
-                                               klass->has_cctor = 1;
+                                               has_cctor = 1;
                                                break;
                                        }
                                }
@@ -5284,45 +5276,79 @@ mono_class_init (MonoClass *klass)
                }
        }
 
-       if (klass->parent) {
-               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);
-                       goto leave;
+       if (klass->rank) {
+               array_method_count = 3 + (klass->rank > 1? 2: 1);
+
+               if (klass->interface_count) {
+                       int count_generic = generic_array_methods (klass);
+                       array_method_count += klass->interface_count * count_generic;
                }
-               if (!klass->parent->vtable_size) {
-                       /* FIXME: Get rid of this somehow */
+       }
+
+       if (klass->parent) {
+               if (!klass->parent->vtable_size)
                        mono_class_setup_vtable (klass->parent);
-                       if (mono_class_has_failure (klass->parent)) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-                               goto leave;
-                       }
-               }
+               if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
+                       goto leave;
+               g_assert (klass->parent->vtable_size);
                first_iface_slot = klass->parent->vtable_size;
                if (mono_class_need_stelemref_method (klass))
                        ++first_iface_slot;
-               setup_interface_offsets (klass, first_iface_slot, TRUE);
-       } else {
-               setup_interface_offsets (klass, 0, TRUE);
        }
 
+       /*
+        * Do the actual changes to @klass inside the loader lock
+        */
+       mono_loader_lock ();
+       locked = TRUE;
+
+       if (klass->inited || mono_class_has_failure (klass)) {
+               mono_loader_unlock ();
+               /* Somebody might have gotten in before us */
+               return !mono_class_has_failure (klass);
+       }
+
+       mono_stats.initialized_class_count++;
+
+       if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
+               mono_stats.generic_class_count++;
+
+       if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
+               klass->nested_classes_inited = TRUE;
+       klass->ghcimpl = ghcimpl;
+       klass->has_cctor = has_cctor;
+       if (vtable_size)
+               klass->vtable_size = vtable_size;
+       if (has_cached_info) {
+               klass->has_finalize = cached_info.has_finalize;
+               klass->has_finalize_inited = TRUE;
+       }
+       if (klass->rank)
+               mono_class_set_method_count (klass, array_method_count);
+
+       mono_loader_unlock ();
+       locked = FALSE;
+
+       setup_interface_offsets (klass, first_iface_slot, TRUE);
+
        if (mono_security_core_clr_enabled ())
                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"));
+       if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
+               mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
 
        goto leave;
 
  leave:
+       init_list = g_slist_remove (init_list, klass);
+       mono_native_tls_set_value (init_pending_tls_id, init_list);
+
        /* Because of the double-checking locking pattern */
        mono_memory_barrier ();
        klass->inited = 1;
-       klass->init_pending = 0;
 
-       mono_loader_unlock ();
+       if (locked)
+               mono_loader_unlock ();
 
        return !mono_class_has_failure (klass);
 }
@@ -5346,8 +5372,8 @@ mono_class_has_finalizer (MonoClass *klass)
                MonoMethod *cmethod = NULL;
 
                if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
-               } else if (klass->generic_class) {
-                       MonoClass *gklass = klass->generic_class->container_class;
+               } else if (mono_class_is_ginst (klass)) {
+                       MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 
                        has_finalize = mono_class_has_finalizer (gklass);
                } else if (klass->parent && klass->parent->has_finalize) {
@@ -5395,11 +5421,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;
 }
 
 /*
@@ -5528,7 +5550,6 @@ mono_class_setup_mono_type (MonoClass *klass)
 
        if (MONO_CLASS_IS_INTERFACE (klass))
                klass->interface_id = mono_get_unique_iid (klass);
-
 }
 
 #ifndef DISABLE_COM
@@ -5548,7 +5569,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,12 +5613,13 @@ 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;
 
-               if (parent->generic_class && !parent->name) {
+               if (mono_class_is_ginst (parent) && !parent->name) {
                        /*
                         * If the parent is a generic instance, we may get
                         * called before it is fully initialized, especially
@@ -5657,12 +5679,12 @@ mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
  *  - supertypes: array of classes: each element has a class in the hierarchy
  *    starting from @class up to System.Object
  * 
- * LOCKING: This function is atomic, in case of contention we waste memory.
+ * LOCKING: Acquires the loader lock.
  */
 void
 mono_class_setup_supertypes (MonoClass *klass)
 {
-       int ms;
+       int ms, idepth;
        MonoClass **supertypes;
 
        mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
@@ -5672,15 +5694,15 @@ mono_class_setup_supertypes (MonoClass *klass)
        if (klass->parent && !klass->parent->supertypes)
                mono_class_setup_supertypes (klass->parent);
        if (klass->parent)
-               klass->idepth = klass->parent->idepth + 1;
+               idepth = klass->parent->idepth + 1;
        else
-               klass->idepth = 1;
+               idepth = 1;
 
-       ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, klass->idepth);
+       ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
        supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
 
        if (klass->parent) {
-               CHECKED_METADATA_WRITE_PTR ( supertypes [klass->idepth - 1] , klass );
+               CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
 
                int supertype_idx;
                for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
@@ -5689,7 +5711,14 @@ mono_class_setup_supertypes (MonoClass *klass)
                CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
        }
 
-       CHECKED_METADATA_WRITE_PTR_ATOMIC ( klass->supertypes , supertypes );
+       mono_memory_barrier ();
+
+       mono_loader_lock ();
+       klass->idepth = idepth;
+       /* Needed so idepth is visible before supertypes is set */
+       mono_memory_barrier ();
+       klass->supertypes = supertypes;
+       mono_loader_unlock ();
 }
 
 static gboolean
@@ -5697,7 +5726,7 @@ fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
 {
        MonoClass *gtd = (MonoClass*)user_data;
        /* Only try to fix generic instances of @gtd */
-       if (gclass->generic_class->container_class != gtd)
+       if (mono_class_get_generic_class (gclass)->container_class != gtd)
                return FALSE;
 
        /* Check if the generic instance has no parent. */
@@ -5710,8 +5739,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);
 }
 
 /**
@@ -5759,7 +5788,17 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
        nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
 
-       klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
+       if (mono_metadata_has_generic_params (image, type_token)) {
+               klass = mono_image_alloc0 (image, sizeof (MonoClassGtd));
+               klass->class_kind = MONO_CLASS_GTD;
+               classes_size += sizeof (MonoClassGtd);
+               ++class_gtd_count;
+       } else {
+               klass = mono_image_alloc0 (image, sizeof (MonoClassDef));
+               klass->class_kind = MONO_CLASS_DEF;
+               classes_size += sizeof (MonoClassDef);
+               ++class_def_count;
+       }
 
        klass->name = name;
        klass->name_space = nspace;
@@ -5768,25 +5807,21 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 
        klass->image = image;
        klass->type_token = type_token;
-       klass->flags = cols [MONO_TYPEDEF_FLAGS];
+       mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
 
        mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
 
-       classes_size += sizeof (MonoClass);
-
        /*
         * Check whether we're a generic type definition.
         */
-       klass->generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
-       if (klass->generic_container) {
-               klass->is_generic = 1;
-               klass->generic_container->owner.klass = klass;
-               klass->generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
-               context = &klass->generic_container->context;
-       }
-
-       if (klass->generic_container)
+       if (mono_class_is_gtd (klass)) {
+               MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
+               generic_container->owner.klass = klass;
+               generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
+               context = &generic_container->context;
+               mono_class_set_generic_container (klass, generic_container);
                enable_gclass_recording ();
+       }
 
        if (cols [MONO_TYPEDEF_EXTENDS]) {
                MonoClass *tmp;
@@ -5805,7 +5840,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;
                }
 
@@ -5814,7 +5849,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                                mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
                                goto parent_failure;
                        }
-                       if (klass->generic_container && tmp->generic_class && tmp->generic_class->container_class == klass) {
+                       if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
                                mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
                                goto parent_failure;
                        }
@@ -5826,7 +5861,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
        mono_class_setup_mono_type (klass);
 
-       if (klass->generic_container)
+       if (mono_class_is_gtd (klass))
                disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
 
        /* 
@@ -5837,18 +5872,18 @@ 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;
                }
        }
 
-       if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
+       if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
                klass->unicode = 1;
 
 #ifdef HOST_WIN32
-       if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
+       if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
                klass->unicode = 1;
 #endif
 
@@ -5858,12 +5893,15 @@ 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;
                }
 
+               /* This is required now that it is possible for more than 2^16 interfaces to exist. */
+               g_assert(icount <= 65535);
+
                klass->interfaces = interfaces;
                klass->interface_count = icount;
                klass->interfaces_inited = 1;
@@ -5874,8 +5912,10 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        /*
         * Compute the field and method lists
         */
-       klass->field.first  = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
-       klass->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
+       int first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
+       mono_class_set_first_field_idx (klass, first_field_idx);
+       int first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
+       mono_class_set_first_method_idx (klass, first_method_idx);
 
        if (tt->rows > tidx){           
                mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
@@ -5888,19 +5928,14 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 
        if (cols [MONO_TYPEDEF_FIELD_LIST] && 
            cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
-               klass->field.count = field_last - klass->field.first;
-       else
-               klass->field.count = 0;
-
+               mono_class_set_field_count (klass, field_last - first_field_idx);
        if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
-               klass->method.count = method_last - klass->method.first;
-       else
-               klass->method.count = 0;
+               mono_class_set_method_count (klass, method_last - first_method_idx);
 
        /* reserve space to store vector pointer in arrays */
        if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
                klass->instance_size += 2 * sizeof (gpointer);
-               g_assert (klass->field.count == 0);
+               g_assert (mono_class_get_field_count (klass) == 0);
        }
 
        if (klass->enumtype) {
@@ -5908,7 +5943,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;
@@ -5921,8 +5956,8 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
         * We must do this after the class has been constructed to make certain recursive scenarios
         * 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)));
+       if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), 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;
@@ -5950,8 +5985,8 @@ parent_failure:
 gboolean
 mono_class_is_nullable (MonoClass *klass)
 {
-       return klass->generic_class != NULL &&
-               klass->generic_class->container_class == mono_defaults.generic_nullable_class;
+       MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+       return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
 }
 
 
@@ -5960,7 +5995,7 @@ MonoClass*
 mono_class_get_nullable_param (MonoClass *klass)
 {
        g_assert (mono_class_is_nullable (klass));
-       return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+       return mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
 }
 
 static void
@@ -5968,13 +6003,13 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
 {
        if (gtd->parent) {
                MonoError error;
-               MonoGenericClass *gclass = klass->generic_class;
+               MonoGenericClass *gclass = mono_class_get_generic_class (klass);
 
                klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
                if (!mono_error_ok (&error)) {
                        /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
                        klass->parent = mono_defaults.object_class;
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_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);
                }
        }
@@ -6006,7 +6041,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
                return gclass->cached_class;
        }
 
-       klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
+       klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
 
        gklass = gclass->container_class;
 
@@ -6024,12 +6059,11 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
        
        klass->image = gklass->image;
-       klass->flags = gklass->flags;
        klass->type_token = gklass->type_token;
-       klass->field.count = gklass->field.count;
 
-       klass->is_inflated = 1;
-       klass->generic_class = gclass;
+       klass->class_kind = MONO_CLASS_GINST;
+       //FIXME add setter
+       ((MonoClassGenericInst*)klass)->generic_class = gclass;
 
        klass->byval_arg.type = MONO_TYPE_GENERICINST;
        klass->this_arg.type = klass->byval_arg.type;
@@ -6079,8 +6113,8 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
 
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
 
-       inflated_classes ++;
-       inflated_classes_size += sizeof (MonoClass);
+       ++class_ginst_count;
+       inflated_classes_size += sizeof (MonoClassGenericInst);
        
        mono_loader_unlock ();
 
@@ -6141,8 +6175,10 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
        gboolean is_mvar = container->is_method;
        gboolean is_anonymous = container->is_anonymous;
 
-       klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
-       classes_size += sizeof (MonoClass);
+       klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
+       klass->class_kind = MONO_CLASS_GPARAM;
+       classes_size += sizeof (MonoClassGenericParam);
+       ++class_gparam_count;
 
        if (pinfo) {
                CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
@@ -6192,7 +6228,6 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
        klass->inited = TRUE;
        CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class ,    klass );
        CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
-       klass->flags = TYPE_ATTRIBUTE_PUBLIC;
 
        klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
        klass->this_arg.type = klass->byval_arg.type;
@@ -6212,14 +6247,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);
        }
@@ -6419,23 +6453,23 @@ mono_ptr_class_get (MonoType *type)
        }
        mono_image_unlock (image);
        
-       result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
+       result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
 
-       classes_size += sizeof (MonoClass);
+       classes_size += sizeof (MonoClassPointer);
+       ++class_pointer_count;
 
        result->parent = NULL; /* no parent for PTR types */
        result->name_space = el_class->name_space;
        name = g_strdup_printf ("%s*", el_class->name);
        result->name = mono_image_strdup (image, name);
+       result->class_kind = MONO_CLASS_POINTER;
        g_free (name);
 
        mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
 
        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;
 
@@ -6484,17 +6518,19 @@ mono_fnptr_class_get (MonoMethodSignature *sig)
        }
        result = g_new0 (MonoClass, 1);
 
+       classes_size += sizeof (MonoClassPointer);
+       ++class_pointer_count;
+
        result->parent = NULL; /* no parent for PTR types */
        result->name_space = "System";
        result->name = "MonoFNPtrFakeClass";
+       result->class_kind = MONO_CLASS_POINTER;
 
        mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
 
        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 +6691,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,20 +6732,16 @@ 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));
+       klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
 
        klass->image = image;
        klass->name_space = eclass->name_space;
+       klass->class_kind = MONO_CLASS_ARRAY;
+
        nsize = strlen (eclass->name);
        name = (char *)g_malloc (nsize + 2 + rank + 1);
        memcpy (name, eclass->name, nsize);
@@ -6726,21 +6757,25 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
 
-       classes_size += sizeof (MonoClass);
+       classes_size += sizeof (MonoClassArray);
+       ++class_array_count;
 
        klass->type_token = 0;
-       /* all arrays are marked serializable and sealed, bug #42779 */
-       klass->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC;
        klass->parent = parent;
        klass->instance_size = mono_class_instance_size (klass->parent);
 
        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) {
+               guint32 ref_info_handle = mono_class_get_ref_info_handle (eclass);
+               if (!ref_info_handle || eclass->wastypebuilder) {
                        g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
-                       g_assert (eclass->ref_info_handle && !eclass->wastypebuilder);
+                       g_assert (ref_info_handle && !eclass->wastypebuilder);
                }
                /* element_size -1 is ok as this is not an instantitable type*/
                klass->sizes.element_size = -1;
@@ -6749,12 +6784,12 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        mono_class_setup_supertypes (klass);
 
-       if (eclass->generic_class)
+       if (mono_class_is_ginst (eclass))
                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,11 +6840,9 @@ 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;
+       //WTF was this? it's wrong
+       // klass->generic_container = eclass->generic_container;
 
        if (rank == 1 && !bounded) {
                MonoClass *prev_class;
@@ -6871,7 +6904,7 @@ mono_class_instance_size (MonoClass *klass)
  *
  * Use to get the computed minimum alignment requirements for the specified class.
  *
- * Returns: minimm alignment requirements 
+ * Returns: minimum alignment requirements
  */
 gint32
 mono_class_min_align (MonoClass *klass)
@@ -6892,7 +6925,7 @@ mono_class_min_align (MonoClass *klass)
  * Returns: the size of a value of kind @klass
  */
 gint32
-mono_class_value_size      (MonoClass *klass, guint32 *align)
+mono_class_value_size (MonoClass *klass, guint32 *align)
 {
        gint32 size;
 
@@ -6922,7 +6955,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,28 +6973,30 @@ 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;
 
        while (klass) {
+               int first_field_idx = mono_class_get_first_field_idx (klass);
+               int fcount = mono_class_get_field_count (klass);
                if (klass->image->uncompressed_metadata) {
                        /* 
-                        * klass->field.first points to the FieldPtr table, while idx points into the
+                        * first_field_idx points to the FieldPtr table, while idx points into the
                         * Field table, so we have to do a search.
                         */
                        /*FIXME this is broken for types with multiple fields with the same name.*/
                        const char *name = mono_metadata_string_heap (klass->image, mono_metadata_decode_row_col (&klass->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
                        int i;
 
-                       for (i = 0; i < klass->field.count; ++i)
+                       for (i = 0; i < fcount; ++i)
                                if (mono_field_get_name (&klass->fields [i]) == name)
                                        return &klass->fields [i];
                        g_assert_not_reached ();
                } else {                        
-                       if (klass->field.count) {
-                               if ((idx >= klass->field.first) && (idx < klass->field.first + klass->field.count)){
-                                       return &klass->fields [idx - klass->field.first];
+                       if (fcount) {
+                               if ((idx >= first_field_idx) && (idx < first_field_idx + fcount)){
+                                       return &klass->fields [idx - first_field_idx];
                                }
                        }
                }
@@ -7022,12 +7057,13 @@ 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;
 
        while (klass) {
-               for (i = 0; i < klass->field.count; ++i) {
+               int fcount = mono_class_get_field_count (klass);
+               for (i = 0; i < fcount; ++i) {
                        MonoClassField *field = &klass->fields [i];
 
                        if (strcmp (name, mono_field_get_name (field)) != 0)
@@ -7060,14 +7096,16 @@ 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)
                        return 0;
-               for (i = 0; i < klass->field.count; ++i) {
+               int first_field_idx = mono_class_get_first_field_idx (klass);
+               int fcount = mono_class_get_field_count (klass);
+               for (i = 0; i < fcount; ++i) {
                        if (&klass->fields [i] == field) {
-                               int idx = klass->field.first + i + 1;
+                               int idx = first_field_idx + i + 1;
 
                                if (klass->image->uncompressed_metadata)
                                        idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
@@ -7085,8 +7123,7 @@ static int
 mono_field_get_index (MonoClassField *field)
 {
        int index = field - field->parent->fields;
-
-       g_assert (index >= 0 && index < field->parent->field.count);
+       g_assert (index >= 0 && index < mono_class_get_field_count (field->parent));
 
        return index;
 }
@@ -7106,23 +7143,25 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ
 
        g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
 
-       if (!klass->ext || !klass->ext->field_def_values) {
+       MonoClassExt *ext = mono_class_get_ext (klass);
+       if (!ext || !ext->field_def_values) {
                MonoFieldDefaultValue *def_values;
 
                mono_class_alloc_ext (klass);
+               ext = mono_class_get_ext (klass);
 
-               def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
+               def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
 
                mono_image_lock (klass->image);
                mono_memory_barrier ();
-               if (!klass->ext->field_def_values)
-                       klass->ext->field_def_values = def_values;
+               if (!ext->field_def_values)
+                       ext->field_def_values = def_values;
                mono_image_unlock (klass->image);
        }
 
        field_index = mono_field_get_index (field);
                
-       if (!klass->ext->field_def_values [field_index].data) {
+       if (!ext->field_def_values [field_index].data) {
                cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
                if (!cindex)
                        return NULL;
@@ -7130,20 +7169,21 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ
                g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
 
                mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
-               klass->ext->field_def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
-               klass->ext->field_def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
+               ext->field_def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
+               ext->field_def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
        }
 
-       *def_type = klass->ext->field_def_values [field_index].def_type;
-       return klass->ext->field_def_values [field_index].data;
+       *def_type = ext->field_def_values [field_index].def_type;
+       return ext->field_def_values [field_index].data;
 }
 
 static int
 mono_property_get_index (MonoProperty *prop)
 {
-       int index = prop - prop->parent->ext->properties;
+       MonoClassExt *ext = mono_class_get_ext (prop->parent);
+       int index = prop - ext->properties;
 
-       g_assert (index >= 0 && index < prop->parent->ext->property.count);
+       g_assert (index >= 0 && index < ext->property.count);
 
        return index;
 }
@@ -7168,10 +7208,11 @@ mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def
         */
 
        if (image_is_dynamic (klass->image)) {
+               MonoClassExt *ext = mono_class_get_ext (klass);
                int prop_index = mono_property_get_index (property);
-               if (klass->ext->prop_def_values && klass->ext->prop_def_values [prop_index].data) {
-                       *def_type = klass->ext->prop_def_values [prop_index].def_type;
-                       return klass->ext->prop_def_values [prop_index].data;
+               if (ext->prop_def_values && ext->prop_def_values [prop_index].data) {
+                       *def_type = ext->prop_def_values [prop_index].def_type;
+                       return ext->prop_def_values [prop_index].data;
                }
                return NULL;
        }
@@ -7191,10 +7232,11 @@ mono_class_get_event_token (MonoEvent *event)
        int i;
 
        while (klass) {
-               if (klass->ext) {
-                       for (i = 0; i < klass->ext->event.count; ++i) {
-                               if (&klass->ext->events [i] == event)
-                                       return mono_metadata_make_token (MONO_TABLE_EVENT, klass->ext->event.first + i + 1);
+               MonoClassExt *ext = mono_class_get_ext (klass);
+               if (ext) {
+                       for (i = 0; i < ext->event.count; ++i) {
+                               if (&ext->events [i] == event)
+                                       return mono_metadata_make_token (MONO_TABLE_EVENT, ext->event.first + i + 1);
                        }
                }
                klass = klass->parent;
@@ -7242,9 +7284,10 @@ mono_class_get_property_token (MonoProperty *prop)
                MonoProperty* p;
                int i = 0;
                gpointer iter = NULL;
+               MonoClassExt *ext = mono_class_get_ext (klass);
                while ((p = mono_class_get_properties (klass, &iter))) {
-                       if (&klass->ext->properties [i] == prop)
-                               return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->ext->property.first + i + 1);
+                       if (&ext->properties [i] == prop)
+                               return mono_metadata_make_token (MONO_TABLE_PROPERTY, ext->property.first + i + 1);
                        
                        i ++;
                }
@@ -8111,10 +8154,10 @@ mono_class_has_variant_generic_params (MonoClass *klass)
        int i;
        MonoGenericContainer *container;
 
-       if (!klass->generic_class)
+       if (!mono_class_is_ginst (klass))
                return FALSE;
 
-       container = klass->generic_class->container_class->generic_container;
+       container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
 
        for (i = 0; i < container->type_argc; ++i)
                if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
@@ -8158,7 +8201,7 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean
        int j;
        MonoType **klass_argv, **oklass_argv;
        MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
-       MonoGenericContainer *container = klass_gtd->generic_container;
+       MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
 
        if (klass == oklass)
                return TRUE;
@@ -8167,8 +8210,8 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean
        if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
                return FALSE;
 
-       klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
-       oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
+       klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+       oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
 
        for (j = 0; j < container->type_argc; ++j) {
                MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
@@ -8341,7 +8384,7 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                }
 
                /* interface_offsets might not be set for dynamic classes */
-               if (oklass->ref_info_handle && !oklass->interface_bitmap) {
+               if (mono_class_get_ref_info_handle (oklass) && !oklass->interface_bitmap) {
                        /* 
                         * oklass might be a generic type parameter but they have 
                         * interface_offsets set.
@@ -8423,14 +8466,14 @@ mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
        int j;
        MonoType **klass_argv, **oklass_argv;
        MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
-       MonoGenericContainer *container = klass_gtd->generic_container;
+       MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
 
        /*Viable candidates are instances of the same generic interface*/
        if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
                return FALSE;
 
-       klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
-       oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
+       klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+       oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
 
        for (j = 0; j < container->type_argc; ++j) {
                MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
@@ -8607,8 +8650,8 @@ mono_class_get_cctor (MonoClass *klass)
                return result;
        }
 
-       if (klass->generic_class && !klass->methods)
-               return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
+       if (mono_class_is_ginst (klass) && !klass->methods)
+               return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class));
 
        return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
 }
@@ -8989,22 +9032,6 @@ mono_class_get_rank (MonoClass *klass)
        return klass->rank;
 }
 
-/**
- * mono_class_get_flags:
- * @klass: the MonoClass to act on
- *
- * The type flags from the TypeDef table from the metadata.
- * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the
- * different values.
- *
- * Returns: The flags from the TypeDef table.
- */
-guint32
-mono_class_get_flags (MonoClass *klass)
-{
-       return klass->flags;
-}
-
 /**
  * mono_class_get_name
  * @klass: the MonoClass to act on
@@ -9078,7 +9105,7 @@ mono_class_get_byref_type (MonoClass *klass)
 int
 mono_class_num_fields (MonoClass *klass)
 {
-       return klass->field.count;
+       return mono_class_get_field_count (klass);
 }
 
 /**
@@ -9090,7 +9117,7 @@ mono_class_num_fields (MonoClass *klass)
 int
 mono_class_num_methods (MonoClass *klass)
 {
-       return klass->method.count;
+       return mono_class_get_method_count (klass);
 }
 
 /**
@@ -9104,7 +9131,7 @@ mono_class_num_properties (MonoClass *klass)
 {
        mono_class_setup_properties (klass);
 
-       return klass->ext->property.count;
+       return mono_class_get_ext (klass)->property.count;
 }
 
 /**
@@ -9118,7 +9145,7 @@ mono_class_num_events (MonoClass *klass)
 {
        mono_class_setup_events (klass);
 
-       return klass->ext->event.count;
+       return mono_class_get_ext (klass)->event.count;
 }
 
 /**
@@ -9140,11 +9167,11 @@ 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 */
-               if (klass->field.count) {
+               if (mono_class_get_field_count (klass)) {
                        *iter = &klass->fields [0];
                        return &klass->fields [0];
                } else {
@@ -9154,7 +9181,7 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter)
        }
        field = (MonoClassField *)*iter;
        field++;
-       if (field < &klass->fields [klass->field.count]) {
+       if (field < &klass->fields [mono_class_get_field_count (klass)]) {
                *iter = field;
                return field;
        }
@@ -9189,7 +9216,7 @@ mono_class_get_methods (MonoClass* klass, gpointer *iter)
                if (!klass->methods)
                        return NULL;
                /* start from the first */
-               if (klass->method.count) {
+               if (mono_class_get_method_count (klass)) {
                        *iter = &klass->methods [0];
                        return klass->methods [0];
                } else {
@@ -9199,7 +9226,7 @@ mono_class_get_methods (MonoClass* klass, gpointer *iter)
        }
        method = (MonoMethod **)*iter;
        method++;
-       if (method < &klass->methods [klass->method.count]) {
+       if (method < &klass->methods [mono_class_get_method_count (klass)]) {
                *iter = method;
                return *method;
        }
@@ -9234,12 +9261,13 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                        method = (MonoMethod **)*iter;
                        method++;
                }
-               while (method < &klass->methods [klass->method.count]) {
+               int mcount = mono_class_get_method_count (klass);
+               while (method < &klass->methods [mcount]) {
                        if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
                                break;
                        method ++;
                }
-               if (method < &klass->methods [klass->method.count]) {
+               if (method < &klass->methods [mcount]) {
                        *iter = method;
                        return *method;
                } else {
@@ -9256,19 +9284,21 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                        start_index = GPOINTER_TO_UINT (*iter);
                }
 
-               for (i = start_index; i < klass->method.count; ++i) {
+               int first_idx = mono_class_get_first_method_idx (klass);
+               int mcount = mono_class_get_method_count (klass);
+               for (i = start_index; i < mcount; ++i) {
                        guint32 flags;
 
-                       /* klass->method.first points into the methodptr table */
-                       flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
+                       /* first_idx points into the methodptr table */
+                       flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
 
                        if (flags & METHOD_ATTRIBUTE_VIRTUAL)
                                break;
                }
 
-               if (i < klass->method.count) {
+               if (i < mcount) {
                        MonoError error;
-                       res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
+                       res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
                        mono_error_cleanup (&error); /* FIXME don't swallow the error */
 
                        /* Add 1 here so the if (*iter) check fails */
@@ -9300,9 +9330,10 @@ mono_class_get_properties (MonoClass* klass, gpointer *iter)
                return NULL;
        if (!*iter) {
                mono_class_setup_properties (klass);
+               MonoClassExt *ext = mono_class_get_ext (klass);
                /* start from the first */
-               if (klass->ext->property.count) {
-                       *iter = &klass->ext->properties [0];
+               if (ext->property.count) {
+                       *iter = &ext->properties [0];
                        return (MonoProperty *)*iter;
                } else {
                        /* no fields */
@@ -9311,7 +9342,8 @@ mono_class_get_properties (MonoClass* klass, gpointer *iter)
        }
        property = (MonoProperty *)*iter;
        property++;
-       if (property < &klass->ext->properties [klass->ext->property.count]) {
+       MonoClassExt *ext = mono_class_get_ext (klass);
+       if (property < &ext->properties [ext->property.count]) {
                *iter = property;
                return (MonoProperty *)*iter;
        }
@@ -9338,9 +9370,10 @@ mono_class_get_events (MonoClass* klass, gpointer *iter)
                return NULL;
        if (!*iter) {
                mono_class_setup_events (klass);
+               MonoClassExt *ext = mono_class_get_ext (klass);
                /* start from the first */
-               if (klass->ext->event.count) {
-                       *iter = &klass->ext->events [0];
+               if (ext->event.count) {
+                       *iter = &ext->events [0];
                        return (MonoEvent *)*iter;
                } else {
                        /* no fields */
@@ -9349,7 +9382,8 @@ mono_class_get_events (MonoClass* klass, gpointer *iter)
        }
        event = (MonoEvent *)*iter;
        event++;
-       if (event < &klass->ext->events [klass->ext->event.count]) {
+       MonoClassExt *ext = mono_class_get_ext (klass);
+       if (event < &ext->events [ext->event.count]) {
                *iter = event;
                return (MonoEvent *)*iter;
        }
@@ -9447,7 +9481,7 @@ setup_nested_types (MonoClass *klass)
 
        mono_memory_barrier ();
        if (!klass->nested_classes_inited) {
-               klass->ext->nested_classes = nested_classes;
+               mono_class_get_ext (klass)->nested_classes = nested_classes;
                mono_memory_barrier ();
                klass->nested_classes_inited = TRUE;
        }
@@ -9479,10 +9513,11 @@ mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
                setup_nested_types (klass);
 
        if (!*iter) {
+               MonoClassExt *ext = mono_class_get_ext (klass);
                /* start from the first */
-               if (klass->ext && klass->ext->nested_classes) {
-                       *iter = klass->ext->nested_classes;
-                       return (MonoClass *)klass->ext->nested_classes->data;
+               if (ext && ext->nested_classes) {
+                       *iter = ext->nested_classes;
+                       return (MonoClass *)ext->nested_classes->data;
                } else {
                        /* no nested types */
                        return NULL;
@@ -9621,27 +9656,30 @@ mono_field_get_rva (MonoClassField *field)
 
        g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
 
-       if (!klass->ext || !klass->ext->field_def_values) {
+       MonoClassExt *ext = mono_class_get_ext (klass);
+       if (!ext || !ext->field_def_values) {
                mono_class_alloc_ext (klass);
+               ext = mono_class_get_ext (klass);
 
-               field_def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
+               field_def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
 
                mono_image_lock (klass->image);
-               if (!klass->ext->field_def_values)
-                       klass->ext->field_def_values = field_def_values;
+               if (!ext->field_def_values)
+                       ext->field_def_values = field_def_values;
                mono_image_unlock (klass->image);
        }
 
        field_index = mono_field_get_index (field);
                
-       if (!klass->ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
-               mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
+       if (!ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
+               int first_field_idx = mono_class_get_first_field_idx (klass);
+               mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL);
                if (!rva)
                        g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
-               klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
+               ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
        }
 
-       return klass->ext->field_def_values [field_index].data;
+       return ext->field_def_values [field_index].data;
 }
 
 /**
@@ -9825,17 +9863,19 @@ find_method_in_metadata (MonoClass *klass, const char *name, int param_count, in
        int i;
 
        /* Search directly in the metadata to avoid calling setup_methods () */
-       for (i = 0; i < klass->method.count; ++i) {
+       int first_idx = mono_class_get_first_method_idx (klass);
+       int mcount = mono_class_get_method_count (klass);
+       for (i = 0; i < mcount; ++i) {
                MonoError error;
                guint32 cols [MONO_METHOD_SIZE];
                MonoMethod *method;
                MonoMethodSignature *sig;
 
-               /* klass->method.first points into the methodptr table */
-               mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
+               /* first_idx points into the methodptr table */
+               mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
 
                if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
-                       method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
+                       method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
                        if (!method) {
                                mono_error_cleanup (&error); /* FIXME don't swallow the error */
                                continue;
@@ -9877,8 +9917,8 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p
 
        mono_class_init (klass);
 
-       if (klass->generic_class && !klass->methods) {
-               res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
+       if (mono_class_is_ginst (klass) && !klass->methods) {
+               res = mono_class_get_method_from_name_flags (mono_class_get_generic_class (klass)->container_class, name, param_count, flags);
                if (res) {
                        MonoError error;
                        res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error);
@@ -9897,7 +9937,8 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p
                 */
                if (!klass->methods)
                        return NULL;
-               for (i = 0; i < klass->method.count; ++i) {
+               int mcount = mono_class_get_method_count (klass);
+               for (i = 0; i < mcount; ++i) {
                        MonoMethod *method = klass->methods [i];
 
                        if (method->name[0] == name [0] && 
@@ -9927,21 +9968,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 +10032,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,16 +10048,32 @@ mono_classes_init (void)
 {
        mono_os_mutex_init (&classes_mutex);
 
+       mono_native_tls_alloc (&setup_fields_tls_id, NULL);
+       mono_native_tls_alloc (&init_pending_tls_id, NULL);
+
+       mono_counters_register ("MonoClassDef count",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
+       mono_counters_register ("MonoClassGtd count",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
+       mono_counters_register ("MonoClassGenericInst count",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
+       mono_counters_register ("MonoClassGenericParam count",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
+       mono_counters_register ("MonoClassArray count",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
+       mono_counters_register ("MonoClassPointer count",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
        mono_counters_register ("Inflated methods size",
                                                        MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
-       mono_counters_register ("Inflated classes",
-                                                       MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes);
        mono_counters_register ("Inflated classes size",
                                                        MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
        mono_counters_register ("MonoClass size",
                                                        MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
        mono_counters_register ("MonoClassExt size",
                                                        MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
+
+       mono_counters_register ("MonoClassExt count",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_count);
 }
 
 /**
@@ -9985,6 +10084,9 @@ mono_classes_init (void)
 void
 mono_classes_cleanup (void)
 {
+       mono_native_tls_free (setup_fields_tls_id);
+       mono_native_tls_free (init_pending_tls_id);
+
        if (global_interface_bitset)
                mono_bitset_free (global_interface_bitset);
        global_interface_bitset = NULL;
@@ -10002,55 +10104,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
@@ -10069,7 +10128,8 @@ is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
 MonoClass *
 mono_class_get_generic_type_definition (MonoClass *klass)
 {
-       return klass->generic_class ? klass->generic_class->container_class : klass;
+       MonoGenericClass *gklass =  mono_class_try_get_generic_class (klass);
+       return gklass ? gklass->container_class : klass;
 }
 
 /*
@@ -10166,8 +10226,9 @@ static MonoClass*
 get_generic_definition_class (MonoClass *klass)
 {
        while (klass) {
-               if (klass->generic_class && klass->generic_class->container_class)
-                       return klass->generic_class->container_class;
+               MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+               if (gklass && gklass->container_class)
+                       return gklass->container_class;
                klass = klass->parent;
        }
        return NULL;
@@ -10221,12 +10282,12 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass)
        if (member_klass->element_class && !member_klass->enumtype)
                member_klass = member_klass->element_class;
 
-       access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+       access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
 
        if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
                return TRUE;
 
-       if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
+       if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
                return FALSE;
 
        if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
@@ -10277,15 +10338,16 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass*
        if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
                return TRUE;
 
-       if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
-                                       access_klass->generic_container) && 
+       MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
+       if (((access_gklass && access_gklass->container_class) ||
+                                       mono_class_is_gtd (access_klass)) && 
                        (member_generic_def = get_generic_definition_class (member_klass))) {
                MonoClass *access_container;
 
-               if (access_klass->generic_container)
+               if (mono_class_is_gtd (access_klass))
                        access_container = access_klass;
                else
-                       access_container = access_klass->generic_class->container_class;
+                       access_container = access_gklass->container_class;
 
                if (can_access_member (access_container, member_generic_def, context_klass, access_level))
                        return TRUE;
@@ -10523,7 +10585,9 @@ gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
  * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
  * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
  */
-gboolean mono_class_is_valid_enum (MonoClass *klass) {
+gboolean
+mono_class_is_valid_enum (MonoClass *klass)
+{
        MonoClassField * field;
        gpointer iter = NULL;
        gboolean found_base_field = FALSE;
@@ -10534,7 +10598,7 @@ gboolean mono_class_is_valid_enum (MonoClass *klass) {
                return FALSE;
        }
 
-       if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
+       if (!mono_class_is_auto_layout (klass))
                return FALSE;
 
        while ((field = mono_class_get_fields (klass, &iter))) {
@@ -10550,7 +10614,7 @@ gboolean mono_class_is_valid_enum (MonoClass *klass) {
        if (!found_base_field)
                return FALSE;
 
-       if (klass->method.count > 0) 
+       if (mono_class_get_method_count (klass) > 0)
                return FALSE;
 
        return TRUE;
@@ -10559,7 +10623,7 @@ gboolean mono_class_is_valid_enum (MonoClass *klass) {
 gboolean
 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
 {
-       return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
+       return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
 }
 
 /*
@@ -10588,15 +10652,16 @@ mono_class_alloc_ext (MonoClass *klass)
 {
        MonoClassExt *ext;
 
-       if (klass->ext)
+       if (mono_class_get_ext (klass))
                return;
 
        ext = (MonoClassExt *)mono_class_alloc0 (klass, sizeof (MonoClassExt));
        mono_image_lock (klass->image);
        mono_memory_barrier ();
-       if (!klass->ext)
-               klass->ext = ext;
+       if (!mono_class_get_ext (klass))
+               mono_class_set_ext (klass, ext);
        class_ext_size += sizeof (MonoClassExt);
+       ++class_ext_count;
        mono_image_unlock (klass->image);
 }
 
@@ -10631,21 +10696,21 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
                if (interface_count > 1)
                        interfaces [1] = mono_class_bind_generic_parameters (
                           mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
-       } else if (klass->generic_class) {
-               MonoClass *gklass = klass->generic_class->container_class;
+       } else if (mono_class_is_ginst (klass)) {
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 
                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;
                }
 
                interface_count = gklass->interface_count;
                interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
                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);
+                       interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), 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;
                        }
                }
@@ -10673,7 +10738,8 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error)
 {
        MonoClass *klass = field->parent;
        MonoImage *image = klass->image;
-       MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+       MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
+       MonoType *ftype;
        int field_idx = field - klass->fields;
 
        mono_error_init (error);
@@ -10682,37 +10748,41 @@ 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);
+                       char *full_name = mono_type_get_full_name (gtd);
+                       mono_class_set_type_load_failure (klass, "Could not load generic type of field '%s:%s' (%d) due to: %s", full_name, gfield->name, field_idx, mono_error_get_message (error));
+                       g_free (full_name);
                }
 
-               field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
+               ftype = 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);
+                       char *full_name = mono_type_get_full_name (klass);
+                       mono_class_set_type_load_failure (klass, "Could not load instantiated type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
+                       g_free (full_name);
                }
        } else {
                const char *sig;
                guint32 cols [MONO_FIELD_SIZE];
                MonoGenericContainer *container = NULL;
-               int idx = klass->field.first + field_idx;
+               int idx = mono_class_get_first_field_idx (klass) + field_idx;
 
                /*FIXME, in theory we do not lazy load SRE fields*/
                g_assert (!image_is_dynamic (image));
 
-               if (klass->generic_container) {
-                       container = klass->generic_container;
+               if (mono_class_is_gtd (klass)) {
+                       container = mono_class_get_generic_container (klass);
                } else if (gtd) {
-                       container = gtd->generic_container;
+                       container = mono_class_get_generic_container (gtd);
                        g_assert (container);
                }
 
-               /* klass->field.first and idx points into the fieldptr table */
+               /* first_field_idx and idx points into the fieldptr table */
                mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
 
                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)));
+                       char *full_name = mono_type_get_full_name (klass);
+                       mono_error_set_type_load_class (error, klass, "Could not verify field '%s:%s' signature", full_name, field->name);;
+                       mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
+                       g_free (full_name);
                        return;
                }
 
@@ -10722,12 +10792,15 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error)
                /* FIELD signature == 0x06 */
                g_assert (*sig == 0x06);
 
-               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);
+               ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
+               if (!ftype) {
+                       char *full_name = mono_type_get_full_name (klass);
+                       mono_class_set_type_load_failure (klass, "Could not load type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
+                       g_free (full_name);
                }
        }
+       mono_memory_barrier ();
+       field->type = ftype;
 }
 
 static guint32
@@ -10735,7 +10808,7 @@ mono_field_resolve_flags (MonoClassField *field)
 {
        MonoClass *klass = field->parent;
        MonoImage *image = klass->image;
-       MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+       MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
        int field_idx = field - klass->fields;
 
 
@@ -10743,7 +10816,7 @@ mono_field_resolve_flags (MonoClassField *field)
                MonoClassField *gfield = &gtd->fields [field_idx];
                return mono_field_get_flags (gfield);
        } else {
-               int idx = klass->field.first + field_idx;
+               int idx = mono_class_get_first_field_idx (klass) + field_idx;
 
                /*FIXME, in theory we do not lazy load SRE fields*/
                g_assert (!image_is_dynamic (image));
@@ -10752,21 +10825,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,11 +10846,11 @@ 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 */
-               if (klass->field.count) {
+               if (mono_class_get_field_count (klass)) {
                        *iter = &klass->fields [0];
                        return (MonoClassField *)*iter;
                } else {
@@ -10802,7 +10860,7 @@ mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
        }
        field = (MonoClassField *)*iter;
        field++;
-       if (field < &klass->fields [klass->field.count]) {
+       if (field < &klass->fields [mono_class_get_field_count (klass)]) {
                *iter = field;
                return (MonoClassField *)*iter;
        }