Merge pull request #2408 from tastywheattasteslikechicken/MoreInterfaceSupport
[mono.git] / mono / metadata / class.c
index 60e320b6970e94c627e052492430b5ab8b21b71a..042c869adccf3ee198a8e02451ca412ce496b3db 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
  * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 #include <config.h>
 #ifdef HAVE_ALLOCA_H
@@ -17,7 +18,9 @@
 #include <string.h>
 #include <stdlib.h>
 #include <mono/metadata/image.h>
+#include <mono/metadata/image-internals.h>
 #include <mono/metadata/assembly.h>
+#include <mono/metadata/assembly-internals.h>
 #include <mono/metadata/metadata.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/profiler-private.h>
@@ -51,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;
@@ -74,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.
 
@@ -101,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)
 {
@@ -150,14 +163,14 @@ disable_gclass_recording (gclass_record_func func, void *user_data)
        }
 }
 
-/*
+/**
  * mono_class_from_typeref:
  * @image: a MonoImage
  * @type_token: a TypeRef token
  *
  * Creates the MonoClass* structure representing the type defined by
  * the typeref token valid inside @image.
- * Returns: the MonoClass* representing the typeref token, NULL ifcould
+ * Returns: The MonoClass* representing the typeref token, NULL ifcould
  * not be loaded.
  */
 MonoClass *
@@ -169,6 +182,19 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
        return klass;
 }
 
+/**
+ * mono_class_from_typeref_checked:
+ * @image: a MonoImage
+ * @type_token: a TypeRef token
+ * @error: error return code, if any.
+ *
+ * Creates the MonoClass* structure representing the type defined by
+ * the typeref token valid inside @image.
+ *
+ * Returns: The MonoClass* representing the typeref token, NULL if it could
+ * not be loaded with the @error value filled with the information about the
+ * error.
+ */
 MonoClass *
 mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
 {
@@ -202,7 +228,7 @@ mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError
                goto done;
 
        case MONO_RESOLUTION_SCOPE_MODULEREF:
-               module = mono_image_load_module (image, idx);
+               module = mono_image_load_module_checked (image, idx, error);
                if (module)
                        res = mono_class_from_name_checked (module, nspace, name, error);
                goto done;
@@ -217,8 +243,7 @@ mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError
                }
 
                enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error); 
-               if (!mono_error_ok (error))
-                       return NULL;
+               return_val_if_nok (error, NULL);
 
                if (enclosing->nested_classes_inited && enclosing->ext) {
                        /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
@@ -273,15 +298,10 @@ mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError
 done:
        /* Generic case, should be avoided for when a better error is possible. */
        if (!res && mono_error_ok (error)) {
-               if (mono_loader_get_last_error ()) { /*FIXME plug the above to not leak errors*/
-                       mono_error_set_from_loader_error (error);
-               } else {
-                       char *name = mono_class_name_from_token (image, type_token);
-                       char *assembly = mono_assembly_name_from_token (image, type_token);
-                       mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
-               }
+               char *name = mono_class_name_from_token (image, type_token);
+               char *assembly = mono_assembly_name_from_token (image, type_token);
+               mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
        }
-       mono_loader_assert_no_error ();
        return res;
 }
 
@@ -487,8 +507,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;
@@ -517,7 +537,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;
@@ -526,10 +546,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, '>');
@@ -552,7 +572,7 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
  * @format: the format for the return string.
  *
  * 
- * Returns: the string representation in a number of formats:
+ * Returns: The string representation in a number of formats:
  *
  * if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
  * returned in the formatrequired by System.Reflection, this is the
@@ -581,7 +601,7 @@ mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
  * mono_type_get_full_name:
  * @class: a class
  *
- * Returns: the string representation for type as required by System.Reflection.
+ * Returns: The string representation for type as required by System.Reflection.
  * The inverse of mono_reflection_parse_type ().
  */
 char *
@@ -594,7 +614,7 @@ mono_type_get_full_name (MonoClass *klass)
  * mono_type_get_name:
  * @type: a type
  *
- * Returns: the string representation for type as it would be represented in IL code.
+ * Returns: The string representation for type as it would be represented in IL code.
  */
 char*
 mono_type_get_name (MonoType *type)
@@ -606,7 +626,7 @@ mono_type_get_name (MonoType *type)
  * mono_type_get_underlying_type:
  * @type: a type
  *
- * Returns: the MonoType for the underlying integer type if @type
+ * Returns: The MonoType for the underlying integer type if @type
  * is an enum and byref is false, otherwise the type itself.
  */
 MonoType*
@@ -619,11 +639,11 @@ mono_type_get_underlying_type (MonoType *type)
        return type;
 }
 
-/*
+/**
  * mono_class_is_open_constructed_type:
  * @type: a type
  *
- * Returns TRUE if type represents a generics open constructed type.
+ * Returns: TRUE if type represents a generics open constructed type.
  * IOW, not all type parameters required for the instantiation have
  * been provided or it's a generic type definition.
  *
@@ -648,7 +668,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;
        }
@@ -756,8 +776,8 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
                        return NULL;
 
                inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
-               if (!mono_error_ok (error))
-                       return NULL;
+               return_val_if_nok (error, NULL);
+
                if (inst != gclass->context.class_inst)
                        gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
 
@@ -771,7 +791,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;
@@ -781,8 +801,8 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
 
                /* We can't use context->class_inst directly, since it can have more elements */
                inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
-               if (!mono_error_ok (error))
-                       return NULL;
+               return_val_if_nok (error, NULL);
+
                if (inst == container->context.class_inst)
                        return NULL;
 
@@ -808,33 +828,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;
 }
 
 /*
@@ -858,8 +853,7 @@ mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type,
 
        if (context)
                inflated = inflate_generic_type (image, type, context, error);
-       if (!mono_error_ok (error))
-               return NULL;
+       return_val_if_nok (error, NULL);
 
        if (!inflated) {
                MonoType *shared = mono_metadata_get_shared_type (type);
@@ -883,7 +877,7 @@ mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type,
  * If @type is a generic type and @context is not NULL, instantiate it using the 
  * generics context @context.
  *
- * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
+ * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
  * on the heap and is owned by the caller. Returns NULL on error.
  *
  * @deprecated Please use mono_class_inflate_generic_type_checked instead
@@ -894,11 +888,7 @@ mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
        MonoError error;
        MonoType *result;
        result = mono_class_inflate_generic_type_checked (type, context, &error);
-
-       if (!mono_error_ok (&error)) {
-               mono_error_cleanup (&error);
-               return NULL;
-       }
+       mono_error_cleanup (&error);
        return result;
 }
 
@@ -911,7 +901,7 @@ mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
  * If @type is a generic type and @context is not NULL, instantiate it using the 
  * generics context @context.
  *
- * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
+ * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
  * on the heap and is owned by the caller.
  */
 MonoType*
@@ -934,8 +924,7 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG
        mono_error_init (error);
        if (context) {
                inflated = inflate_generic_type (image, type, context, error);
-               if (!mono_error_ok (error))
-                       return NULL;
+               return_val_if_nok (error, NULL);
        }
 
        if (!inflated)
@@ -945,6 +934,11 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG
        return inflated;
 }
 
+/*
+ * mono_class_inflate_generic_class:
+ *
+ *   Inflate the class @gklass with @context. Set @error on failure.
+ */
 MonoClass*
 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
 {
@@ -952,32 +946,13 @@ mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext
        MonoType *inflated;
 
        inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
-       if (!mono_error_ok (error))
-               return NULL;
+       return_val_if_nok (error, NULL);
 
        res = mono_class_from_mono_type (inflated);
        mono_metadata_free_type (inflated);
 
        return res;
 }
-/*
- * mono_class_inflate_generic_class:
- *
- *   Inflate the class GKLASS with CONTEXT.
- */
-MonoClass*
-mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
-{
-       MonoError error;
-       MonoClass *res;
-
-       res = mono_class_inflate_generic_class_checked (gklass, context, &error);
-       g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
-
-       return res;
-}
-
-
 
 static MonoGenericContext
 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
@@ -1013,7 +988,7 @@ fail:
  *
  * Instantiate the generic method @method using the generics context @context.
  *
- * Returns: the new instantiated method
+ * Returns: The new instantiated method
  */
 MonoMethod *
 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
@@ -1066,8 +1041,8 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
                MonoMethodInflated *imethod = (MonoMethodInflated *) method;
 
                tmp_context = inflate_generic_context (method_context, context, error);
-               if (!mono_error_ok (error))
-                       return NULL;
+               return_val_if_nok (error, NULL);
+
                context = &tmp_context;
 
                if (mono_metadata_generic_context_equal (method_context, context))
@@ -1085,7 +1060,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);
@@ -1096,14 +1071,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);
@@ -1142,22 +1115,32 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
        result->sre_method = FALSE;
        result->signature = NULL;
 
-       if (!context->method_inst) {
+       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);
 
-               if (generic_container) {
+               if (generic_container && iresult->context.method_inst == generic_container->context.method_inst) {
                        result->is_generic = 1;
                        mono_method_set_generic_container (result, generic_container);
                }
        }
 
-       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) {
@@ -1232,8 +1215,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;
 }
 
@@ -1298,31 +1281,31 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
        MonoGenericContainer *container = NULL;
        MonoImage *m = klass->image;
        const int top = klass->field.count;
-       int i;
+       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
@@ -1341,15 +1324,11 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
                        goto fail;
                }
 
-               ftype = mono_metadata_parse_type_full (m, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
-               if (!ftype) {
-                       if (mono_loader_get_last_error ()) /*FIXME plug the above to not leak errors*/
-                               mono_error_set_from_loader_error (error);
-                       else
-                               mono_error_set_bad_image (error, klass->image, "Could not parse type for field signature %x", cols [MONO_FIELD_SIGNATURE]);
+               ftype = mono_metadata_parse_type_checked (m, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, 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))
@@ -1362,12 +1341,11 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
        mono_error_set_type_load_class (error, klass, "Could not find base type");
 
 fail:
-       mono_loader_assert_no_error ();
        return NULL;
 }
 
 /*
- * 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)
@@ -1376,32 +1354,42 @@ mono_type_has_exceptions (MonoType *type)
        case MONO_TYPE_CLASS:
        case MONO_TYPE_VALUETYPE:
        case MONO_TYPE_SZARRAY:
-               return type->data.klass->exception_type;
+               return mono_class_has_failure (type->data.klass);
        case MONO_TYPE_ARRAY:
-               return type->data.array->eklass->exception_type;
+               return mono_class_has_failure (type->data.array->eklass);
        case MONO_TYPE_GENERICINST:
-               return mono_generic_class_get_class (type->data.generic_class)->exception_type;
+               return mono_class_has_failure (mono_generic_class_get_class (type->data.generic_class));
        default:
                return FALSE;
        }
 }
 
+void
+mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
+{
+       g_assert (mono_class_has_failure (klass));
+       MonoErrorBoxed *box = (MonoErrorBoxed*)mono_class_get_exception_data (klass);
+       mono_error_set_from_boxed (oerror, box);
+}
+
+
 /*
  * mono_class_alloc:
  *
  *   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;
@@ -1418,13 +1406,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;
@@ -1432,11 +1425,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
@@ -1449,104 +1443,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;
+               mono_loader_lock ();
                klass->field.count = gtd->field.count;
+               mono_loader_unlock ();
        }
 
-       klass->fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
+       top = klass->field.count;
+
+       fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
 
        /*
         * Fetch all the field information.
         */
-       for (i = 0; i < top; i++){
-               field = &klass->fields [i];
+       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 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
  *
- * Initializes the klass->fields.
- * LOCKING: Assumes the loader lock is held.
+ * LOCKING: Acquires the loader lock.
  */
-static void
+void
 mono_class_setup_fields (MonoClass *klass)
 {
        MonoError error;
        MonoImage *m = klass->image;
        int top;
-       guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
-       int i, blittable = TRUE;
+       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
@@ -1561,97 +1554,51 @@ mono_class_setup_fields (MonoClass *klass)
 
        if (gtd) {
                mono_class_setup_fields (gtd);
-               if (gtd->exception_type) {
-                       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;
-               }
        }
 
-       klass->instance_size = 0;
-       if (!klass->rank)
-               klass->sizes.class_size = 0;
-
+       instance_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 (klass->parent->exception_type) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-                               return;
-                       }
-               }
-               klass->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 {
-               klass->instance_size = sizeof (MonoObject);
-               klass->min_align = 1;
+               instance_size = sizeof (MonoObject);
        }
 
-       /* 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 += klass->instance_size;
-       }
-
-       if (!top) {
-               if (explicit_size && real_size) {
-                       klass->instance_size = MAX (real_size, klass->instance_size);
-               }
-               klass->blittable = blittable;
-               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);
@@ -1660,58 +1607,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 (field_class->exception_type) {
-                                               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);
@@ -1720,66 +1638,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) {
-               klass->instance_size = MAX (real_size, klass->instance_size);
+       else {
+               if (!klass->size_inited)
+                       mono_class_setup_fields (klass);
        }
-
-       if (klass->exception_type)
-               return;
-       mono_class_layout_fields (klass);
-
-       /*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);
 }
 
 /*
@@ -1799,16 +1709,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;
 }
@@ -1816,27 +1739,59 @@ type_has_references (MonoClass *klass, MonoType *ftype)
 /*
  * mono_class_layout_fields:
  * @class: a class
+ * @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)
+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;
+       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
@@ -1845,6 +1800,21 @@ mono_class_layout_fields (MonoClass *klass)
         * 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 
@@ -1860,60 +1830,73 @@ mono_class_layout_fields (MonoClass *klass)
                        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
@@ -1924,10 +1907,8 @@ mono_class_layout_fields (MonoClass *klass)
 
                if (klass->parent) {
                        mono_class_setup_fields (klass->parent);
-                       if (klass->parent->exception_type) {
-                               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);
@@ -1958,7 +1939,7 @@ mono_class_layout_fields (MonoClass *klass)
                                        }
                                }
 
-                               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;
@@ -1967,29 +1948,29 @@ mono_class_layout_fields (MonoClass *klass)
                                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;
                        }
 
-                       klass->instance_size = MAX (real_size, klass->instance_size);
+                       instance_size = MAX (real_size, instance_size);
        
-                       if (klass->instance_size & (klass->min_align - 1)) {
-                               klass->instance_size += klass->min_align - 1;
-                               klass->instance_size &= ~(klass->min_align - 1);
+                       if (instance_size & (min_align - 1)) {
+                               instance_size += min_align - 1;
+                               instance_size &= ~(min_align - 1);
                        }
                }
                break;
@@ -2014,28 +1995,30 @@ mono_class_layout_fields (MonoClass *klass)
                                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) {
@@ -2053,7 +2036,7 @@ mono_class_layout_fields (MonoClass *klass)
                                        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];
@@ -2065,19 +2048,18 @@ mono_class_layout_fields (MonoClass *klass)
 
                                // 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
                        }
                        g_free (ref_bitmap);
                }
 
-               klass->instance_size = MAX (real_size, klass->instance_size);
-               if (klass->instance_size & (klass->min_align - 1)) {
-                       klass->instance_size += klass->min_align - 1;
-                       klass->instance_size &= ~(klass->min_align - 1);
+               instance_size = MAX (real_size, instance_size);
+               if (instance_size & (min_align - 1)) {
+                       instance_size += min_align - 1;
+                       instance_size &= ~(min_align - 1);
                }
                break;
        }
@@ -2092,19 +2074,46 @@ mono_class_layout_fields (MonoClass *klass)
                 * 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 (klass->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
-                               klass->min_align = MAX (klass->min_align, klass->instance_size - sizeof (MonoObject));
+               if (mono_align_small_structs && top) {
+                       if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
+                               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;
 
@@ -2116,23 +2125,60 @@ mono_class_layout_fields (MonoClass *klass)
                        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*
@@ -2166,7 +2212,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)
@@ -2177,18 +2223,15 @@ 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 (!gklass->exception_type)
+               if (!mono_class_has_failure (gklass))
                        mono_class_setup_methods (gklass);
-               if (gklass->exception_type) {
-                       /* 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;
@@ -2199,7 +2242,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);
@@ -2296,19 +2339,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;
                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)) {
@@ -2345,13 +2392,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,
@@ -2365,7 +2413,7 @@ mono_class_get_method_by_index (MonoClass *klass, int index)
                return m;
        } else {
                mono_class_setup_methods (klass);
-               if (klass->exception_type) /*FIXME do proper error handling*/
+               if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
                        return NULL;
                g_assert (index >= 0 && index < klass->method.count);
                return klass->methods [index];
@@ -2381,13 +2429,13 @@ 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;
+       MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
        int i;
 
        g_assert (method->klass == gklass);
 
        mono_class_setup_methods (gklass);
-       g_assert (!gklass->exception_type); /*FIXME do proper error handling*/
+       g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/
 
        for (i = 0; i < gklass->method.count; ++i) {
                if (gklass->methods [i] == method) {
@@ -2426,9 +2474,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];
 
@@ -2436,7 +2484,7 @@ mono_class_get_vtable_entry (MonoClass *klass, int offset)
                g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
        } else {
                mono_class_setup_vtable (klass);
-               if (klass->exception_type)
+               if (mono_class_has_failure (klass))
                        return NULL;
                m = klass->vtable [offset];
        }
@@ -2477,15 +2525,13 @@ mono_class_setup_properties (MonoClass *klass)
        if (klass->ext && klass->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 (gklass->exception_type) {
-                       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);
 
@@ -2514,7 +2560,7 @@ mono_class_setup_properties (MonoClass *klass)
 
                if (count) {
                        mono_class_setup_methods (klass);
-                       if (klass->exception_type)
+                       if (mono_class_has_failure (klass))
                                return;
                }
 
@@ -2526,6 +2572,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;
 
@@ -2537,7 +2584,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]) {
@@ -2610,15 +2657,13 @@ mono_class_setup_events (MonoClass *klass)
        if (klass->ext && klass->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 (gklass->exception_type) {
-                       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;
@@ -2655,8 +2700,7 @@ mono_class_setup_events (MonoClass *klass)
 
                if (count) {
                        mono_class_setup_methods (klass);
-                       if (klass->exception_type) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+                       if (mono_class_has_failure (klass)) {
                                return;
                        }
                }
@@ -2671,6 +2715,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;
 
@@ -2682,7 +2727,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]) {
@@ -2772,14 +2817,14 @@ mono_unload_interface_id (MonoClass *klass)
        }
 }
 
-/*
+/**
  * mono_get_unique_iid:
  * @class: interface
  *
  * Assign a unique integer ID to the interface represented by @class.
  * The ID will positive and as small as possible.
  * LOCKING: Acquires the classes lock.
- * Returns: the new ID.
+ * Returns: The new ID.
  */
 static guint32
 mono_get_unique_iid (MonoClass *klass)
@@ -2804,7 +2849,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);
@@ -2823,8 +2868,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;
@@ -2847,8 +2893,7 @@ collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, MonoError
        MonoClass *ic;
 
        mono_class_setup_interfaces (klass, error);
-       if (!mono_error_ok (error))
-               return;
+       return_if_nok (error);
 
        for (i = 0; i < klass->interface_count; i++) {
                ic = klass->interfaces [i];
@@ -2857,14 +2902,13 @@ collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, MonoError
                        *res = g_ptr_array_new ();
                g_ptr_array_add (*res, ic);
                mono_class_init (ic);
-               if (ic->exception_type) {
+               if (mono_class_has_failure (ic)) {
                        mono_error_set_type_load_class (error, ic, "Error Loading class");
                        return;
                }
 
                collect_implemented_interfaces_aux (ic, res, error);
-               if (!mono_error_ok (error))
-                       return;
+               return_if_nok (error);
        }
 }
 
@@ -2906,7 +2950,7 @@ mono_class_interface_offset (MonoClass *klass, MonoClass *itf) {
        }
 }
 
-/*
+/**
  * mono_class_interface_offset_with_variance:
  * 
  * Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
@@ -3041,6 +3085,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
@@ -3058,11 +3108,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;
@@ -3078,11 +3128,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;
@@ -3100,18 +3151,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_from_name (mono_defaults.corlib,
-                       "System.Collections.Generic", "ICollection`1");
-               generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
-                       "System.Collections.Generic", "IEnumerable`1");
-               generic_ienumerator_class = mono_class_from_name (mono_defaults.corlib,
-                       "System.Collections.Generic", "IEnumerator`1");
-               generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
-                       "System.Collections.Generic", "IReadOnlyList`1");
-               generic_ireadonlycollection_class = mono_class_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);
 
@@ -3293,7 +3337,7 @@ count_virtual_methods (MonoClass *klass)
 
        if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
                mono_class_setup_methods (klass);
-               if (klass->exception_type)
+               if (mono_class_has_failure (klass))
                        return -1;
 
                for (i = 0; i < klass->method.count; ++i) {
@@ -3302,8 +3346,9 @@ count_virtual_methods (MonoClass *klass)
                                ++count;
                }
        } else {
+               int first_idx = mono_class_get_first_method_idx (klass);
                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);
+                       flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
 
                        if (flags & METHOD_ATTRIBUTE_VIRTUAL)
                                ++count;
@@ -3415,7 +3460,7 @@ set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *inte
  * the size of the buffer.
  * This compression algorithm assumes the bits set in the bitmap are
  * few and far between, like in interface bitmaps.
- * Returns: the size of the compressed bitmap in bytes.
+ * Returns: The size of the compressed bitmap in bytes.
  */
 int
 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
@@ -3457,7 +3502,7 @@ mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
  * be already checked for being smaller than the maximum id encoded in the
  * bitmap.
  *
- * Returns: a non-zero value if bit @id is set in the bitmap @bitmap,
+ * Returns: A non-zero value if bit @id is set in the bitmap @bitmap,
  * #FALSE otherwise.
  */
 int
@@ -3477,8 +3522,8 @@ 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)
@@ -3514,8 +3559,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                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;
@@ -3523,7 +3567,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;
@@ -3552,14 +3596,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++) {
@@ -3590,7 +3633,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;
@@ -3633,7 +3676,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;
@@ -3652,11 +3695,14 @@ 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 */
+       mono_loader_lock ();
+
+       klass->max_interface_id = max_iid;
        /*
         * We might get called multiple times:
         * - mono_class_init ()
@@ -3697,6 +3743,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                klass->interface_bitmap = bitmap;
 #endif
        }
+       mono_loader_unlock ();
 
 end:
        g_free (interfaces_full);
@@ -3711,7 +3758,7 @@ end:
        
        //printf ("JUST DONE: ");
        //print_implemented_interfaces (klass);
+
        return cur_slot;
 }
 
@@ -3729,11 +3776,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
@@ -3760,18 +3803,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 klass->exception_type == 0;
+               return !mono_class_has_failure (klass);
        }
 
        mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
-       if (klass->generic_class->container_class->exception_type) {
-               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)
@@ -3781,7 +3823,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;
                }
        }
@@ -3796,7 +3838,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.
  */
@@ -3809,6 +3852,7 @@ mono_class_setup_vtable (MonoClass *klass)
 static void
 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
 {
+       MonoError error;
        MonoMethod **overrides;
        MonoGenericContext *context;
        guint32 type_token;
@@ -3824,7 +3868,7 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
                return;
        }
 
-       if (klass->exception_type)
+       if (mono_class_has_failure (klass))
                return;
 
        if (g_list_find (in_setup, klass))
@@ -3840,7 +3884,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);
@@ -3848,9 +3892,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;
        }
 
@@ -3859,7 +3903,14 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
                 * This is true since we don't do layout all over again for them, we simply inflate
                 * the layout of the parent.
                 */
-               mono_reflection_get_dynamic_overrides (klass, &overrides, &onum);
+               mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
+               if (!is_ok (&error)) {
+                       mono_loader_unlock ();
+                       g_list_remove (in_setup, klass);
+                       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;
+               }
        } else {
                /* The following call fails if there are missing methods in the type */
                /* FIXME it's probably a good idea to avoid this for generic instances. */
@@ -3869,7 +3920,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);
 
@@ -3985,7 +4036,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;
                }
 
@@ -4003,7 +4054,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;
@@ -4027,7 +4078,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;
                }
 
@@ -4084,7 +4135,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;
@@ -4218,7 +4269,7 @@ print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, Mono
        g_free (method_signature);
        g_free (type_name);
        mono_class_setup_methods (klass);
-       if (klass->exception_type) {
+       if (mono_class_has_failure (klass)) {
                char *name = mono_type_get_full_name (klass);
                mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name);
                g_free (name);
@@ -4251,28 +4302,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;
                }
 
@@ -4282,7 +4333,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;
@@ -4326,7 +4377,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
        ifaces = mono_class_get_implemented_interfaces (klass, &error);
        if (!mono_error_ok (&error)) {
                char *name = mono_type_get_full_name (klass);
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error)));
+               mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error));
                g_free (name);
                mono_error_cleanup (&error);
                return;
@@ -4343,12 +4394,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                mono_class_init (klass->parent);
                mono_class_setup_vtable_full (klass->parent, in_setup);
 
-               if (klass->parent->exception_type) {
-                       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;
@@ -4376,16 +4423,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 (gklass->exception_type != MONO_EXCEPTION_NONE) {
-                       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;
@@ -4393,9 +4438,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;
                                }
@@ -4438,7 +4481,7 @@ 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 && !klass->exception_type; j++) {
+                               for (j = 0; j < parent_interface->method.count && !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,
@@ -4468,7 +4511,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;
                        }
 
@@ -4500,7 +4543,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
                        virt_methods = g_slist_prepend (virt_methods, cm);
                }
-               if (klass->exception_type)
+               if (mono_class_has_failure (klass))
                        goto fail;
        }
        
@@ -4515,7 +4558,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                ic_offset = mono_class_interface_offset (klass, ic);
 
                mono_class_setup_methods (ic);
-               if (ic->exception_type)
+               if (mono_class_has_failure (ic))
                        goto fail;
                
                // Check if this interface is explicitly implemented (instead of just inherited)
@@ -4562,7 +4605,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                                                }
                                        }
                                        TRACE_INTERFACE_VTABLE (printf ("\n"));
-                                       if (klass->exception_type)  /*Might be set by check_interface_method_override*/
+                                       if (mono_class_has_failure (klass))  /*Might be set by check_interface_method_override*/
                                                goto fail;
                                }
                                
@@ -4583,7 +4626,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                                                        }
                                                        break;
                                                }
-                                               if (klass->exception_type) /*Might be set by check_interface_method_override*/
+                                               if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
                                                        goto fail;
                                                TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
                                        }
@@ -4599,7 +4642,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;
@@ -4645,7 +4688,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;
                                        }
 
@@ -4662,7 +4706,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;
@@ -4678,7 +4722,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                                                break;
                                        }
                                }
-                               if (k->exception_type)
+                               if (mono_class_has_failure (k))
                                        goto fail;
                                
                                if (slot >= 0) 
@@ -4742,12 +4786,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;
@@ -4755,8 +4799,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);
 
@@ -4831,7 +4875,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);
@@ -4853,20 +4897,20 @@ mono_method_get_vtable_slot (MonoMethod *method)
 {
        if (method->slot == -1) {
                mono_class_setup_vtable (method->klass);
-               if (method->klass->exception_type)
+               if (mono_class_has_failure (method->klass))
                        return -1;
                if (method->slot == -1) {
                        MonoClass *gklass;
                        int i;
 
-                       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) {
@@ -4949,7 +4993,7 @@ generic_array_methods (MonoClass *klass)
        if (generic_array_method_num)
                return generic_array_method_num;
        mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
-       g_assert (!klass->parent->exception_type); /*So hitting this assert is a huge problem*/
+       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++) {
                MonoMethod *m = klass->parent->methods [i];
                if (!strncmp (m->name, "InternalArray__", 15)) {
@@ -5007,7 +5051,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++) {
@@ -5035,138 +5079,80 @@ concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
        return s;
 }
 
-static void
-set_failure_from_loader_error (MonoClass *klass, MonoLoaderError *error)
-{
-       gpointer exception_data = NULL;
-
-       switch (error->exception_type) {
-       case MONO_EXCEPTION_TYPE_LOAD:
-               exception_data = concat_two_strings_with_zero (klass->image, error->class_name, error->assembly_name);
-               break;
-
-       case MONO_EXCEPTION_MISSING_METHOD:
-               exception_data = concat_two_strings_with_zero (klass->image, error->class_name, error->member_name);
-               break;
-
-       case MONO_EXCEPTION_MISSING_FIELD: {
-               const char *name_space = error->klass->name_space ? error->klass->name_space : NULL;
-               const char *class_name;
-
-               if (name_space)
-                       class_name = g_strdup_printf ("%s.%s", name_space, error->klass->name);
-               else
-                       class_name = error->klass->name;
-
-               exception_data = concat_two_strings_with_zero (klass->image, class_name, error->member_name);
-               
-               if (name_space)
-                       g_free ((void*)class_name);
-               break;
-       }
-
-       case MONO_EXCEPTION_FILE_NOT_FOUND: {
-               const char *msg;
-
-               if (error->ref_only)
-                       msg = "Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.";
-               else
-                       msg = "Could not load file or assembly '%s' or one of its dependencies.";
-
-               exception_data = concat_two_strings_with_zero (klass->image, msg, error->assembly_name);
-               break;
-       }
-
-       case MONO_EXCEPTION_BAD_IMAGE:
-               exception_data = error->msg;
-               break;
-
-       default :
-               g_assert_not_reached ();
-       }
-
-       mono_class_set_failure (klass, error->exception_type, exception_data);
-}
-
 /**
  * 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);
 
        /* Double-checking locking pattern */
-       if (klass->inited || klass->exception_type)
-               return klass->exception_type == MONO_EXCEPTION_NONE;
+       if (klass->inited || mono_class_has_failure (klass))
+               return !mono_class_has_failure (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 || klass->exception_type) {
-               mono_loader_unlock ();
-               /* Somebody might have gotten in before us */
-               return klass->exception_type == MONO_EXCEPTION_NONE;
-       }
-
-       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 (element_class->exception_type != MONO_EXCEPTION_NONE) {
-                       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 (!gklass->exception_type)
-                       mono_class_setup_methods (gklass);
-               if (gklass->exception_type) {
-                       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)
@@ -5174,38 +5160,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 (klass->exception_type || mono_loader_get_last_error ())
-                               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);
 
@@ -5219,11 +5177,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.
@@ -5236,23 +5192,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 (gklass->exception_type) {
-                       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 */
 
@@ -5272,21 +5227,27 @@ 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 (klass->exception_type)
+                               if (mono_class_has_failure (klass))
                                        goto leave;
 
                                for (i = 0; i < klass->method.count; ++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;
                                        }
                                }
@@ -5294,58 +5255,87 @@ 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 (klass->parent->exception_type) {
-                       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 (mono_loader_get_last_error ())
-                       goto leave;
-               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 (klass->parent->exception_type) {
-                               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-                               goto leave;
-                       }
-                       if (mono_loader_get_last_error ())
-                               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) {
+               MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
+
+               mono_stats.generic_class_count++;
+
+               klass->method = gklass->method;
+               klass->field = gklass->field;
+       }
+
+       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)
+               klass->method.count = 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 (mono_loader_get_last_error ()) {
-               if (klass->exception_type == MONO_EXCEPTION_NONE) {
-                       set_failure_from_loader_error (klass, mono_loader_get_last_error ());
-               }
-               mono_loader_clear_error ();
-       }
-
-       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 klass->exception_type == MONO_EXCEPTION_NONE;
+       return !mono_class_has_failure (klass);
 }
 
 /*
@@ -5367,8 +5357,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) {
@@ -5380,7 +5370,7 @@ mono_class_has_finalizer (MonoClass *klass)
                                 * ignores overrides.
                                 */
                                mono_class_setup_vtable (klass);
-                               if (klass->exception_type || mono_loader_get_last_error ())
+                               if (mono_class_has_failure (klass))
                                        cmethod = NULL;
                                else
                                        cmethod = klass->vtable [finalize_slot];
@@ -5416,11 +5406,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;
 }
 
 /*
@@ -5549,7 +5535,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
@@ -5569,7 +5554,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;
                }
        }
@@ -5613,12 +5598,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
@@ -5718,7 +5704,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. */
@@ -5731,24 +5717,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);
-}
-
-static void
-mono_class_set_failure_from_loader_error (MonoClass *klass, MonoError *error, char *msg)
-{
-       MonoLoaderError *lerror = mono_loader_get_last_error ();
-
-       if (lerror) {
-               set_failure_from_loader_error (klass, lerror);
-               mono_error_set_from_loader_error (error);
-               if (msg)
-                       g_free (msg);
-       } else {
-               mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, 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);
 }
 
 /**
@@ -5781,7 +5751,6 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 
        if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
                mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
-               mono_loader_assert_no_error ();
                return NULL;
        }
 
@@ -5789,7 +5758,6 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 
        if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
                mono_loader_unlock ();
-               mono_loader_assert_no_error ();
                return klass;
        }
 
@@ -5798,7 +5766,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;
@@ -5807,25 +5785,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;
@@ -5844,7 +5818,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;
                }
 
@@ -5853,7 +5827,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;
                        }
@@ -5865,7 +5839,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);
 
        /* 
@@ -5876,19 +5850,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);
-                       mono_loader_assert_no_error ();
                        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
 
@@ -5898,7 +5871,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                if (!mono_metadata_interfaces_from_typedef_full (
                            image, type_token, &interfaces, &icount, FALSE, context, error)){
 
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+                       mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        mono_loader_unlock ();
                        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
                        return NULL;
@@ -5917,8 +5890,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);
@@ -5931,12 +5906,12 @@ 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;
+               klass->field.count = field_last - first_field_idx;
        else
                klass->field.count = 0;
 
        if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
-               klass->method.count = method_last - klass->method.first;
+               klass->method.count = method_last - first_method_idx;
        else
                klass->method.count = 0;
 
@@ -5951,10 +5926,9 @@ 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);
-                       mono_loader_assert_no_error ();
                        return NULL;
                }
                klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype);
@@ -5965,11 +5939,10 @@ 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);
-               mono_loader_assert_no_error ();
                return NULL;
        }
 
@@ -5981,7 +5954,6 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        mono_loader_unlock ();
 
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
-       mono_loader_assert_no_error ();
 
        return klass;
 
@@ -5989,7 +5961,6 @@ parent_failure:
        mono_class_setup_mono_type (klass);
        mono_loader_unlock ();
        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
-       mono_loader_assert_no_error ();
        return NULL;
 }
 
@@ -5997,8 +5968,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;
 }
 
 
@@ -6007,7 +5978,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
@@ -6015,13 +5986,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);
                }
        }
@@ -6053,7 +6024,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;
 
@@ -6071,12 +6042,12 @@ 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;
@@ -6126,8 +6097,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 ();
 
@@ -6188,8 +6159,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 );
@@ -6221,7 +6194,7 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
                CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
                pos++;
        } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
-               CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_from_name (mono_defaults.corlib, "System", "ValueType") );
+               CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
        } else {
                CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
        }
@@ -6239,7 +6212,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;
@@ -6259,14 +6231,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 (klass->parent->exception_type)
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
+               if (mono_class_has_failure (klass->parent))
+                       mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
                else
                        setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
        }
@@ -6466,23 +6437,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;
 
@@ -6531,17 +6502,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;
 
@@ -6562,6 +6535,12 @@ mono_fnptr_class_get (MonoMethodSignature *sig)
        return result;
 }
 
+/**
+ * mono_class_from_mono_type:
+ * @type: describes the type to return
+ *
+ * This returns a MonoClass for the specified MonoType, the value is never NULL.
+ */
 MonoClass *
 mono_class_from_mono_type (MonoType *type)
 {
@@ -6622,7 +6601,9 @@ mono_class_from_mono_type (MonoType *type)
                g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
                g_assert_not_reached ();
        }
-       
+
+       // Yes, this returns NULL, even if it is documented as not doing so, but there
+       // is no way for the code to make it this far, due to the assert above.
        return NULL;
 }
 
@@ -6646,7 +6627,6 @@ mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGener
                MonoType *inflated = inflate_generic_type (NULL, t, context, error);
 
                if (!mono_error_ok (error)) {
-                       mono_loader_assert_no_error ();
                        return NULL;
                }
 
@@ -6670,8 +6650,7 @@ mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGeneri
        MonoClass *ret;
        gboolean inflated = FALSE;
        MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
-       if (!mono_error_ok (error))
-               return NULL;
+       return_val_if_nok (error, NULL);
        ret = mono_class_from_mono_type (t);
        if (inflated)
                mono_metadata_free_type (t);
@@ -6684,7 +6663,7 @@ mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGeneri
  * @rank: the dimension of the array class
  * @bounded: whenever the array has non-zero bounds
  *
- * Returns: a class object describing the array with element type @element_type and 
+ * Returns: A class object describing the array with element type @element_type and 
  * dimension @rank. 
  */
 MonoClass *
@@ -6696,7 +6675,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);
 
@@ -6738,20 +6716,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_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);
@@ -6767,17 +6741,20 @@ 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_TYPE_LOAD, NULL);
+               MonoError prepared_error;
+               mono_error_init (&prepared_error);
+               mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
+               mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
+               mono_error_cleanup (&prepared_error);
        } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
                if (!eclass->ref_info_handle || eclass->wastypebuilder) {
                        g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
@@ -6790,12 +6767,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 (eclass->exception_type) /*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;
 
@@ -6846,11 +6823,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;
@@ -6880,7 +6855,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
  * @element_class: element class 
  * @rank: the dimension of the array class
  *
- * Returns: a class object describing the array with element type @element_type and 
+ * Returns: A class object describing the array with element type @element_type and 
  * dimension @rank. 
  */
 MonoClass *
@@ -6892,8 +6867,10 @@ mono_array_class_get (MonoClass *eclass, guint32 rank)
 /**
  * mono_class_instance_size:
  * @klass: a class 
- * 
- * Returns: the size of an object instance
+ *
+ * Use to get the size of a class in bytes.
+ *
+ * Returns: The size of an object instance
  */
 gint32
 mono_class_instance_size (MonoClass *klass)
@@ -6907,8 +6884,10 @@ mono_class_instance_size (MonoClass *klass)
 /**
  * mono_class_min_align:
  * @klass: a class 
- * 
- * Returns: minimm alignment requirements 
+ *
+ * Use to get the computed minimum alignment requirements for the specified class.
+ *
+ * Returns: minimum alignment requirements
  */
 gint32
 mono_class_min_align (MonoClass *klass)
@@ -6929,7 +6908,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;
 
@@ -6950,7 +6929,7 @@ mono_class_value_size      (MonoClass *klass, guint32 *align)
  * mono_class_data_size:
  * @klass: a class 
  * 
- * Returns: the size of the static class data
+ * Returns: The size of the static class data
  */
 gint32
 mono_class_data_size (MonoClass *klass)
@@ -6959,7 +6938,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
@@ -6977,14 +6956,15 @@ mono_class_data_size (MonoClass *klass)
 static MonoClassField *
 mono_class_get_field_idx (MonoClass *klass, int idx)
 {
-       mono_class_setup_fields_locking (klass);
-       if (klass->exception_type)
+       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);
                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.*/
@@ -6997,8 +6977,8 @@ mono_class_get_field_idx (MonoClass *klass, int idx)
                        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 ((idx >= first_field_idx) && (idx < first_field_idx + klass->field.count)){
+                                       return &klass->fields [idx - first_field_idx];
                                }
                        }
                }
@@ -7033,7 +7013,7 @@ mono_class_get_field (MonoClass *klass, guint32 field_token)
  *
  * Search the class @klass and it's parents for a field with the name @name.
  * 
- * Returns: the MonoClassField pointer of the named field or NULL
+ * Returns: The MonoClassField pointer of the named field or NULL
  */
 MonoClassField *
 mono_class_get_field_from_name (MonoClass *klass, const char *name)
@@ -7052,15 +7032,15 @@ mono_class_get_field_from_name (MonoClass *klass, const char *name)
  * If @klass is an inflated generic type, the type comparison is done with the equivalent field
  * of its generic type definition.
  *
- * Returns: the MonoClassField pointer of the named field or NULL
+ * Returns: The MonoClassField pointer of the named field or NULL
  */
 MonoClassField *
 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
 {
        int i;
 
-       mono_class_setup_fields_locking (klass);
-       if (klass->exception_type)
+       mono_class_setup_fields (klass);
+       if (mono_class_has_failure (klass))
                return NULL;
 
        while (klass) {
@@ -7089,7 +7069,7 @@ mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoTyp
  * Get the token of a field. Note that the tokesn is only valid for the image
  * the field was loaded from. Don't use this function for fields in dynamic types.
  * 
- * Returns: the token representing the field in the image it was loaded from.
+ * Returns: The token representing the field in the image it was loaded from.
  */
 guint32
 mono_class_get_field_token (MonoClassField *field)
@@ -7097,14 +7077,15 @@ 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;
+               int first_field_idx = mono_class_get_first_field_idx (klass);
                for (i = 0; i < klass->field.count; ++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);
@@ -7241,6 +7222,15 @@ mono_class_get_event_token (MonoEvent *event)
        return 0;
 }
 
+/**
+ * mono_class_get_property_from_name:
+ * @klass: a class
+ * @name: name of the property to lookup in the specified class
+ *
+ * Use this method to lookup a property in a class
+ * Returns: the MonoProperty with the given name, or NULL if the property
+ * does not exist on the @klass.
+ */
 MonoProperty*
 mono_class_get_property_from_name (MonoClass *klass, const char *name)
 {
@@ -7256,6 +7246,12 @@ mono_class_get_property_from_name (MonoClass *klass, const char *name)
        return NULL;
 }
 
+/**
+ * mono_class_get_property_token:
+ * @prop: MonoProperty to query
+ *
+ * Returns: The ECMA token for the specified property.
+ */
 guint32
 mono_class_get_property_token (MonoProperty *prop)
 {
@@ -7399,7 +7395,7 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
  * @context: the generic context used to evaluate generic instantiations in
  * @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0
  *
- * Returns: the MonoClass that represents @type_token in @image
+ * Returns: The MonoClass that represents @type_token in @image
  */
 MonoClass *
 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
@@ -7435,7 +7431,7 @@ mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_toke
  * @type_token: the token for the class
  * @error: error object to return any error
  *
- * Returns: the MonoClass that represents @type_token in @image
+ * Returns: The MonoClass that represents @type_token in @image, or NULL on error.
  */
 MonoClass *
 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
@@ -7451,7 +7447,7 @@ mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
                        mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
                        return NULL;
                }
-               klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL); /*FIXME proper error handling*/
+               klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
                goto done;
        }
 
@@ -7490,7 +7486,7 @@ done:
  *
  * This functions exists to fullfill the fact that sometimes it's desirable to have access to the 
  * 
- * Returns: the MonoType that represents @type_token in @image
+ * Returns: The MonoType that represents @type_token in @image
  */
 MonoType *
 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
@@ -7501,14 +7497,16 @@ mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext
        mono_error_init (error);
 
        //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
-       if (image_is_dynamic (image))
-               return mono_class_get_type ((MonoClass *)mono_lookup_dynamic_token (image, type_token, context));
+       if (image_is_dynamic (image)) {
+               MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
+               return_val_if_nok (error, NULL);
+               return mono_class_get_type (klass);
+       }
 
        if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
                MonoClass *klass = mono_class_get_checked (image, type_token, error);
 
                if (!klass) {
-                       mono_loader_assert_no_error ();
                        return NULL;
                }
 
@@ -7519,7 +7517,6 @@ mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext
        type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
 
        if (!type) {
-               mono_loader_assert_no_error ();
                return NULL;
        }
 
@@ -7540,7 +7537,13 @@ mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext
        return type;
 }
 
-
+/**
+ * mono_class_get:
+ * @image: image where the class token will be looked up.
+ * @type_token: a type token from the image
+ *
+ * Returns the MonoClass with the given @type_token on the @image
+ */
 MonoClass *
 mono_class_get (MonoImage *image, guint32 type_token)
 {
@@ -7694,7 +7697,7 @@ find_nocase (gpointer key, gpointer value, gpointer user_data)
  * @image: The MonoImage where the type is looked up in
  * @name_space: the type namespace
  * @name: the type short name.
- * @deprecated: use the _checked variant
+ * @deprecated: use the mono_class_from_name_case_checked variant instead.
  *
  * Obtains a MonoClass with a given namespace and a given name which
  * is located in the given MonoImage.   The namespace and name
@@ -7705,12 +7708,28 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
 {
        MonoError error;
        MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
-       g_assert (!mono_error_ok (&error));
+       mono_error_cleanup (&error);
+
        return res;
 }
 
+/**
+ * mono_class_from_name_case:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ * @error: if 
+ *
+ * Obtains a MonoClass with a given namespace and a given name which
+ * is located in the given MonoImage.   The namespace and name
+ * lookups are case insensitive.
+ *
+ * Returns: The MonoClass if the given namespace and name were found, or NULL if it
+ * was not found.   The @error object will contain information about the problem
+ * in that case.
+ */
 MonoClass *
-mono_class_from_name_case_checked (MonoImage *image, const charname_space, const char *name, MonoError *error)
+mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
 {
        MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEDEF];
        guint32 cols [MONO_TYPEDEF_SIZE];
@@ -7793,13 +7812,15 @@ return_nested_in (MonoClass *klass, char *nested)
 }
 
 static MonoClass*
-search_modules (MonoImage *image, const char *name_space, const char *name)
+search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error)
 {
        MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
        MonoImage *file_image;
        MonoClass *klass;
        int i;
 
+       mono_error_init (error);
+
        /* 
         * The EXPORTEDTYPES table only contains public types, so have to search the
         * modules as well.
@@ -7812,10 +7833,10 @@ search_modules (MonoImage *image, const char *name_space, const char *name)
                if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
                        continue;
 
-               file_image = mono_image_load_file_for_image (image, i + 1);
+               file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
                if (file_image) {
-                       klass = mono_class_from_name (file_image, name_space, name);
-                       if (klass)
+                       klass = mono_class_from_name_checked (file_image, name_space, name, error);
+                       if (klass || !is_ok (error))
                                return klass;
                }
        }
@@ -7824,7 +7845,7 @@ search_modules (MonoImage *image, const char *name_space, const char *name)
 }
 
 static MonoClass *
-mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, MonoError *error, GHashTable* visited_images)
+mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error)
 {
        GHashTable *nspace_table;
        MonoImage *loaded_image;
@@ -7857,8 +7878,11 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons
        if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
                gboolean res = get_class_from_name (image, name_space, name, &klass);
                if (res) {
-                       if (!klass)
-                               klass = search_modules (image, name_space, name);
+                       if (!klass) {
+                               klass = search_modules (image, name_space, name, error);
+                               if (!is_ok (error))
+                                       return NULL;
+                       }
                        if (nested)
                                return klass ? return_nested_in (klass, nested) : NULL;
                        else
@@ -7881,20 +7905,18 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons
                for (i = 0; i < image->module_count; ++i) {
                        MonoImage *module = image->modules [i];
 
-                       klass = mono_class_from_name (module, name_space, name);
-                       if (klass)
+                       klass = mono_class_from_name_checked (module, name_space, name, error);
+                       if (klass || !is_ok (error))
                                return klass;
                }
        }
 
        if (!token) {
-               klass = search_modules (image, name_space, name);
-               if (klass)
+               klass = search_modules (image, name_space, name, error);
+               if (klass || !is_ok (error))
                        return klass;
-       }
-
-       if (!token)
                return NULL;
+       }
 
        if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
                MonoTableInfo  *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
@@ -7907,10 +7929,10 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons
 
                impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
                if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
-                       loaded_image = mono_assembly_load_module (image->assembly, impl >> MONO_IMPLEMENTATION_BITS);
+                       loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
                        if (!loaded_image)
                                return NULL;
-                       klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, error, visited_images);
+                       klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error);
                        if (nested)
                                return klass ? return_nested_in (klass, nested) : NULL;
                        return klass;
@@ -7923,9 +7945,9 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons
                        g_assert (image->references [assembly_idx - 1]);
                        if (image->references [assembly_idx - 1] == (gpointer)-1)
                                return NULL;                    
-                       klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, error, visited_images);
+                       klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error);
                        if (nested)
-                               return return_nested_in (klass, nested);
+                               return klass ? return_nested_in (klass, nested) : NULL;
                        return klass;
                } else {
                        g_assert_not_reached ();
@@ -7940,6 +7962,18 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons
        return klass;
 }
 
+/**
+ * mono_class_from_name_checked:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * Obtains a MonoClass with a given namespace and a given name which
+ * is located in the given MonoImage.
+ *
+ * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
+ * set if the class was not found or it will return NULL and set the error if there was a loading error.
+ */
 MonoClass *
 mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
 {
@@ -7948,7 +7982,7 @@ mono_class_from_name_checked (MonoImage *image, const char* name_space, const ch
 
        visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
 
-       klass = mono_class_from_name_checked_aux (image, name_space, name, error, visited_images);
+       klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error);
 
        g_hash_table_destroy (visited_images);
 
@@ -7975,13 +8009,61 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
        MonoClass *klass;
 
        klass = mono_class_from_name_checked (image, name_space, name, &error);
-       if (!mono_error_ok (&error)) {
-               mono_loader_set_error_from_mono_error (&error);
-               mono_error_cleanup (&error); /* FIXME Don't swallow the error */
-       }
+       mono_error_cleanup (&error); /* FIXME Don't swallow the error */
+
+       return klass;
+}
+
+/**
+ * mono_class_load_from_name:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * This function works exactly like mono_class_from_name but it will abort if the class is not found.
+ * This function should be used by the runtime for critical types to which there's no way to recover but crash
+ * If they are missing. Thing of System.Object or System.String.
+ */
+MonoClass *
+mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
+{
+       MonoError error;
+       MonoClass *klass;
+
+       klass = mono_class_from_name_checked (image, name_space, name, &error);
+       if (!klass)
+               g_error ("Runtime critical type %s.%s not found", name_space, name);
+       if (!mono_error_ok (&error))
+               g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
+       return klass;
+}
+
+/**
+ * mono_class_try_load_from_name:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * This function tries to load a type, returning the class was found or NULL otherwise.
+ * This function should be used by the runtime when probing for optional types, those that could have being linked out.
+ *
+ * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
+ * a type that we would otherwise assume to be available but was not due some error.
+ *
+ */
+MonoClass*
+mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
+{
+       MonoError error;
+       MonoClass *klass;
+
+       klass = mono_class_from_name_checked (image, name_space, name, &error);
+       if (!mono_error_ok (&error))
+               g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
        return klass;
 }
 
+
 /**
  * mono_class_is_subclass_of:
  * @klass: class to probe if it is a subclass of another one
@@ -7991,11 +8073,11 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
  * This method determines whether @klass is a subclass of @klassc.
  *
  * If the @check_interfaces flag is set, then if @klassc is an interface
- * this method return true if the @klass implements the interface or
+ * this method return TRUE if the @klass implements the interface or
  * if @klass is an interface, if one of its base classes is @klass.
  *
  * If @check_interfaces is false then, then if @klass is not an interface
- * then it returns true if the @klass is a subclass of @klassc.
+ * then it returns TRUE if the @klass is a subclass of @klassc.
  *
  * if @klass is an interface and @klassc is System.Object, then this function
  * return true.
@@ -8005,7 +8087,9 @@ gboolean
 mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc, 
                           gboolean check_interfaces)
 {
-/*FIXME test for interfaces with variant generic arguments*/
+       /* FIXME test for interfaces with variant generic arguments */
+       mono_class_init (klass);
+       mono_class_init (klassc);
        
        if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
                if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
@@ -8045,10 +8129,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))
@@ -8082,8 +8166,9 @@ mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, g
  * @klass: the class to be assigned to
  * @oklass: the source class
  * 
- * Both klass and oklass must be instances of the same generic interface.
- * Return true if @klass can be assigned to a @klass variable
+ * Both @klass and @oklass must be instances of the same generic interface.
+ *
+ * Returns: TRUE if @klass can be assigned to a @klass variable
  */
 gboolean
 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
@@ -8091,7 +8176,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;
@@ -8100,8 +8185,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]);
@@ -8234,12 +8319,13 @@ mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
  * @klass: the class to be assigned to
  * @oklass: the source class
  *
- * Return: true if an instance of object oklass can be assigned to an
+ * Returns: TRUE if an instance of object oklass can be assigned to an
  * instance of object @klass
  */
 gboolean
 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
 {
+       MonoError error;
        /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
        if (!klass->inited)
                mono_class_init (klass);
@@ -8247,7 +8333,7 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
        if (!oklass->inited)
                mono_class_init (oklass);
 
-       if (klass->exception_type || oklass->exception_type)
+       if (mono_class_has_failure (klass) || mono_class_has_failure  (oklass))
                return FALSE;
 
        if (mono_type_is_generic_argument (&klass->byval_arg)) {
@@ -8273,12 +8359,18 @@ 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 (oklass->ref_info_handle && !oklass->interface_bitmap) {
                        /* 
                         * oklass might be a generic type parameter but they have 
                         * interface_offsets set.
                         */
-                       return mono_reflection_call_is_assignable_to (oklass, klass);
+                       gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
+                       if (!is_ok (&error)) {
+                               mono_error_cleanup (&error);
+                               return FALSE;
+                       }
+                       return result;
+               }
                if (!oklass->interface_bitmap)
                        /* Happens with generic instances of not-yet created dynamic types */
                        return FALSE;
@@ -8286,7 +8378,6 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                        return TRUE;
 
                if (mono_class_has_variant_generic_params (klass)) {
-                       MonoError error;
                        int i;
                        mono_class_setup_interfaces (oklass, &error);
                        if (!mono_error_ok (&error)) {
@@ -8350,14 +8441,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]);
@@ -8508,7 +8599,7 @@ mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
  * mono_class_get_cctor:
  * @klass: A MonoClass pointer
  *
- * Returns: the static constructor of @klass if it exists, NULL otherwise.
+ * Returns: The static constructor of @klass if it exists, NULL otherwise.
  */
 MonoMethod*
 mono_class_get_cctor (MonoClass *klass)
@@ -8534,8 +8625,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);
 }
@@ -8544,7 +8635,7 @@ mono_class_get_cctor (MonoClass *klass)
  * mono_class_get_finalizer:
  * @klass: The MonoClass pointer
  *
- * Returns: the finalizer method of @klass if it exists, NULL otherwise.
+ * Returns: The finalizer method of @klass if it exists, NULL otherwise.
  */
 MonoMethod*
 mono_class_get_finalizer (MonoClass *klass)
@@ -8592,7 +8683,7 @@ mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
  * mono_class_array_element_size:
  * @klass: 
  *
- * Returns: the number of bytes an element of type @klass
+ * Returns: The number of bytes an element of type @klass
  * uses when stored into an array.
  */
 gint32
@@ -8656,7 +8747,7 @@ handle_enum:
  * mono_array_element_size:
  * @ac: pointer to a #MonoArrayClass
  *
- * Returns: the size of single array element.
+ * Returns: The size of single array element.
  */
 gint32
 mono_array_element_size (MonoClass *ac)
@@ -8683,8 +8774,9 @@ mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
 
        if (image_is_dynamic (image)) {
                MonoClass *tmp_handle_class;
-               gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
+               gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
 
+               mono_error_assert_ok (error);
                g_assert (tmp_handle_class);
                if (handle_class)
                        *handle_class = tmp_handle_class;
@@ -8764,30 +8856,18 @@ mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
        return NULL;
 }
 
-/**
- * This function might need to call runtime functions so it can't be part
- * of the metadata library.
- */
-static MonoLookupDynamicToken lookup_dynamic = NULL;
-
-void
-mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
-{
-       lookup_dynamic = func;
-}
-
 gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
 {
        MonoClass *handle_class;
-
-       return lookup_dynamic (image, token, TRUE, &handle_class, context);
+       mono_error_init (error);
+       return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
 }
 
 gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
 {
-       return lookup_dynamic (image, token, valid_token, handle_class, context);
+       return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
 }
 
 static MonoGetCachedClassInfo get_cached_class_info = NULL;
@@ -8813,6 +8893,13 @@ mono_install_get_class_from_name (MonoGetClassFromName func)
        get_class_from_name = func;
 }
 
+/**
+ * mono_class_get_image:
+ *
+ * Use this method to get the `MonoImage*` where this class came from.
+ *
+ * Returns: The image where this class is defined.
+ */
 MonoImage*
 mono_class_get_image (MonoClass *klass)
 {
@@ -8823,7 +8910,9 @@ mono_class_get_image (MonoClass *klass)
  * mono_class_get_element_class:
  * @klass: the MonoClass to act on
  *
- * Returns: the element class of an array or an enumeration.
+ * Use this function to get the element class of an array.
+ *
+ * Returns: The element class of an array.
  */
 MonoClass*
 mono_class_get_element_class (MonoClass *klass)
@@ -8835,7 +8924,10 @@ mono_class_get_element_class (MonoClass *klass)
  * mono_class_is_valuetype:
  * @klass: the MonoClass to act on
  *
- * Returns: true if the MonoClass represents a ValueType.
+ * Use this method to determine if the provided `MonoClass*` represents a value type,
+ * or a reference type.
+ *
+ * Returns: TRUE if the MonoClass represents a ValueType, FALSE if it represents a reference type.
  */
 gboolean
 mono_class_is_valuetype (MonoClass *klass)
@@ -8847,7 +8939,9 @@ mono_class_is_valuetype (MonoClass *klass)
  * mono_class_is_enum:
  * @klass: the MonoClass to act on
  *
- * Returns: true if the MonoClass represents an enumeration.
+ * Use this function to determine if the provided `MonoClass*` represents an enumeration.
+ *
+ * Returns: TRUE if the MonoClass represents an enumeration.
  */
 gboolean
 mono_class_is_enum (MonoClass *klass)
@@ -8859,7 +8953,9 @@ mono_class_is_enum (MonoClass *klass)
  * mono_class_enum_basetype:
  * @klass: the MonoClass to act on
  *
- * Returns: the underlying type representation for an enumeration.
+ * Use this function to get the underlying type for an enumeration value.
+ * 
+ * Returns: The underlying type representation for an enumeration.
  */
 MonoType*
 mono_class_enum_basetype (MonoClass *klass)
@@ -8875,7 +8971,7 @@ mono_class_enum_basetype (MonoClass *klass)
  * mono_class_get_parent
  * @klass: the MonoClass to act on
  *
- * Returns: the parent class for this class.
+ * Returns: The parent class for this class.
  */
 MonoClass*
 mono_class_get_parent (MonoClass *klass)
@@ -8884,10 +8980,14 @@ mono_class_get_parent (MonoClass *klass)
 }
 
 /**
- * mono_class_get_nesting_type;
+ * mono_class_get_nesting_type:
  * @klass: the MonoClass to act on
  *
- * Returns: the container type where this type is nested or NULL if this type is not a nested type.
+ * Use this function to obtain the class that the provided `MonoClass*` is nested on.
+ *
+ * If the return is NULL, this indicates that this class is not nested.
+ *
+ * Returns: The container type where this type is nested or NULL if this type is not a nested type.
  */
 MonoClass*
 mono_class_get_nesting_type (MonoClass *klass)
@@ -8899,7 +8999,7 @@ mono_class_get_nesting_type (MonoClass *klass)
  * mono_class_get_rank:
  * @klass: the MonoClass to act on
  *
- * Returns: the rank for the array (the number of dimensions).
+ * Returns: The rank for the array (the number of dimensions).
  */
 int
 mono_class_get_rank (MonoClass *klass)
@@ -8907,27 +9007,11 @@ 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
  *
- * Returns: the name of the class.
+ * Returns: The name of the class.
  */
 const char*
 mono_class_get_name (MonoClass *klass)
@@ -8939,7 +9023,7 @@ mono_class_get_name (MonoClass *klass)
  * mono_class_get_namespace:
  * @klass: the MonoClass to act on
  *
- * Returns: the namespace of the class.
+ * Returns: The namespace of the class.
  */
 const char*
 mono_class_get_namespace (MonoClass *klass)
@@ -8953,7 +9037,7 @@ mono_class_get_namespace (MonoClass *klass)
  *
  * This method returns the internal Type representation for the class.
  *
- * Returns: the MonoType from the class.
+ * Returns: The MonoType from the class.
  */
 MonoType*
 mono_class_get_type (MonoClass *klass)
@@ -8962,12 +9046,12 @@ mono_class_get_type (MonoClass *klass)
 }
 
 /**
- * mono_class_get_type_token
+ * mono_class_get_type_token:
  * @klass: the MonoClass to act on
  *
  * This method returns type token for the class.
  *
- * Returns: the type token for the class.
+ * Returns: The type token for the class.
  */
 guint32
 mono_class_get_type_token (MonoClass *klass)
@@ -8991,7 +9075,7 @@ mono_class_get_byref_type (MonoClass *klass)
  * mono_class_num_fields:
  * @klass: the MonoClass to act on
  *
- * Returns: the number of static and instance fields in the class.
+ * Returns: The number of static and instance fields in the class.
  */
 int
 mono_class_num_fields (MonoClass *klass)
@@ -9003,7 +9087,7 @@ mono_class_num_fields (MonoClass *klass)
  * mono_class_num_methods:
  * @klass: the MonoClass to act on
  *
- * Returns: the number of methods in the class.
+ * Returns: The number of methods in the class.
  */
 int
 mono_class_num_methods (MonoClass *klass)
@@ -9015,7 +9099,7 @@ mono_class_num_methods (MonoClass *klass)
  * mono_class_num_properties
  * @klass: the MonoClass to act on
  *
- * Returns: the number of properties in the class.
+ * Returns: The number of properties in the class.
  */
 int
 mono_class_num_properties (MonoClass *klass)
@@ -9029,7 +9113,7 @@ mono_class_num_properties (MonoClass *klass)
  * mono_class_num_events:
  * @klass: the MonoClass to act on
  *
- * Returns: the number of events in the class.
+ * Returns: The number of events in the class.
  */
 int
 mono_class_num_events (MonoClass *klass)
@@ -9058,8 +9142,8 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter)
        if (!iter)
                return NULL;
        if (!*iter) {
-               mono_class_setup_fields_locking (klass);
-               if (klass->exception_type)
+               mono_class_setup_fields (klass);
+               if (mono_class_has_failure (klass))
                        return NULL;
                /* start from the first */
                if (klass->field.count) {
@@ -9174,11 +9258,12 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                        start_index = GPOINTER_TO_UINT (*iter);
                }
 
+               int first_idx = mono_class_get_first_method_idx (klass);
                for (i = start_index; i < klass->method.count; ++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;
@@ -9186,7 +9271,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
 
                if (i < klass->method.count) {
                        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 */
@@ -9420,7 +9505,7 @@ mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
  * mono_class_is_delegate
  * @klass: the MonoClass to act on
  *
- * Returns: true if the MonoClass represents a System.Delegate.
+ * Returns: TRUE if the MonoClass represents a System.Delegate.
  */
 mono_bool
 mono_class_is_delegate (MonoClass *klass)
@@ -9433,7 +9518,7 @@ mono_class_is_delegate (MonoClass *klass)
  * @klass: The MonoClass to act on
  * @interface: The interface to check if @klass implements.
  *
- * Returns: true if @klass implements @interface.
+ * Returns: TRUE if @klass implements @interface.
  */
 mono_bool
 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
@@ -9445,7 +9530,7 @@ mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
  * mono_field_get_name:
  * @field: the MonoClassField to act on
  *
- * Returns: the name of the field.
+ * Returns: The name of the field.
  */
 const char*
 mono_field_get_name (MonoClassField *field)
@@ -9507,7 +9592,7 @@ mono_field_get_parent (MonoClassField *field)
  * The metadata flags for a field are encoded using the
  * FIELD_ATTRIBUTE_* constants.  See the tabledefs.h file for details.
  *
- * Returns: the flags for the field.
+ * Returns: The flags for the field.
  */
 guint32
 mono_field_get_flags (MonoClassField *field)
@@ -9518,10 +9603,10 @@ mono_field_get_flags (MonoClassField *field)
 }
 
 /**
- * mono_field_get_offset;
+ * mono_field_get_offset:
  * @field: the MonoClassField to act on
  *
- * Returns: the field offset.
+ * Returns: The field offset.
  */
 guint32
 mono_field_get_offset (MonoClassField *field)
@@ -9553,7 +9638,8 @@ mono_field_get_rva (MonoClassField *field)
        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);
+               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);
@@ -9563,10 +9649,10 @@ mono_field_get_rva (MonoClassField *field)
 }
 
 /**
- * mono_field_get_data;
+ * mono_field_get_data:
  * @field: the MonoClassField to act on
  *
- * Returns: pointer to the metadata constant value or to the field
+ * Returns: pointer to the metadata constant value or to the field
  * data if it has an RVA flag.
  */
 const char *
@@ -9587,7 +9673,7 @@ mono_field_get_data (MonoClassField *field)
  * mono_property_get_name: 
  * @prop: the MonoProperty to act on
  *
- * Returns: the name of the property
+ * Returns: The name of the property
  */
 const char*
 mono_property_get_name (MonoProperty *prop)
@@ -9599,7 +9685,7 @@ mono_property_get_name (MonoProperty *prop)
  * mono_property_get_set_method
  * @prop: the MonoProperty to act on.
  *
- * Returns: the setter method of the property (A MonoMethod)
+ * Returns: The setter method of the property (A MonoMethod)
  */
 MonoMethod*
 mono_property_get_set_method (MonoProperty *prop)
@@ -9611,7 +9697,7 @@ mono_property_get_set_method (MonoProperty *prop)
  * mono_property_get_get_method
  * @prop: the MonoProperty to act on.
  *
- * Returns: the setter method of the property (A MonoMethod)
+ * Returns: The setter method of the property (A MonoMethod)
  */
 MonoMethod*
 mono_property_get_get_method (MonoProperty *prop)
@@ -9623,7 +9709,7 @@ mono_property_get_get_method (MonoProperty *prop)
  * mono_property_get_parent:
  * @prop: the MonoProperty to act on.
  *
- * Returns: the MonoClass where the property was defined.
+ * Returns: The MonoClass where the property was defined.
  */
 MonoClass*
 mono_property_get_parent (MonoProperty *prop)
@@ -9638,7 +9724,7 @@ mono_property_get_parent (MonoProperty *prop)
  * The metadata flags for a property are encoded using the
  * PROPERTY_ATTRIBUTE_* constants.  See the tabledefs.h file for details.
  *
- * Returns: the flags for the property.
+ * Returns: The flags for the property.
  */
 guint32
 mono_property_get_flags (MonoProperty *prop)
@@ -9650,7 +9736,7 @@ mono_property_get_flags (MonoProperty *prop)
  * mono_event_get_name:
  * @event: the MonoEvent to act on
  *
- * Returns: the name of the event.
+ * Returns: The name of the event.
  */
 const char*
 mono_event_get_name (MonoEvent *event)
@@ -9662,7 +9748,7 @@ mono_event_get_name (MonoEvent *event)
  * mono_event_get_add_method:
  * @event: The MonoEvent to act on.
  *
- * Returns: the @add' method for the event (a MonoMethod).
+ * Returns: The @add' method for the event (a MonoMethod).
  */
 MonoMethod*
 mono_event_get_add_method (MonoEvent *event)
@@ -9674,7 +9760,7 @@ mono_event_get_add_method (MonoEvent *event)
  * mono_event_get_remove_method:
  * @event: The MonoEvent to act on.
  *
- * Returns: the @remove method for the event (a MonoMethod).
+ * Returns: The @remove method for the event (a MonoMethod).
  */
 MonoMethod*
 mono_event_get_remove_method (MonoEvent *event)
@@ -9686,7 +9772,7 @@ mono_event_get_remove_method (MonoEvent *event)
  * mono_event_get_raise_method:
  * @event: The MonoEvent to act on.
  *
- * Returns: the @raise method for the event (a MonoMethod).
+ * Returns: The @raise method for the event (a MonoMethod).
  */
 MonoMethod*
 mono_event_get_raise_method (MonoEvent *event)
@@ -9698,7 +9784,7 @@ mono_event_get_raise_method (MonoEvent *event)
  * mono_event_get_parent:
  * @event: the MonoEvent to act on.
  *
- * Returns: the MonoClass where the event is defined.
+ * Returns: The MonoClass where the event is defined.
  */
 MonoClass*
 mono_event_get_parent (MonoEvent *event)
@@ -9713,7 +9799,7 @@ mono_event_get_parent (MonoEvent *event)
  * The metadata flags for an event are encoded using the
  * EVENT_* constants.  See the tabledefs.h file for details.
  *
- * Returns: the flags for the event.
+ * Returns: The flags for the event.
  */
 guint32
 mono_event_get_flags (MonoEvent *event)
@@ -9743,17 +9829,18 @@ 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 () */
+       int first_idx = mono_class_get_first_method_idx (klass);
        for (i = 0; i < klass->method.count; ++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;
@@ -9795,8 +9882,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);
@@ -9845,21 +9932,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)
 {
-       if (klass->exception_type)
+       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:
  *
@@ -9867,10 +9996,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);
 }
 
 /**
@@ -9883,16 +10012,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);
 }
 
 /**
@@ -9903,6 +10048,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;
@@ -9920,61 +10068,12 @@ mono_classes_cleanup (void)
 MonoException*
 mono_class_get_exception_for_failure (MonoClass *klass)
 {
-       gpointer exception_data = mono_class_get_exception_data (klass);
-
-       switch (klass->exception_type) {
-       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);
-       }
-       default: {
-               MonoLoaderError *error;
-               MonoException *ex;
-               
-               error = mono_loader_get_last_error ();
-               if (error != NULL){
-                       ex = mono_loader_error_prepare_exception (error);
-                       return ex;
-               }
-               
-               /* TODO - handle other class related failures */
+       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
@@ -9993,7 +10092,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;
 }
 
 /*
@@ -10090,8 +10190,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;
@@ -10133,6 +10234,9 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass)
 {
        int access_level;
 
+       if (access_klass == member_klass)
+               return TRUE;
+
        if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
                return TRUE;
 
@@ -10142,12 +10246,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)))
@@ -10198,15 +10302,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;
@@ -10241,6 +10346,16 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass*
        return FALSE;
 }
 
+/**
+ * mono_method_can_access_field:
+ * @method: Method that will attempt to access the field
+ * @field: the field to access
+ *
+ * Used to determine if a method is allowed to access the specified field.
+ *
+ * Returns: TRUE if the given @method is allowed to access the @field while following
+ * the accessibility rules of the CLI.
+ */
 gboolean
 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
 {
@@ -10258,29 +10373,22 @@ mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
        return can;
 }
 
+/**
+ * mono_method_can_access_method:
+ * @method: Method that will attempt to access the other method
+ * @called: the method that we want to probe for accessibility.
+ *
+ * Used to determine if the @method is allowed to access the specified @called method.
+ *
+ * Returns: TRUE if the given @method is allowed to invoke the @called while following
+ * the accessibility rules of the CLI.
+ */
 gboolean
 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
 {
-       int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
-       if (!can) {
-               MonoClass *nested = method->klass->nested_in;
-               while (nested) {
-                       can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
-                       if (can)
-                               return TRUE;
-                       nested = nested->nested_in;
-               }
-       }
-       /* 
-        * FIXME:
-        * with generics calls to explicit interface implementations can be expressed
-        * directly: the method is private, but we must allow it. This may be opening
-        * a hole or the generics code should handle this differently.
-        * Maybe just ensure the interface type is public.
-        */
-       if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
-               return TRUE;
-       return can;
+       method = mono_method_get_method_definition (method);
+       called = mono_method_get_method_definition (called);
+       return mono_method_can_access_method_full (method, called, NULL);
 }
 
 /*
@@ -10297,6 +10405,10 @@ mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
 gboolean
 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
 {
+       /* Wrappers are except from access checks */
+       if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
+               return TRUE;
+
        MonoClass *access_class = method->klass;
        MonoClass *member_class = called->klass;
        int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
@@ -10437,7 +10549,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;
@@ -10448,7 +10562,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))) {
@@ -10473,7 +10587,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;
 }
 
 /*
@@ -10511,6 +10625,7 @@ mono_class_alloc_ext (MonoClass *klass)
        if (!klass->ext)
                klass->ext = ext;
        class_ext_size += sizeof (MonoClassExt);
+       ++class_ext_count;
        mono_image_unlock (klass->image);
 }
 
@@ -10545,21 +10660,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;
                        }
                }
@@ -10587,7 +10702,7 @@ 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;
        int field_idx = field - klass->fields;
 
        mono_error_init (error);
@@ -10596,39 +10711,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);
-                       g_free (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);
                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);
-                       g_free (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, NULL);
+                       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;
                }
 
@@ -10637,9 +10754,13 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error)
                mono_metadata_decode_value (sig, &sig);
                /* FIELD signature == 0x06 */
                g_assert (*sig == 0x06);
-               field->type = mono_metadata_parse_type_full (image, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
-               if (!field->type)
-                       mono_class_set_failure_from_loader_error (klass, error, g_strdup_printf ("Could not load field %s type", field->name));
+
+               field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
+               if (!field->type) {
+                       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);
+               }
        }
 }
 
@@ -10648,7 +10769,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;
 
 
@@ -10656,7 +10777,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));
@@ -10665,21 +10786,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
@@ -10701,7 +10807,7 @@ mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
        if (!iter)
                return NULL;
        if (!*iter) {
-               mono_class_setup_basic_field_info_locking (klass);
+               mono_class_setup_basic_field_info (klass);
                if (!klass->fields)
                        return NULL;
                /* start from the first */
@@ -10728,3 +10834,5 @@ mono_class_full_name (MonoClass *klass)
        return mono_type_full_name (&klass->byval_arg);
 }
 
+/* Declare all shared lazy type lookup functions */
+GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)