Merge pull request #4621 from alexanderkyte/strdup_env
[mono.git] / mono / metadata / class.c
index b7f974c428c6b670de9c869bfc9e6d64ac355ab0..6e086cf1442a451765cc3fdb8ad2586709f0e208 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * class.c: Class management for the Mono runtime
+/**
+ * \file
+ * Class management for the Mono runtime
  *
  * Author:
  *   Miguel de Icaza (miguel@ximian.com)
@@ -69,7 +70,7 @@ static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedCl
 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
 static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
 static int generic_array_methods (MonoClass *klass);
-static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos);
+static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
 
 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
@@ -79,7 +80,6 @@ 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);
 
 
 /*
@@ -165,12 +165,12 @@ disable_gclass_recording (gclass_record_func func, void *user_data)
 
 /**
  * mono_class_from_typeref:
- * @image: a MonoImage
- * @type_token: a TypeRef token
+ * \param image a MonoImage
+ * \param 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
+ * Creates the \c MonoClass* structure representing the type defined by
+ * the typeref token valid inside \p image.
+ * \returns The \c MonoClass* representing the typeref token, or NULL if it could
  * not be loaded.
  */
 MonoClass *
@@ -184,15 +184,15 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
 
 /**
  * mono_class_from_typeref_checked:
- * @image: a MonoImage
- * @type_token: a TypeRef token
- * @error: error return code, if any.
+ * \param image a MonoImage
+ * \param type_token a TypeRef token
+ * \param error error return code, if any.
  *
- * Creates the MonoClass* structure representing the type defined by
- * the typeref token valid inside @image.
+ * Creates the \c MonoClass* structure representing the type defined by
+ * the typeref token valid inside \p 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
+ * \returns The \c MonoClass* representing the typeref token, NULL if it could
+ * not be loaded with the \p error value filled with the information about the
  * error.
  */
 MonoClass *
@@ -205,7 +205,7 @@ mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError
        MonoClass *res = NULL;
        MonoImage *module;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
                return NULL;
@@ -245,10 +245,10 @@ mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError
                enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error); 
                return_val_if_nok (error, NULL);
 
-               MonoClassExt *ext = mono_class_get_ext (enclosing);
-               if (enclosing->nested_classes_inited && ext) {
+               GList *nested_classes = mono_class_get_nested_classes_property (enclosing);
+               if (enclosing->nested_classes_inited && nested_classes) {
                        /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
-                       for (tmp = ext->nested_classes; tmp; tmp = tmp->next) {
+                       for (tmp = nested_classes; tmp; tmp = tmp->next) {
                                res = (MonoClass *)tmp->data;
                                if (strcmp (res->name, name) == 0)
                                        return res;
@@ -301,7 +301,7 @@ done:
        if (!res && mono_error_ok (error)) {
                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_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x (from typeref, class/assembly %s, %s)", type_token, name, assembly);
        }
        return res;
 }
@@ -370,10 +370,10 @@ mono_type_name_check_byref (MonoType *type, GString *str)
 
 /**
  * mono_identifier_escape_type_name_chars:
- * @str: a destination string
- * @identifier: an IDENTIFIER in internal form
+ * \param str a destination string
+ * \param identifier an IDENTIFIER in internal form
  *
- * Returns: str.
+ * \returns \p str
  *
  * The displayed form of the identifier is appended to str.
  *
@@ -569,22 +569,22 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
 
 /**
  * mono_type_get_name_full:
- * @type: a type
- * @format: the format for the return string.
+ * \param type a type
+ * \param 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
- * inverse of mono_reflection_parse_type ().
+ * if \p format is \c MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
+ * returned in the format required by \c System.Reflection, this is the
+ * inverse of mono_reflection_parse_type().
  *
- * if format is MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
+ * if \p format is \c MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
  * be used by the IL assembler.
  *
- * if format is MONO_TYPE_NAME_FORMAT_FULL_NAME
+ * if \p format is \c MONO_TYPE_NAME_FORMAT_FULL_NAME
  *
- * if format is MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
+ * if \p format is \c MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
  */
 char*
 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
@@ -600,10 +600,10 @@ mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
 
 /**
  * mono_type_get_full_name:
- * @class: a class
+ * \param class a class
  *
- * Returns: The string representation for type as required by System.Reflection.
- * The inverse of mono_reflection_parse_type ().
+ * \returns The string representation for type as required by System.Reflection.
+ * The inverse of mono_reflection_parse_type().
  */
 char *
 mono_type_get_full_name (MonoClass *klass)
@@ -613,9 +613,8 @@ 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.
+ * \param type a type
+ * \returns The string representation for type as it would be represented in IL code.
  */
 char*
 mono_type_get_name (MonoType *type)
@@ -623,11 +622,10 @@ mono_type_get_name (MonoType *type)
        return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
 }
 
-/*
+/**
  * mono_type_get_underlying_type:
- * @type: a type
- *
- * Returns: The MonoType for the underlying integer type if @type
+ * \param type a type
+ * \returns The \c MonoType for the underlying integer type if \p type
  * is an enum and byref is false, otherwise the type itself.
  */
 MonoType*
@@ -642,9 +640,9 @@ mono_type_get_underlying_type (MonoType *type)
 
 /**
  * mono_class_is_open_constructed_type:
- * @type: a type
+ * \param 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.
  *
@@ -694,7 +692,7 @@ is_valid_generic_argument (MonoType *type)
 static MonoType*
 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
 {
-       mono_error_init (error);
+       error_init (error);
 
        switch (type->type) {
        case MONO_TYPE_MVAR: {
@@ -850,7 +848,7 @@ MonoType*
 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
 {
        MonoType *inflated = NULL;
-       mono_error_init (error);
+       error_init (error);
 
        if (context)
                inflated = inflate_generic_type (image, type, context, error);
@@ -870,18 +868,17 @@ mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type,
        return inflated;
 }
 
-/*
+/**
  * mono_class_inflate_generic_type:
- * @type: a type
- * @context: a generics context
+ * \param type a type
+ * \param context a generics context
+ * \deprecated Please use \c mono_class_inflate_generic_type_checked instead
  *
- * If @type is a generic type and @context is not NULL, instantiate it using the 
- * generics context @context.
+ * If \p type is a generic type and \p context is not NULL, instantiate it using the 
+ * generics context \p context.
  *
- * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
+ * \returns The instantiated type or a copy of \p type. The returned \c 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
  */
 MonoType*
 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
@@ -922,7 +919,7 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG
 {
        MonoType *inflated = NULL; 
 
-       mono_error_init (error);
+       error_init (error);
        if (context) {
                inflated = inflate_generic_type (image, type, context, error);
                return_val_if_nok (error, NULL);
@@ -962,7 +959,7 @@ inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflat
        MonoGenericInst *method_inst = NULL;
        MonoGenericContext res = { NULL, NULL };
 
-       mono_error_init (error);
+       error_init (error);
 
        if (context->class_inst) {
                class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
@@ -982,14 +979,14 @@ fail:
        return res;
 }
 
-/*
+/**
  * mono_class_inflate_generic_method:
- * @method: a generic method
- * @context: a generics context
+ * \param method a generic method
+ * \param context a generics context
  *
- * Instantiate the generic method @method using the generics context @context.
+ * Instantiate the generic method \p method using the generics context \p context.
  *
- * Returns: The new instantiated method
+ * \returns The new instantiated method
  */
 MonoMethod *
 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
@@ -1006,9 +1003,9 @@ mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContex
 /**
  * mono_class_inflate_generic_method_full:
  *
- * Instantiate method @method with the generic context @context.
+ * Instantiate method \p method with the generic context \p context.
  * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
- *         Use mono_method_signature () and mono_method_get_header () to get the correct values.
+ *         Use mono_method_signature() and mono_method_get_header() to get the correct values.
  */
 MonoMethod*
 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
@@ -1024,7 +1021,7 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
 
 /**
  * mono_class_inflate_generic_method_full_checked:
- * Same as mono_class_inflate_generic_method_full but return failure using @error.
+ * Same as mono_class_inflate_generic_method_full but return failure using \p error.
  */
 MonoMethod*
 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
@@ -1034,7 +1031,7 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
        MonoMethodSignature *sig;
        MonoGenericContext tmp_context;
 
-       mono_error_init (error);
+       error_init (error);
 
        /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
        while (method->is_inflated) {
@@ -1271,7 +1268,7 @@ mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* con
 
 /** 
  * mono_class_find_enum_basetype:
- * @class: The enum class
+ * \param class The enum class
  *
  *   Determine the basetype of an enum by iterating through its fields. We do this
  * in a separate function since it is cheaper than calling mono_class_setup_fields.
@@ -1286,7 +1283,7 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
 
        g_assert (klass->enumtype);
 
-       mono_error_init (error);
+       error_init (error);
 
        container = mono_class_try_get_generic_container (klass);
        if (mono_class_is_ginst (klass)) {
@@ -1369,11 +1366,10 @@ 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);
+       MonoErrorBoxed *box = mono_class_get_exception_data ((MonoClass*)klass);
        mono_error_set_from_boxed (oerror, box);
 }
 
-
 /*
  * mono_class_alloc:
  *
@@ -1405,7 +1401,7 @@ mono_class_alloc0 (MonoClass *klass, int size)
 
 /**
  * mono_class_setup_basic_field_info:
- * @class: The class to initialize
+ * \param class The class to initialize
  *
  * Initializes the following fields in MonoClass:
  * * klass->fields (only field->parent and field->name)
@@ -1482,21 +1478,21 @@ mono_class_setup_basic_field_info (MonoClass *klass)
 
 /**
  * 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.
+ * \param klass the class that is failing
+ * \param caused_by the class that caused the failure
+ * \param msg Why \p klass is failing.
  * 
- * If @caused_by has a failure, sets a TypeLoadException failure on
- * @klass with message "@msg, due to: {@caused_by message}".
+ * If \p caused_by has a failure, sets a TypeLoadException failure on
+ * \p klass with message "\p msg, due to: {\p caused_by message}".
  *
- * Returns: TRUE if a failiure was set, or FALSE if @caused_by doesn't have a failure.
+ * \returns TRUE if a failiure was set, or FALSE if \p 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);
+               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);
@@ -1509,11 +1505,11 @@ mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoCla
 
 /** 
  * mono_class_setup_fields:
- * @klass: The class to initialize
+ * \p 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:
+ * Sets the following fields in \p klass:
  *  - all the fields initialized by mono_class_init_sizes ()
  *  - element_class/cast_class (for enums)
  *  - field->type/offset for all fields
@@ -1653,6 +1649,7 @@ static void
 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
 {
        if (cached_info) {
+               mono_loader_lock ();
                klass->instance_size = cached_info->instance_size;
                klass->sizes.class_size = cached_info->class_size;
                klass->packing_size = cached_info->packing_size;
@@ -1661,6 +1658,7 @@ init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
                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;
+               mono_loader_unlock ();
        }
        else {
                if (!klass->size_inited)
@@ -1860,7 +1858,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
                                        mono_class_setup_fields (field_class);
                                        if (mono_class_has_failure (field_class)) {
                                                MonoError field_error;
-                                               mono_error_init (&field_error);
+                                               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);
@@ -2363,8 +2361,10 @@ mono_class_setup_methods (MonoClass *klass)
                amethod = create_array_method (klass, "Set", sig);
                methods [method_num++] = amethod;
 
+               GHashTable *cache = g_hash_table_new (NULL, NULL);
                for (i = 0; i < klass->interface_count; i++)
-                       setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
+                       setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
+               g_hash_table_destroy (cache);
        } else if (mono_class_has_static_metadata (klass)) {
                MonoError error;
                int first_idx = mono_class_get_first_method_idx (klass);
@@ -2548,9 +2548,10 @@ mono_class_setup_properties (MonoClass *klass)
        MonoProperty *properties;
        guint32 last;
        int first, count;
+       MonoClassPropertyInfo *info;
 
-       MonoClassExt *ext = mono_class_get_ext (klass);
-       if (ext && ext->properties)
+       info = mono_class_get_property_info (klass);
+       if (info)
                return;
 
        if (mono_class_is_ginst (klass)) {
@@ -2561,14 +2562,14 @@ mono_class_setup_properties (MonoClass *klass)
                if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
                        return;
 
-               MonoClassExt *gext = mono_class_get_ext (gklass);
-               properties = mono_class_new0 (klass, MonoProperty, gext->property.count + 1);
+               MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
+               properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
 
-               for (i = 0; i < gext->property.count; i++) {
+               for (i = 0; i < ginfo->count; i++) {
                        MonoError error;
                        MonoProperty *prop = &properties [i];
 
-                       *prop = gext->properties [i];
+                       *prop = ginfo->properties [i];
 
                        if (prop->get)
                                prop->get = mono_class_inflate_generic_method_full_checked (
@@ -2581,8 +2582,8 @@ mono_class_setup_properties (MonoClass *klass)
                        prop->parent = klass;
                }
 
-               first = gext->property.first;
-               count = gext->property.count;
+               first = ginfo->first;
+               count = ginfo->count;
        } else {
                first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
                count = last - first;
@@ -2630,27 +2631,14 @@ mono_class_setup_properties (MonoClass *klass)
                }
        }
 
-       mono_class_alloc_ext (klass);
-       ext = mono_class_get_ext (klass);
-
-       mono_image_lock (klass->image);
-
-       if (ext->properties) {
-               /* We leak 'properties' which was allocated from the image mempool */
-               mono_image_unlock (klass->image);
-               return;
-       }
-
-       ext->property.first = first;
-       ext->property.count = count;
-
-       /* Flush any pending writes as we do double checked locking on klass->ext->properties */
+       info = mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
+       info->first = first;
+       info->count = count;
+       info->properties = properties;
        mono_memory_barrier ();
 
-       /* Leave this assignment as the last op in the function */
-       ext->properties = properties;
-
-       mono_image_unlock (klass->image);
+       /* This might leak 'info' which was allocated from the image mempool */
+       mono_class_set_property_info (klass, info);
 }
 
 static MonoMethod**
@@ -2684,8 +2672,8 @@ mono_class_setup_events (MonoClass *klass)
        guint32 last;
        MonoEvent *events;
 
-       MonoClassExt *ext = mono_class_get_ext (klass);
-       if (ext && ext->events)
+       MonoClassEventInfo *info = mono_class_get_event_info (klass);
+       if (info)
                return;
 
        if (mono_class_is_ginst (klass)) {
@@ -2696,9 +2684,9 @@ mono_class_setup_events (MonoClass *klass)
                if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
                        return;
 
-               MonoClassExt *gext = mono_class_get_ext (gklass);
-               first = gext->event.first;
-               count = gext->event.count;
+               MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
+               first = ginfo->first;
+               count = ginfo->count;
 
                events = mono_class_new0 (klass, MonoEvent, count);
 
@@ -2708,9 +2696,9 @@ mono_class_setup_events (MonoClass *klass)
                for (i = 0; i < count; i++) {
                        MonoError error;
                        MonoEvent *event = &events [i];
-                       MonoEvent *gevent = &gext->events [i];
+                       MonoEvent *gevent = &ginfo->events [i];
 
-                       mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok
+                       error_init (&error); //since we do conditional calls, we must ensure the default value is ok
 
                        event->parent = klass;
                        event->name = gevent->name;
@@ -2796,26 +2784,14 @@ mono_class_setup_events (MonoClass *klass)
                }
        }
 
-       mono_class_alloc_ext (klass);
-       ext = mono_class_get_ext (klass);
-
-       mono_image_lock (klass->image);
+       info = mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
+       info->events = events;
+       info->first = first;
+       info->count = count;
 
-       if (ext->events) {
-               mono_image_unlock (klass->image);
-               return;
-       }
-
-       ext->event.first = first;
-       ext->event.count = count;
-
-       /* Flush any pending writes as we do double checked locking on klass->ext.events */
        mono_memory_barrier ();
 
-       /* Leave this assignment as the last op in the function */
-       ext->events = events;
-
-       mono_image_unlock (klass->image);
+       mono_class_set_event_info (klass, info);
 }
 
 /*
@@ -2852,12 +2828,12 @@ mono_unload_interface_id (MonoClass *klass)
 
 /**
  * mono_get_unique_iid:
- * @class: interface
+ * \param klass interface
  *
- * Assign a unique integer ID to the interface represented by @class.
+ * Assign a unique integer ID to the interface represented by \p klass.
  * 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)
@@ -2996,8 +2972,8 @@ 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
- * If @itf is an interface with generic variant arguments, try to find the compatible one.
+ * Return the interface offset of \p itf in \p klass. Sets \p non_exact_match to TRUE if the match required variance check
+ * If \p itf is an interface with generic variant arguments, try to find the compatible one.
  *
  * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
  *
@@ -3011,6 +2987,18 @@ mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gbo
        if (i >= 0)
                return i;
        
+       if (itf->is_array_special_interface && klass->rank < 2) {
+               MonoClass *gtd = mono_class_get_generic_type_definition (itf);
+
+               for (i = 0; i < klass->interface_offsets_count; i++) {
+                       // printf ("\t%s\n", mono_type_get_full_name (klass->interfaces_packed [i]));
+                       if (mono_class_get_generic_type_definition (klass->interfaces_packed [i]) == gtd) {
+                               *non_exact_match = TRUE;
+                               return klass->interface_offsets_packed [i];
+                       }
+               }
+       }
+
        if (!mono_class_has_variant_generic_params (itf))
                return -1;
 
@@ -3091,282 +3079,6 @@ print_implemented_interfaces (MonoClass *klass)
        }
 }
 
-static MonoClass*
-inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
-{
-       MonoType *args [1];
-       args [0] = &arg0->byval_arg;
-
-       return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
-}
-
-static MonoClass*
-array_class_get_if_rank (MonoClass *klass, guint rank)
-{
-       return rank ? mono_array_class_get (klass, rank) : klass;
-}
-
-static void
-fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *eclass, int rank)
-{
-       valuetype_types [0] = eclass;
-       if (eclass == mono_defaults.int16_class)
-               valuetype_types [1] = mono_defaults.uint16_class;
-       else if (eclass == mono_defaults.uint16_class)
-               valuetype_types [1] = mono_defaults.int16_class;
-       else if (eclass == mono_defaults.int32_class)
-               valuetype_types [1] = mono_defaults.uint32_class;
-       else if (eclass == mono_defaults.uint32_class)
-               valuetype_types [1] = mono_defaults.int32_class;
-       else if (eclass == mono_defaults.int64_class)
-               valuetype_types [1] = mono_defaults.uint64_class;
-       else if (eclass == mono_defaults.uint64_class)
-               valuetype_types [1] = mono_defaults.int64_class;
-       else if (eclass == mono_defaults.byte_class)
-               valuetype_types [1] = mono_defaults.sbyte_class;
-       else if (eclass == mono_defaults.sbyte_class)
-               valuetype_types [1] = mono_defaults.byte_class;
-       else if (eclass->enumtype && mono_class_enum_basetype (eclass))
-               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
- * 
- * FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
- * MS returns diferrent types based on which instance is called. For example:
- *     object obj = new byte[10][];
- *     Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
- *     Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
- *     a != b ==> true
- * 
- * Fixing this should kill quite some code, save some bits and improve compatibility.
- */
-static MonoClass**
-get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator)
-{
-       MonoClass *eclass = klass->element_class;
-       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;
-       int all_interfaces;
-       gboolean internal_enumerator;
-       gboolean eclass_is_valuetype;
-
-       if (!mono_defaults.generic_ilist_class) {
-               *num = 0;
-               return NULL;
-       }
-       internal_enumerator = FALSE;
-       eclass_is_valuetype = FALSE;
-       original_rank = eclass->rank;
-       if (klass->byval_arg.type != MONO_TYPE_SZARRAY) {
-               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 (gklass->context.class_inst->type_argv [0]);
-                       original_rank = eclass->rank;
-                       if (!eclass->rank)
-                               eclass = eclass->element_class;
-                       internal_enumerator = TRUE;
-                       *is_enumerator = TRUE;
-               } else {
-                       *num = 0;
-                       return NULL;
-               }
-       }
-
-       /* 
-        * with this non-lazy impl we can't implement all the interfaces so we do just the minimal stuff
-        * for deep levels of arrays of arrays (string[][] has all the interfaces, string[][][] doesn't)
-        */
-       all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
-
-       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);
-
-       /*
-        * Arrays in 2.0 need to implement a number of generic interfaces
-        * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
-        * on the element class). For net 4.5, we also need to implement IReadOnlyList`1/IReadOnlyCollection`1.
-        * We collect the types needed to build the
-        * instantiations in interfaces at intervals of 3/5, because 3/5 are
-        * the generic interfaces needed to implement.
-        *
-        * On 4.5, as an optimization, we don't expand ref classes for the variant generic interfaces
-        * (IEnumerator, IReadOnlyList and IReadOnlyColleciton). The regular dispatch code can handle those cases.
-        */
-       if (eclass->valuetype) {
-               nifaces = generic_ireadonlylist_class ? 5 : 3;
-               fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank);
-
-               /* IList, ICollection, IEnumerable, IReadOnlyList`1 */
-               real_count = interface_count = valuetype_types [1] ? (nifaces * 2) : nifaces;
-               if (internal_enumerator) {
-                       ++real_count;
-                       if (valuetype_types [1])
-                               ++real_count;
-               }
-
-               interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count);
-               interfaces [0] = valuetype_types [0];
-               if (valuetype_types [1])
-                       interfaces [nifaces] = valuetype_types [1];
-
-               eclass_is_valuetype = TRUE;
-       } else {
-               int j;
-               int idepth = eclass->idepth;
-               if (!internal_enumerator)
-                       idepth--;
-               nifaces = generic_ireadonlylist_class ? 2 : 3;
-
-               // FIXME: This doesn't seem to work/required for generic params
-               if (!(eclass->this_arg.type == MONO_TYPE_VAR || eclass->this_arg.type == MONO_TYPE_MVAR || (image_is_dynamic (eclass->image) && !eclass->wastypebuilder)))
-                       mono_class_setup_interface_offsets (eclass);
-
-               interface_count = all_interfaces? eclass->interface_offsets_count: eclass->interface_count;
-               /* we add object for interfaces and the supertypes for the other
-                * types. The last of the supertypes is the element class itself which we
-                * already created the explicit interfaces for (so we include it for IEnumerator
-                * and exclude it for arrays).
-                */
-               if (MONO_CLASS_IS_INTERFACE (eclass))
-                       interface_count++;
-               else
-                       interface_count += idepth;
-               if (eclass->rank && eclass->element_class->valuetype) {
-                       fill_valuetype_array_derived_types (valuetype_types, eclass->element_class, original_rank);
-                       if (valuetype_types [1])
-                               ++interface_count;
-               }
-               /* IList, ICollection, IEnumerable, IReadOnlyList */
-               interface_count *= nifaces;
-               real_count = interface_count;
-               if (internal_enumerator) {
-                       real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count;
-                       if (valuetype_types [1])
-                               ++real_count;
-               }
-               interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count);
-               if (MONO_CLASS_IS_INTERFACE (eclass)) {
-                       interfaces [0] = mono_defaults.object_class;
-                       j = nifaces;
-               } else {
-                       j = 0;
-                       for (i = 0; i < idepth; i++) {
-                               mono_class_init (eclass->supertypes [i]);
-                               interfaces [j] = eclass->supertypes [i];
-                               j += nifaces;
-                       }
-               }
-               if (all_interfaces) {
-                       for (i = 0; i < eclass->interface_offsets_count; i++) {
-                               interfaces [j] = eclass->interfaces_packed [i];
-                               j += nifaces;
-                       }
-               } else {
-                       for (i = 0; i < eclass->interface_count; i++) {
-                               interfaces [j] = eclass->interfaces [i];
-                               j += nifaces;
-                       }
-               }
-               if (valuetype_types [1]) {
-                       interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank);
-                       j += nifaces;
-               }
-       }
-
-       /* instantiate the generic interfaces */
-       for (i = 0; i < interface_count; i += nifaces) {
-               MonoClass *iface = interfaces [i];
-
-               interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface);
-               interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface);
-
-               if (eclass->valuetype) {
-                       interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
-                       if (generic_ireadonlylist_class) {
-                               interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface);
-                               interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface);
-                       }
-               } else {
-                       if (!generic_ireadonlylist_class)
-                               interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
-               }
-       }
-       if (internal_enumerator) {
-               int j;
-               /* instantiate IEnumerator<iface> */
-               for (i = 0; i < interface_count; i++) {
-                       interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]);
-               }
-               j = interface_count;
-               if (!eclass_is_valuetype) {
-                       if (MONO_CLASS_IS_INTERFACE (eclass)) {
-                               interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, mono_defaults.object_class);
-                               j ++;
-                       } else {
-                               for (i = 0; i < eclass->idepth; i++) {
-                                       interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->supertypes [i]);
-                                       j ++;
-                               }
-                       }
-                       for (i = 0; i < eclass->interface_offsets_count; i++) {
-                               interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->interfaces_packed [i]);
-                               j ++;
-                       }
-               } else {
-                       interfaces [j++] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [0], original_rank));
-               }
-               if (valuetype_types [1])
-                       interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [1], original_rank));
-       }
-#if 0
-       {
-       char *type_name = mono_type_get_name_full (&klass->byval_arg, 0);
-       for (i = 0; i  < real_count; ++i) {
-               char *name = mono_type_get_name_full (&interfaces [i]->byval_arg, 0);
-               g_print ("%s implements %s\n", type_name, name);
-               g_free (name);
-       }
-       g_free (type_name);
-       }
-#endif
-       *num = real_count;
-       return interfaces;
-}
-
-static int
-find_array_interface (MonoClass *klass, const char *name)
-{
-       int i;
-       for (i = 0; i < klass->interface_count; ++i) {
-               if (strcmp (klass->interfaces [i]->name, name) == 0)
-                       return i;
-       }
-       return -1;
-}
-
 /*
  * Return the number of virtual methods.
  * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
@@ -3426,15 +3138,6 @@ find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
        }
 }
 
-static int
-find_interface_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic)
-{
-       int i = find_interface (num_ifaces, interfaces_full, ic);
-       if (i >= 0)
-               return interface_offsets_full [i];
-       return -1;
-}
-
 static mono_bool
 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
 {
@@ -3495,19 +3198,19 @@ set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *inte
 
 /**
  * mono_compress_bitmap:
- * @dest: destination buffer
- * @bitmap: bitmap buffer
- * @size: size of @bitmap in bytes
+ * \param dest destination buffer
+ * \param bitmap bitmap buffer
+ * \param size size of \p bitmap in bytes
  *
  * This is a mono internal function.
- * The @bitmap data is compressed into a format that is small but
+ * The \p bitmap data is compressed into a format that is small but
  * still searchable in few instructions by the JIT and runtime.
  * The compressed data is stored in the buffer pointed to by the
- * @dest array. Passing a #NULL value for @dest allows to just compute
+ * \p dest array. Passing a NULL value for \p dest allows to just compute
  * 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)
@@ -3541,16 +3244,16 @@ mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
 
 /**
  * mono_class_interface_match:
- * @bitmap: a compressed bitmap buffer
- * @id: the index to check in the bitmap
+ * \param bitmap a compressed bitmap buffer
+ * \param id the index to check in the bitmap
  *
  * This is a mono internal function.
- * Checks if a bit is set in a compressed interface bitmap. @id must
+ * Checks if a bit is set in a compressed interface bitmap. \p id must
  * 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,
- * #FALSE otherwise.
+ * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
+ * FALSE otherwise.
  */
 int
 mono_class_interface_match (const uint8_t *bitmap, int id)
@@ -3584,23 +3287,14 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
        GPtrArray *ifaces;
        GPtrArray **ifaces_array = NULL;
        int interface_offsets_count;
-       MonoClass **array_interfaces = NULL;
-       int num_array_interfaces;
-       int is_enumerator = FALSE;
 
        mono_loader_lock ();
 
        mono_class_setup_supertypes (klass);
-       /* 
-        * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
-        * implicit interfaces have the property that they are assigned the same slot in the
-        * vtables for compatible interfaces
-        */
-       array_interfaces = get_implicit_generic_array_interfaces (klass, &num_array_interfaces, &is_enumerator);
 
        /* compute maximum number of slots and maximum interface id */
        max_iid = 0;
-       num_ifaces = num_array_interfaces; /* this can include duplicated ones */
+       num_ifaces = 0; /* this can include duplicated ones */
        ifaces_array = g_new0 (GPtrArray *, klass->idepth);
        for (j = 0; j < klass->idepth; j++) {
                k = klass->supertypes [j];
@@ -3634,13 +3328,6 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                }
        }
 
-       for (i = 0; i < num_array_interfaces; ++i) {
-               ic = array_interfaces [i];
-               mono_class_init (ic);
-               if (max_iid < ic->interface_id)
-                       max_iid = ic->interface_id;
-       }
-
        if (MONO_CLASS_IS_INTERFACE (klass)) {
                num_ifaces++;
                if (max_iid < klass->interface_id)
@@ -3695,55 +3382,6 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
        if (MONO_CLASS_IS_INTERFACE (klass))
                set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
 
-       if (num_array_interfaces) {
-               if (is_enumerator) {
-                       int ienumerator_idx = find_array_interface (klass, "IEnumerator`1");
-                       int ienumerator_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ienumerator_idx]);
-                       g_assert (ienumerator_offset >= 0);
-                       for (i = 0; i < num_array_interfaces; ++i) {
-                               ic = array_interfaces [i];
-                               if (strcmp (ic->name, "IEnumerator`1") == 0)
-                                       set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, ienumerator_offset, TRUE);
-                               else
-                                       g_assert_not_reached ();
-                               /*g_print ("type %s has %s offset at %d (%s)\n", klass->name, ic->name, interface_offsets_full [ic->interface_id], klass->interfaces [0]->name);*/
-                       }
-               } else {
-                       int ilist_offset, icollection_offset, ienumerable_offset, ireadonlylist_offset, ireadonlycollection_offset;
-                       int ilist_iface_idx = find_array_interface (klass, "IList`1");
-                       MonoClass* ilist_class = klass->interfaces [ilist_iface_idx];
-                       int ireadonlylist_iface_idx = find_array_interface (klass, "IReadOnlyList`1");
-                       MonoClass* ireadonlylist_class = ireadonlylist_iface_idx != -1 ? klass->interfaces [ireadonlylist_iface_idx] : NULL;
-                       int icollection_iface_idx = find_array_interface (ilist_class, "ICollection`1");
-                       int ienumerable_iface_idx = find_array_interface (ilist_class, "IEnumerable`1");
-                       int ireadonlycollection_iface_idx = ireadonlylist_iface_idx != -1 ? find_array_interface (ireadonlylist_class, "IReadOnlyCollection`1") : -1;
-                       ilist_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ilist_iface_idx]);
-                       icollection_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [icollection_iface_idx]);
-                       ienumerable_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [ienumerable_iface_idx]);
-                       ireadonlylist_offset = ireadonlylist_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ireadonlylist_iface_idx]) : -1;
-                       ireadonlycollection_offset = ireadonlycollection_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ireadonlylist_class->interfaces [ireadonlycollection_iface_idx]) : -1;
-                       g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
-                       for (i = 0; i < num_array_interfaces; ++i) {
-                               int offset;
-                               ic = array_interfaces [i];
-                               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;
-                               else if (strcmp (ic->name, "IEnumerable`1") == 0)
-                                       offset = ienumerable_offset;
-                               else if (strcmp (ic->name, "IReadOnlyList`1") == 0)
-                                       offset = ireadonlylist_offset;
-                               else if (strcmp (ic->name, "IReadOnlyCollection`1") == 0)
-                                       offset = ireadonlycollection_offset;
-                               else
-                                       g_assert_not_reached ();
-                               set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, offset, TRUE);
-                               /*g_print ("type %s has %s offset at %d (%s)\n", klass->name, ic->name, offset, klass->interfaces [0]->name);*/
-                       }
-               }
-       }
-
        for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
                if (interface_offsets_full [i] != -1)
                        interface_offsets_count ++;
@@ -3779,8 +3417,6 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                        bitmap [id >> 3] |= (1 << (id & 7));
                        klass->interfaces_packed [i] = interfaces_full [i];
                        klass->interface_offsets_packed [i] = interface_offsets_full [i];
-                       /*if (num_array_interfaces)
-                         g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&klass->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/
                }
 #ifdef COMPRESSED_INTERFACE_BITMAP
                i = mono_compress_bitmap (NULL, bitmap, bsize);
@@ -3796,7 +3432,6 @@ end:
 
        g_free (interfaces_full);
        g_free (interface_offsets_full);
-       g_free (array_interfaces);
        for (i = 0; i < klass->idepth; i++) {
                ifaces = ifaces_array [i];
                if (ifaces)
@@ -4052,7 +3687,7 @@ is_wcf_hack_disabled (void)
        static gboolean disabled;
        static gboolean inited = FALSE;
        if (!inited) {
-               disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
+               disabled = g_hasenv ("MONO_DISABLE_WCF_HACK");
                inited = TRUE;
        }
        return disabled;
@@ -4839,6 +4474,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
        g_slist_free (virt_methods);
        virt_methods = NULL;
 
+       g_assert (cur_slot <= max_vtsize);
+
        /* Ensure that all vtable slots are filled with concrete instance methods */
        if (!mono_class_is_abstract (klass)) {
                for (i = 0; i < cur_slot; ++i) {
@@ -4987,7 +4624,7 @@ mono_method_get_vtable_slot (MonoMethod *method)
 
 /**
  * mono_method_get_vtable_index:
- * @method: a method
+ * \param method a method
  *
  * Returns the index into the runtime vtable to access the method or,
  * in the case of a virtual generic method, the virtual generic method
@@ -5105,7 +4742,7 @@ generic_array_methods (MonoClass *klass)
 }
 
 static void
-setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos)
+setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
 {
        MonoGenericContext tmp_context;
        int i;
@@ -5117,11 +4754,16 @@ setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **met
        for (i = 0; i < generic_array_method_num; i++) {
                MonoError error;
                MonoMethod *m = generic_array_method_info [i].array_method;
-               MonoMethod *inflated;
+               MonoMethod *inflated, *helper;
 
                inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, &error);
-               g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
-               methods [pos++] = mono_marshal_get_generic_array_helper (klass, iface, generic_array_method_info [i].name, inflated);
+               mono_error_assert_ok (&error);
+               helper = g_hash_table_lookup (cache, inflated);
+               if (!helper) {
+                       helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
+                       g_hash_table_insert (cache, inflated, helper);
+               }
+               methods [pos ++] = helper;
        }
 }
 
@@ -5141,19 +4783,20 @@ concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
 
 /**
  * mono_class_init:
- * @klass: the class to initialize
+ * \param 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).
- * Initializes the following fields in @klass:
- * - all the fields initialized by mono_class_init_sizes ()
+ * Compute the \c instance_size, \c class_size and other infos that cannot be 
+ * computed at \c mono_class_get time. Also compute vtable_size if possible. 
+ * Initializes the following fields in \p klass:
+ * - all the fields initialized by \c mono_class_init_sizes
  * - has_cctor
  * - ghcimpl
  * - inited
  *
  * LOCKING: Acquires the loader lock.
+ *
+ * \returns TRUE on success or FALSE if there was a problem in loading
+ * the type (incorrect assemblies, missing assemblies, methods, etc).
  */
 gboolean
 mono_class_init (MonoClass *klass)
@@ -5383,13 +5026,14 @@ mono_class_init (MonoClass *klass)
        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;
-
        if (locked)
                mono_loader_unlock ();
 
+       /* Leave this for last */
+       mono_loader_lock ();
+       klass->inited = 1;
+       mono_loader_unlock ();
+
        return !mono_class_has_failure (klass);
 }
 
@@ -5444,16 +5088,14 @@ mono_class_has_finalizer (MonoClass *klass)
                }
        }
 
-       mono_image_lock (klass->image);
-
+       mono_loader_lock ();
        if (!klass->has_finalize_inited) {
                klass->has_finalize = has_finalize ? 1 : 0;
 
                mono_memory_barrier ();
                klass->has_finalize_inited = TRUE;
        }
-
-       mono_image_unlock (klass->image);
+       mono_loader_unlock ();
 
        return klass->has_finalize;
 }
@@ -5588,8 +5230,22 @@ mono_class_setup_mono_type (MonoClass *klass)
                klass->this_arg.type = (MonoTypeEnum)t;
        }
 
-       if (MONO_CLASS_IS_INTERFACE (klass))
+       if (MONO_CLASS_IS_INTERFACE (klass)) {
                klass->interface_id = mono_get_unique_iid (klass);
+
+               if (is_corlib && !strcmp (nspace, "System.Collections.Generic")) {
+                       //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
+                   /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
+                   * MS returns diferrent types based on which instance is called. For example:
+                   *   object obj = new byte[10][];
+                   *   Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
+                   *   Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
+                   *   a != b ==> true
+                       */
+                       if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
+                               klass->is_array_special_interface = 1;
+               }
+       }
 }
 
 #ifndef DISABLE_COM
@@ -5761,6 +5417,12 @@ mono_class_setup_supertypes (MonoClass *klass)
        mono_loader_unlock ();
 }
 
+static gboolean
+discard_gclass_due_to_failure (MonoClass *gclass, void *user_data)
+{
+       return mono_class_get_generic_class (gclass)->container_class == user_data;
+}
+
 static gboolean
 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
 {
@@ -5785,12 +5447,12 @@ mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char
 
 /**
  * mono_class_create_from_typedef:
- * @image: image where the token is valid
- * @type_token:  typedef token
- * @error:  used to return any error found while creating the type
+ * \param image: image where the token is valid
+ * \param type_token:  typedef token
+ * \param error:  used to return any error found while creating the type
  *
  * Create the MonoClass* representing the specified type token.
- * @type_token must be a TypeDef token.
+ * \p type_token must be a TypeDef token.
  *
  * FIXME: don't return NULL on failure, just the the caller figure it out.
  */
@@ -5809,7 +5471,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        guint32 field_last, method_last;
        guint32 nesting_tokeen;
 
-       mono_error_init (error);
+       error_init (error);
 
        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);
@@ -5928,6 +5590,42 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 #endif
 
        klass->cast_class = klass->element_class = klass;
+       if (mono_is_corlib_image (klass->image)) {
+               switch (klass->byval_arg.type) {
+                       case MONO_TYPE_I1:
+                               if (mono_defaults.byte_class)
+                                       klass->cast_class = mono_defaults.byte_class;
+                               break;
+                       case MONO_TYPE_U1:
+                               if (mono_defaults.sbyte_class)
+                                       mono_defaults.sbyte_class = klass;
+                               break;
+                       case MONO_TYPE_I2:
+                               if (mono_defaults.uint16_class)
+                                       mono_defaults.uint16_class = klass;
+                               break;
+                       case MONO_TYPE_U2:
+                               if (mono_defaults.int16_class)
+                                       klass->cast_class = mono_defaults.int16_class;
+                               break;
+                       case MONO_TYPE_I4:
+                               if (mono_defaults.uint32_class)
+                                       mono_defaults.uint32_class = klass;
+                               break;
+                       case MONO_TYPE_U4:
+                               if (mono_defaults.int32_class)
+                                       klass->cast_class = mono_defaults.int32_class;
+                               break;
+                       case MONO_TYPE_I8:
+                               if (mono_defaults.uint64_class)
+                                       mono_defaults.uint64_class = klass;
+                               break;
+                       case MONO_TYPE_U8:
+                               if (mono_defaults.int64_class)
+                                       klass->cast_class = mono_defaults.int64_class;
+                               break;
+               }
+       }
 
        if (!klass->enumtype) {
                if (!mono_metadata_interfaces_from_typedef_full (
@@ -6009,9 +5707,6 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) {
                if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
                        klass->simd_type = 1;
-       } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (nspace, "System.Numerics")) {
-               if (!strcmp (name, "Vector`1"))
-                       klass->simd_type = 1;
        }
 
        mono_loader_unlock ();
@@ -6021,6 +5716,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        return klass;
 
 parent_failure:
+       if (mono_class_is_gtd (klass))
+               disable_gclass_recording (discard_gclass_due_to_failure, klass);
+
        mono_class_setup_mono_type (klass);
        mono_loader_unlock ();
        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
@@ -6059,6 +5757,7 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
                        mono_error_cleanup (&error);
                }
        }
+       mono_loader_lock ();
        if (klass->parent)
                mono_class_setup_parent (klass, klass->parent);
 
@@ -6066,8 +5765,15 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
                klass->cast_class = gtd->cast_class;
                klass->element_class = gtd->element_class;
        }
+       mono_loader_unlock ();
 }
 
+gboolean
+mono_type_is_primitive (MonoType *type)
+{
+       return (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_R8) ||
+                       type-> type == MONO_TYPE_I || type->type == MONO_TYPE_U;
+}
 
 /*
  * Create the `MonoClass' for an instantiation of a generic type.
@@ -6081,19 +5787,10 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        if (gclass->cached_class)
                return gclass->cached_class;
 
-       mono_loader_lock ();
-       if (gclass->cached_class) {
-               mono_loader_unlock ();
-               return gclass->cached_class;
-       }
-
        klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
 
        gklass = gclass->container_class;
 
-       if (record_gclass_instantiation > 0)
-               gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
-
        if (gklass->nested_in) {
                /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
                klass->nested_in = gklass->nested_in;
@@ -6102,8 +5799,6 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        klass->name = gklass->name;
        klass->name_space = gklass->name_space;
        
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
-       
        klass->image = gklass->image;
        klass->type_token = gklass->type_token;
 
@@ -6117,19 +5812,17 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        klass->this_arg.byref = TRUE;
        klass->enumtype = gklass->enumtype;
        klass->valuetype = gklass->valuetype;
-       klass->simd_type = gklass->simd_type;
-
-       klass->cast_class = klass->element_class = klass;
 
-       if (mono_class_is_nullable (klass))
-               klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
 
-       /*
-        * We're not interested in the nested classes of a generic instance.
-        * We use the generic type definition to look for nested classes.
-        */
+       if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
+               g_assert (gclass->context.class_inst);
+               g_assert (gclass->context.class_inst->type_argc > 0);
+               if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
+                       klass->simd_type = 1;
+       }
+       klass->is_array_special_interface = gklass->is_array_special_interface;
 
-       mono_generic_class_setup_parent (klass, gklass);
+       klass->cast_class = klass->element_class = klass;
 
        if (gclass->is_dynamic) {
                /*
@@ -6140,8 +5833,6 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
                if (!gklass->wastypebuilder)
                        klass->inited = 1;
 
-               mono_class_setup_supertypes (klass);
-
                if (klass->enumtype) {
                        /*
                         * For enums, gklass->fields might not been set, but instance_size etc. is 
@@ -6150,11 +5841,30 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
                         */
                        klass->instance_size = gklass->instance_size;
                        klass->sizes.class_size = gklass->sizes.class_size;
-                       mono_memory_barrier ();
                        klass->size_inited = 1;
                }
        }
 
+       mono_loader_lock ();
+
+       if (gclass->cached_class) {
+               mono_loader_unlock ();
+               return gclass->cached_class;
+       }
+
+       if (record_gclass_instantiation > 0)
+               gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
+
+       if (mono_class_is_nullable (klass))
+               klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
+
+       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+
+       mono_generic_class_setup_parent (klass, gklass);
+
+       if (gclass->is_dynamic)
+               mono_class_setup_supertypes (klass);
+
        mono_memory_barrier ();
        gclass->cached_class = klass;
 
@@ -6469,9 +6179,9 @@ mono_class_from_generic_parameter_internal (MonoGenericParam *param)
 
 /**
  * mono_class_from_generic_parameter:
- * @param: Parameter to find/construct a class for.
- * @arg2: Is ignored.
- * @arg3: Is ignored.
+ * \param param Parameter to find/construct a class for.
+ * \param arg2 Is ignored.
+ * \param arg3 Is ignored.
  */
 MonoClass *
 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GNUC_UNUSED, gboolean arg3 G_GNUC_UNUSED)
@@ -6479,7 +6189,9 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GN
        return mono_class_from_generic_parameter_internal (param);
 }
 
-
+/**
+ * mono_ptr_class_get:
+ */
 MonoClass *
 mono_ptr_class_get (MonoType *type)
 {
@@ -6549,46 +6261,52 @@ mono_ptr_class_get (MonoType *type)
 static MonoClass *
 mono_fnptr_class_get (MonoMethodSignature *sig)
 {
-       MonoClass *result;
+       MonoClass *result, *cached;
        static GHashTable *ptr_hash = NULL;
 
        /* FIXME: These should be allocate from a mempool as well, but which one ? */
 
        mono_loader_lock ();
-
        if (!ptr_hash)
                ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
-       
-       if ((result = (MonoClass *)g_hash_table_lookup (ptr_hash, sig))) {
-               mono_loader_unlock ();
-               return result;
-       }
-       result = g_new0 (MonoClass, 1);
+       cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
+       mono_loader_unlock ();
+       if (cached)
+               return cached;
 
-       classes_size += sizeof (MonoClassPointer);
-       ++class_pointer_count;
+       result = g_new0 (MonoClass, 1);
 
        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->instance_size = sizeof (MonoObject) + sizeof (gpointer);
        result->cast_class = result->element_class = result;
-       result->blittable = TRUE;
-
        result->byval_arg.type = MONO_TYPE_FNPTR;
        result->this_arg.type = result->byval_arg.type;
        result->this_arg.data.method = result->byval_arg.data.method = sig;
        result->this_arg.byref = TRUE;
        result->blittable = TRUE;
+       result->inited = TRUE;
 
        mono_class_setup_supertypes (result);
 
+       mono_loader_lock ();
+
+       cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
+       if (cached) {
+               g_free (result);
+               mono_loader_unlock ();
+               return cached;
+       }
+
+       mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+
+       classes_size += sizeof (MonoClassPointer);
+       ++class_pointer_count;
+
        g_hash_table_insert (ptr_hash, sig, result);
 
        mono_loader_unlock ();
@@ -6600,9 +6318,8 @@ mono_fnptr_class_get (MonoMethodSignature *sig)
 
 /**
  * mono_class_from_mono_type:
- * @type: describes the type to return
- *
- * This returns a MonoClass for the specified MonoType, the value is never NULL.
+ * \param type describes the type to return
+ * \returns a \c MonoClass for the specified \c MonoType, the value is never NULL.
  */
 MonoClass *
 mono_class_from_mono_type (MonoType *type)
@@ -6672,9 +6389,9 @@ mono_class_from_mono_type (MonoType *type)
 
 /**
  * mono_type_retrieve_from_typespec
- * @image: context where the image is created
- * @type_spec:  typespec token
- * @context: the generic context used to evaluate generic instantiations in
+ * \param image context where the image is created
+ * \param type_spec  typespec token
+ * \param context the generic context used to evaluate generic instantiations in
  */
 static MonoType *
 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
@@ -6703,9 +6420,9 @@ mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGener
 
 /**
  * mono_class_create_from_typespec
- * @image: context where the image is created
- * @type_spec:  typespec token
- * @context: the generic context used to evaluate generic instantiations in
+ * \param image context where the image is created
+ * \param type_spec typespec token
+ * \param context the generic context used to evaluate generic instantiations in
  */
 static MonoClass *
 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
@@ -6722,18 +6439,17 @@ mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGeneri
 
 /**
  * mono_bounded_array_class_get:
- * @element_class: element class 
- * @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 
- * dimension @rank. 
+ * \param element_class element class 
+ * \param rank the dimension of the array class
+ * \param bounded whenever the array has non-zero bounds
+ * \returns A class object describing the array with element type \p element_type and 
+ * dimension \p rank.
  */
 MonoClass *
 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 {
        MonoImage *image;
-       MonoClass *klass;
+       MonoClass *klass, *cached, *k;
        MonoClass *parent = NULL;
        GSList *list, *rootlist = NULL;
        int nsize;
@@ -6747,37 +6463,35 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        image = eclass->image;
 
+       /* Check cache */
+       cached = NULL;
        if (rank == 1 && !bounded) {
-               /* 
-                * This case is very frequent not just during compilation because of calls 
-                * from mono_class_from_mono_type (), mono_array_new (), 
+               /*
+                * This case is very frequent not just during compilation because of calls
+                * from mono_class_from_mono_type (), mono_array_new (),
                 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
                 */
                mono_os_mutex_lock (&image->szarray_cache_lock);
                if (!image->szarray_cache)
                        image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
-               klass = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
+               cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
                mono_os_mutex_unlock (&image->szarray_cache_lock);
-               if (klass)
-                       return klass;
-
-               mono_loader_lock ();
        } else {
                mono_loader_lock ();
-
                if (!image->array_cache)
                        image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
-
-               if ((rootlist = list = (GSList *)g_hash_table_lookup (image->array_cache, eclass))) {
-                       for (; list; list = list->next) {
-                               klass = (MonoClass *)list->data;
-                               if ((klass->rank == rank) && (klass->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
-                                       mono_loader_unlock ();
-                                       return klass;
-                               }
+               rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
+               for (list = rootlist; list; list = list->next) {
+                       k = (MonoClass *)list->data;
+                       if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
+                               cached = k;
+                               break;
                        }
                }
+               mono_loader_unlock ();
        }
+       if (cached)
+               return cached;
 
        parent = mono_defaults.array_class;
        if (!parent->inited)
@@ -6802,20 +6516,15 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
        klass->name = mono_image_strdup (image, name);
        g_free (name);
 
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
-
-       classes_size += sizeof (MonoClassArray);
-       ++class_array_count;
-
        klass->type_token = 0;
        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) {
+       if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF) {
                /*Arrays of those two types are invalid.*/
                MonoError prepared_error;
-               mono_error_init (&prepared_error);
-               mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
+               error_init (&prepared_error);
+               mono_error_set_invalid_program (&prepared_error, "Arrays of 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)) {
@@ -6888,19 +6597,47 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
        klass->this_arg = klass->byval_arg;
        klass->this_arg.byref = 1;
 
-       //WTF was this? it's wrong
-       // klass->generic_container = eclass->generic_container;
+       if (rank > 32) {
+               MonoError prepared_error;
+               error_init (&prepared_error);
+               name = mono_type_get_full_name (klass);
+               mono_error_set_type_load_class (&prepared_error, klass, "%s has too many dimensions.", name);
+               mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
+               mono_error_cleanup (&prepared_error);
+               g_free (name);
+       }
+
+       mono_loader_lock ();
 
+       /* Check cache again */
+       cached = NULL;
        if (rank == 1 && !bounded) {
-               MonoClass *prev_class;
+               mono_os_mutex_lock (&image->szarray_cache_lock);
+               cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
+               mono_os_mutex_unlock (&image->szarray_cache_lock);
+       } else {
+               rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
+               for (list = rootlist; list; list = list->next) {
+                       k = (MonoClass *)list->data;
+                       if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
+                               cached = k;
+                               break;
+                       }
+               }
+       }
+       if (cached) {
+               mono_loader_unlock ();
+               return cached;
+       }
+
+       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+
+       classes_size += sizeof (MonoClassArray);
+       ++class_array_count;
 
+       if (rank == 1 && !bounded) {
                mono_os_mutex_lock (&image->szarray_cache_lock);
-               prev_class = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
-               if (prev_class)
-                       /* Someone got in before us */
-                       klass = prev_class;
-               else
-                       g_hash_table_insert (image->szarray_cache, eclass, klass);
+               g_hash_table_insert (image->szarray_cache, eclass, klass);
                mono_os_mutex_unlock (&image->szarray_cache_lock);
        } else {
                list = g_slist_append (rootlist, klass);
@@ -6916,11 +6653,10 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
 /**
  * mono_array_class_get:
- * @element_class: element class 
- * @rank: the dimension of the array class
- *
- * Returns: A class object describing the array with element type @element_type and 
- * dimension @rank. 
+ * \param element_class element class 
+ * \param rank the dimension of the array class
+ * \returns A class object describing the array with element type \p element_type and 
+ * dimension \p rank.
  */
 MonoClass *
 mono_array_class_get (MonoClass *eclass, guint32 rank)
@@ -6930,11 +6666,11 @@ mono_array_class_get (MonoClass *eclass, guint32 rank)
 
 /**
  * mono_class_instance_size:
- * @klass: a class 
+ * \param klass a class
  *
  * Use to get the size of a class in bytes.
  *
- * Returns: The size of an object instance
+ * \returns The size of an object instance
  */
 gint32
 mono_class_instance_size (MonoClass *klass)
@@ -6947,7 +6683,7 @@ mono_class_instance_size (MonoClass *klass)
 
 /**
  * mono_class_min_align:
- * @klass: a class 
+ * \param klass a class 
  *
  * Use to get the computed minimum alignment requirements for the specified class.
  *
@@ -6964,12 +6700,12 @@ mono_class_min_align (MonoClass *klass)
 
 /**
  * mono_class_value_size:
- * @klass: a class 
+ * \param klass a class 
  *
  * This function is used for value types, and return the
  * space and the alignment to store that kind of value object.
  *
- * Returns: the size of a value of kind @klass
+ * \returns the size of a value of kind \p klass
  */
 gint32
 mono_class_value_size (MonoClass *klass, guint32 *align)
@@ -6991,9 +6727,9 @@ mono_class_value_size (MonoClass *klass, guint32 *align)
 
 /**
  * mono_class_data_size:
- * @klass: a class 
+ * \param 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)
@@ -7054,10 +6790,10 @@ mono_class_get_field_idx (MonoClass *klass, int idx)
 
 /**
  * mono_class_get_field:
- * @class: the class to lookup the field.
- * @field_token: the field token
+ * \param class the class to lookup the field.
+ * \param field_token the field token
  *
- * Returns: A MonoClassField representing the type and offset of
+ * \returns A \c MonoClassField representing the type and offset of
  * the field, or a NULL value if the field does not belong to this
  * class.
  */
@@ -7073,12 +6809,12 @@ mono_class_get_field (MonoClass *klass, guint32 field_token)
 
 /**
  * mono_class_get_field_from_name:
- * @klass: the class to lookup the field.
- * @name: the field name
+ * \param klass the class to lookup the field.
+ * \param name the field name
  *
- * Search the class @klass and it's parents for a field with the name @name.
+ * Search the class \p klass and its parents for a field with the name \p name.
  * 
- * Returns: The MonoClassField pointer of the named field or NULL
+ * \returns The \c MonoClassField pointer of the named field or NULL
  */
 MonoClassField *
 mono_class_get_field_from_name (MonoClass *klass, const char *name)
@@ -7088,16 +6824,16 @@ mono_class_get_field_from_name (MonoClass *klass, const char *name)
 
 /**
  * mono_class_get_field_from_name_full:
- * @klass: the class to lookup the field.
- * @name: the field name
- * @type: the type of the fields. This optional.
+ * \param klass the class to lookup the field.
+ * \param name the field name
+ * \param type the type of the fields. This optional.
  *
- * Search the class @klass and it's parents for a field with the name @name and type @type.
+ * Search the class \p klass and it's parents for a field with the name \p name and type \p type.
  *
- * If @klass is an inflated generic type, the type comparison is done with the equivalent field
+ * If \p 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)
@@ -7130,12 +6866,12 @@ mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoTyp
 
 /**
  * mono_class_get_field_token:
- * @field: the field we need the token of
+ * \param field the field we need the token of
  *
  * 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)
@@ -7187,28 +6923,20 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ
        guint32 constant_cols [MONO_CONSTANT_SIZE];
        int field_index;
        MonoClass *klass = field->parent;
+       MonoFieldDefaultValue *def_values;
 
        g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
 
-       MonoClassExt *ext = mono_class_get_ext (klass);
-       if (!ext || !ext->field_def_values) {
-               MonoFieldDefaultValue *def_values;
-
-               mono_class_alloc_ext (klass);
-               ext = mono_class_get_ext (klass);
-
+       def_values = mono_class_get_field_def_values (klass);
+       if (!def_values) {
                def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
 
-               mono_image_lock (klass->image);
-               mono_memory_barrier ();
-               if (!ext->field_def_values)
-                       ext->field_def_values = def_values;
-               mono_image_unlock (klass->image);
+               mono_class_set_field_def_values (klass, def_values);
        }
 
        field_index = mono_field_get_index (field);
                
-       if (!ext->field_def_values [field_index].data) {
+       if (!def_values [field_index].data) {
                cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
                if (!cindex)
                        return NULL;
@@ -7216,21 +6944,22 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ
                g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
 
                mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
-               ext->field_def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
-               ext->field_def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
+               def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
+               mono_memory_barrier ();
+               def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
        }
 
-       *def_type = ext->field_def_values [field_index].def_type;
-       return ext->field_def_values [field_index].data;
+       *def_type = def_values [field_index].def_type;
+       return def_values [field_index].data;
 }
 
 static int
 mono_property_get_index (MonoProperty *prop)
 {
-       MonoClassExt *ext = mono_class_get_ext (prop->parent);
-       int index = prop - ext->properties;
+       MonoClassPropertyInfo *info = mono_class_get_property_info (prop->parent);
+       int index = prop - info->properties;
 
-       g_assert (index >= 0 && index < ext->property.count);
+       g_assert (index >= 0 && index < info->count);
 
        return index;
 }
@@ -7255,11 +6984,11 @@ mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def
         */
 
        if (image_is_dynamic (klass->image)) {
-               MonoClassExt *ext = mono_class_get_ext (klass);
+               MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
                int prop_index = mono_property_get_index (property);
-               if (ext->prop_def_values && ext->prop_def_values [prop_index].data) {
-                       *def_type = ext->prop_def_values [prop_index].def_type;
-                       return ext->prop_def_values [prop_index].data;
+               if (info->def_values && info->def_values [prop_index].data) {
+                       *def_type = info->def_values [prop_index].def_type;
+                       return info->def_values [prop_index].data;
                }
                return NULL;
        }
@@ -7272,6 +7001,9 @@ mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def
        return (const char *)mono_metadata_blob_heap (klass->image, constant_cols [MONO_CONSTANT_VALUE]);
 }
 
+/**
+ * mono_class_get_event_token:
+ */
 guint32
 mono_class_get_event_token (MonoEvent *event)
 {
@@ -7279,11 +7011,11 @@ mono_class_get_event_token (MonoEvent *event)
        int i;
 
        while (klass) {
-               MonoClassExt *ext = mono_class_get_ext (klass);
-               if (ext) {
-                       for (i = 0; i < ext->event.count; ++i) {
-                               if (&ext->events [i] == event)
-                                       return mono_metadata_make_token (MONO_TABLE_EVENT, ext->event.first + i + 1);
+               MonoClassEventInfo *info = mono_class_get_event_info (klass);
+               if (info) {
+                       for (i = 0; i < info->count; ++i) {
+                               if (&info->events [i] == event)
+                                       return mono_metadata_make_token (MONO_TABLE_EVENT, info->first + i + 1);
                        }
                }
                klass = klass->parent;
@@ -7295,12 +7027,12 @@ mono_class_get_event_token (MonoEvent *event)
 
 /**
  * mono_class_get_property_from_name:
- * @klass: a class
- * @name: name of the property to lookup in the specified class
+ * \param klass a class
+ * \param 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.
+ * \returns the \c MonoProperty with the given name, or NULL if the property
+ * does not exist on the \p klass.
  */
 MonoProperty*
 mono_class_get_property_from_name (MonoClass *klass, const char *name)
@@ -7319,9 +7051,9 @@ mono_class_get_property_from_name (MonoClass *klass, const char *name)
 
 /**
  * mono_class_get_property_token:
- * @prop: MonoProperty to query
+ * \param prop MonoProperty to query
  *
- * Returns: The ECMA token for the specified property.
+ * \returns The ECMA token for the specified property.
  */
 guint32
 mono_class_get_property_token (MonoProperty *prop)
@@ -7331,10 +7063,10 @@ mono_class_get_property_token (MonoProperty *prop)
                MonoProperty* p;
                int i = 0;
                gpointer iter = NULL;
-               MonoClassExt *ext = mono_class_get_ext (klass);
+               MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
                while ((p = mono_class_get_properties (klass, &iter))) {
-                       if (&ext->properties [i] == prop)
-                               return mono_metadata_make_token (MONO_TABLE_PROPERTY, ext->property.first + i + 1);
+                       if (&info->properties [i] == prop)
+                               return mono_metadata_make_token (MONO_TABLE_PROPERTY, info->first + i + 1);
                        
                        i ++;
                }
@@ -7345,6 +7077,9 @@ mono_class_get_property_token (MonoProperty *prop)
        return 0;
 }
 
+/**
+ * mono_class_name_from_token:
+ */
 char *
 mono_class_name_from_token (MonoImage *image, guint32 type_token)
 {
@@ -7462,12 +7197,11 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
 
 /**
  * mono_class_get_full:
- * @image: the image where the class resides
- * @type_token: the token for the class
- * @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
+ * \param image the image where the class resides
+ * \param type_token the token for the class
+ * \param context the generic context used to evaluate generic instantiations in
+ * \deprecated Functions that expose \c MonoGenericContext are going away in mono 4.0
+ * \returns The \c MonoClass that represents \p type_token in \p image
  */
 MonoClass *
 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
@@ -7489,7 +7223,7 @@ mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_toke
 {
        MonoClass *klass;
 
-       mono_error_init (error);
+       error_init (error);
        klass = mono_class_get_checked (image, type_token, error);
 
        if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
@@ -7499,18 +7233,18 @@ mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_toke
 }
 /**
  * mono_class_get_checked:
- * @image: the image where the class resides
- * @type_token: the token for the class
- * @error: error object to return any error
+ * \param image the image where the class resides
+ * \param type_token the token for the class
+ * \param error error object to return any error
  *
- * Returns: The MonoClass that represents @type_token in @image, or NULL on error.
+ * \returns The MonoClass that represents \p type_token in \p image, or NULL on error.
  */
 MonoClass *
 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
 {
        MonoClass *klass = NULL;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (image_is_dynamic (image)) {
                int table = mono_metadata_token_table (type_token);
@@ -7542,7 +7276,7 @@ done:
        if (!klass && mono_error_ok (error)) {
                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_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x (class/assembly %s, %s)", type_token, name, assembly);
        }
 
        return klass;
@@ -7551,14 +7285,14 @@ done:
 
 /**
  * mono_type_get_checked:
- * @image: the image where the type resides
- * @type_token: the token for the type
- * @context: the generic context used to evaluate generic instantiations in
- * @error: Error handling context
+ * \param image the image where the type resides
+ * \param type_token the token for the type
+ * \param context the generic context used to evaluate generic instantiations in
+ * \param error Error handling context
  *
  * 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 \p type_token in \p image
  */
 MonoType *
 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
@@ -7566,7 +7300,7 @@ mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext
        MonoType *type = NULL;
        gboolean inflated = FALSE;
 
-       mono_error_init (error);
+       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)) {
@@ -7611,10 +7345,9 @@ mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext
 
 /**
  * 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
+ * \param image image where the class token will be looked up.
+ * \param type_token a type token from the image
+ * \returns the \c MonoClass with the given \p type_token on the \p image
  */
 MonoClass *
 mono_class_get (MonoImage *image, guint32 type_token)
@@ -7724,6 +7457,9 @@ mono_image_init_name_cache (MonoImage *image)
 }
 
 /*FIXME Only dynamic assemblies should allow this operation.*/
+/**
+ * mono_image_add_to_name_cache:
+ */
 void
 mono_image_add_to_name_cache (MonoImage *image, const char *nspace, 
                                                          const char *name, guint32 index)
@@ -7766,13 +7502,13 @@ find_nocase (gpointer key, gpointer value, gpointer user_data)
 
 /**
  * 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.
- * @deprecated: use the mono_class_from_name_case_checked variant instead.
+ * \param image The MonoImage where the type is looked up in
+ * \param name_space the type namespace
+ * \param name the type short name.
+ * \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
+ * Obtains a \c MonoClass with a given namespace and a given name which
+ * is located in the given \c MonoImage.   The namespace and name
  * lookups are case insensitive.
  */
 MonoClass *
@@ -7786,18 +7522,18 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
 }
 
 /**
- * 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 
+ * mono_class_from_name_case_checked:
+ * \param image The MonoImage where the type is looked up in
+ * \param name_space the type namespace
+ * \param name the type short name.
+ * \param 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
+ * \returns The MonoClass if the given namespace and name were found, or NULL if it
+ * was not found.   The \p error object will contain information about the problem
  * in that case.
  */
 MonoClass *
@@ -7809,7 +7545,7 @@ mono_class_from_name_case_checked (MonoImage *image, const char *name_space, con
        const char *nspace;
        guint32 i, visib;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (image_is_dynamic (image)) {
                guint32 token = 0;
@@ -7891,7 +7627,7 @@ search_modules (MonoImage *image, const char *name_space, const char *name, Mono
        MonoClass *klass;
        int i;
 
-       mono_error_init (error);
+       error_init (error);
 
        /* 
         * The EXPORTEDTYPES table only contains public types, so have to search the
@@ -7927,7 +7663,7 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons
        char *nested;
        char buf [1024];
 
-       mono_error_init (error);
+       error_init (error);
 
        // Checking visited images avoids stack overflows when cyclic references exist.
        if (g_hash_table_lookup (visited_images, image))
@@ -8036,9 +7772,9 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons
 
 /**
  * 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.
+ * \param image The MonoImage where the type is looked up in
+ * \param name_space the type namespace
+ * \param name the type short name.
  *
  * Obtains a MonoClass with a given namespace and a given name which
  * is located in the given MonoImage.
@@ -8063,16 +7799,16 @@ mono_class_from_name_checked (MonoImage *image, const char* name_space, const ch
 
 /**
  * mono_class_from_name:
- * @image: The MonoImage where the type is looked up in
- * @name_space: the type namespace
- * @name: the type short name.
+ * \param image The \c MonoImage where the type is looked up in
+ * \param name_space the type namespace
+ * \param name the type short name.
  *
- * Obtains a MonoClass with a given namespace and a given name which
- * is located in the given MonoImage.
+ * Obtains a \c MonoClass with a given namespace and a given name which
+ * is located in the given \c MonoImage.
  *
  * To reference nested classes, use the "/" character as a separator.
- * For example use "Foo/Bar" to reference the class Bar that is nested
- * inside Foo, like this: "class Foo { class Bar {} }".
+ * For example use \c "Foo/Bar" to reference the class \c Bar that is nested
+ * inside \c Foo, like this: "class Foo { class Bar {} }".
  */
 MonoClass *
 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
@@ -8088,9 +7824,9 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
 
 /**
  * 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.
+ * \param image The MonoImage where the type is looked up in
+ * \param name_space the type namespace
+ * \param 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
@@ -8112,9 +7848,9 @@ mono_class_load_from_name (MonoImage *image, const char* name_space, const char
 
 /**
  * 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.
+ * \param image The MonoImage where the type is looked up in
+ * \param name_space the type namespace
+ * \param 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.
@@ -8138,21 +7874,21 @@ mono_class_try_load_from_name (MonoImage *image, const char* name_space, const c
 
 /**
  * mono_class_is_subclass_of:
- * @klass: class to probe if it is a subclass of another one
- * @klassc: the class we suspect is the base class
- * @check_interfaces: whether we should perform interface checks
+ * \param klass class to probe if it is a subclass of another one
+ * \param klassc the class we suspect is the base class
+ * \param check_interfaces whether we should perform interface checks
  *
- * This method determines whether @klass is a subclass of @klassc.
+ * This method determines whether \p klass is a subclass of \p 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
- * if @klass is an interface, if one of its base classes is @klass.
+ * If the \p check_interfaces flag is set, then if \p klassc is an interface
+ * this method return TRUE if the \p klass implements the interface or
+ * if \p klass is an interface, if one of its base classes is \p 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.
+ * If \p check_interfaces is false, then if \p klass is not an interface,
+ * it returns TRUE if the \p klass is a subclass of \p klassc.
  *
- * if @klass is an interface and @klassc is System.Object, then this function
- * return true.
+ * if \p klass is an interface and \p klassc is \c System.Object, then this function
+ * returns TRUE.
  *
  */
 gboolean
@@ -8388,11 +8124,11 @@ mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
 
 /**
  * mono_class_is_assignable_from:
- * @klass: the class to be assigned to
- * @oklass: the source class
+ * \param klass the class to be assigned to
+ * \param oklass the source class
  *
- * Returns: TRUE if an instance of object oklass can be assigned to an
- * instance of object @klass
+ * \returns TRUE if an instance of class \p oklass can be assigned to an
+ * instance of class \p klass
  */
 gboolean
 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
@@ -8449,6 +8185,23 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
                        return TRUE;
 
+               if (klass->is_array_special_interface && oklass->rank == 1) {
+                       //XXX we could offset this by having the cast target computed at JIT time
+                       //XXX we could go even further and emit a wrapper that would do the extra type check
+                       MonoClass *iface_klass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
+                       MonoClass *obj_klass = oklass->cast_class; //This gets us the cast class of element type of the array
+
+                       // If the target we're trying to cast to is a valuetype, we must account of weird valuetype equivalences such as IntEnum <> int or uint <> int
+                       // We can't apply it for ref types as this would go wrong with arrays - IList<byte[]> would have byte tested
+                       if (iface_klass->valuetype)
+                               iface_klass = iface_klass->cast_class;
+
+                       //array covariant casts only operates on scalar to scalar
+                       //This is so int[] can't be casted to IComparable<int>[]
+                       if (!(obj_klass->valuetype && !iface_klass->valuetype) && mono_class_is_assignable_from (iface_klass, obj_klass))
+                               return TRUE;
+               }
+
                if (mono_class_has_variant_generic_params (klass)) {
                        int i;
                        mono_class_setup_interfaces (oklass, &error);
@@ -8565,7 +8318,7 @@ mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
 
                /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
                if (image_is_dynamic (candidate->image) && !candidate->wastypebuilder) {
-                       MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info (candidate);
+                       MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info_raw (candidate); /* FIXME use handles */
                        int j;
                        if (tb && tb->interfaces) {
                                for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
@@ -8669,9 +8422,9 @@ mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
 
 /**
  * mono_class_get_cctor:
- * @klass: A MonoClass pointer
+ * \param klass A MonoClass pointer
  *
- * Returns: The static constructor of @klass if it exists, NULL otherwise.
+ * \returns The static constructor of \p klass if it exists, NULL otherwise.
  */
 MonoMethod*
 mono_class_get_cctor (MonoClass *klass)
@@ -8686,9 +8439,14 @@ mono_class_get_cctor (MonoClass *klass)
                return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
        }
 
+       mono_class_init (klass);
+
        if (!klass->has_cctor)
                return NULL;
 
+       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));
+
        if (mono_class_get_cached_class_info (klass, &cached_info)) {
                MonoError error;
                MonoMethod *result = mono_get_method_checked (klass->image, cached_info.cctor_token, klass, NULL, &error);
@@ -8697,17 +8455,14 @@ mono_class_get_cctor (MonoClass *klass)
                return result;
        }
 
-       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);
 }
 
 /**
  * mono_class_get_finalizer:
- * @klass: The MonoClass pointer
+ * \param klass: The MonoClass pointer
  *
- * Returns: The finalizer method of @klass if it exists, NULL otherwise.
+ * \returns The finalizer method of \p klass if it exists, NULL otherwise.
  */
 MonoMethod*
 mono_class_get_finalizer (MonoClass *klass)
@@ -8733,8 +8488,8 @@ mono_class_get_finalizer (MonoClass *klass)
 
 /**
  * mono_class_needs_cctor_run:
- * @klass: the MonoClass pointer
- * @caller: a MonoMethod describing the caller
+ * \param klass the MonoClass pointer
+ * \param caller a MonoMethod describing the caller
  *
  * Determines whenever the class has a static constructor and whenever it
  * needs to be called when executing CALLER.
@@ -8753,10 +8508,9 @@ mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
 
 /**
  * mono_class_array_element_size:
- * @klass: 
+ * \param klass
  *
- * Returns: The number of bytes an element of type @klass
- * uses when stored into an array.
+ * \returns The number of bytes an element of type \p klass uses when stored into an array.
  */
 gint32
 mono_class_array_element_size (MonoClass *klass)
@@ -8817,9 +8571,9 @@ handle_enum:
 
 /**
  * mono_array_element_size:
- * @ac: pointer to a #MonoArrayClass
+ * \param ac pointer to a \c MonoArrayClass
  *
- * Returns: The size of single array element.
+ * \returns The size of single array element.
  */
 gint32
 mono_array_element_size (MonoClass *ac)
@@ -8828,6 +8582,9 @@ mono_array_element_size (MonoClass *ac)
        return ac->sizes.element_size;
 }
 
+/**
+ * mono_ldtoken:
+ */
 gpointer
 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
              MonoGenericContext *context)
@@ -8842,7 +8599,7 @@ gpointer
 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
              MonoGenericContext *context, MonoError *error)
 {
-       mono_error_init (error);
+       error_init (error);
 
        if (image_is_dynamic (image)) {
                MonoClass *tmp_handle_class;
@@ -8932,7 +8689,7 @@ gpointer
 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
 {
        MonoClass *handle_class;
-       mono_error_init (error);
+       error_init (error);
        return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
 }
 
@@ -8968,9 +8725,9 @@ mono_install_get_class_from_name (MonoGetClassFromName func)
 /**
  * mono_class_get_image:
  *
- * Use this method to get the `MonoImage*` where this class came from.
+ * Use this method to get the \c MonoImage* where this class came from.
  *
- * Returns: The image where this class is defined.
+ * \returns The image where this class is defined.
  */
 MonoImage*
 mono_class_get_image (MonoClass *klass)
@@ -8980,11 +8737,11 @@ mono_class_get_image (MonoClass *klass)
 
 /**
  * mono_class_get_element_class:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
  * Use this function to get the element class of an array.
  *
- * Returns: The element class of an array.
+ * \returns The element class of an array.
  */
 MonoClass*
 mono_class_get_element_class (MonoClass *klass)
@@ -8994,12 +8751,12 @@ mono_class_get_element_class (MonoClass *klass)
 
 /**
  * mono_class_is_valuetype:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
- * Use this method to determine if the provided `MonoClass*` represents a value type,
+ * Use this method to determine if the provided \c MonoClass* represents a value type,
  * or a reference type.
  *
- * Returns: TRUE if the MonoClass represents a ValueType, FALSE if it represents a reference type.
+ * \returns TRUE if the \c MonoClass represents a \c ValueType, FALSE if it represents a reference type.
  */
 gboolean
 mono_class_is_valuetype (MonoClass *klass)
@@ -9009,11 +8766,11 @@ mono_class_is_valuetype (MonoClass *klass)
 
 /**
  * mono_class_is_enum:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
- * Use this function to determine if the provided `MonoClass*` represents an enumeration.
+ * Use this function to determine if the provided \c MonoClass* represents an enumeration.
  *
- * Returns: TRUE if the MonoClass represents an enumeration.
+ * \returns TRUE if the \c MonoClass represents an enumeration.
  */
 gboolean
 mono_class_is_enum (MonoClass *klass)
@@ -9023,11 +8780,11 @@ mono_class_is_enum (MonoClass *klass)
 
 /**
  * mono_class_enum_basetype:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
  * Use this function to get the underlying type for an enumeration value.
  * 
- * Returns: The underlying type representation for an enumeration.
+ * \returns The underlying type representation for an enumeration.
  */
 MonoType*
 mono_class_enum_basetype (MonoClass *klass)
@@ -9041,9 +8798,9 @@ mono_class_enum_basetype (MonoClass *klass)
 
 /**
  * mono_class_get_parent
- * @klass: the MonoClass to act on
+ * \param klass the \c 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)
@@ -9053,13 +8810,13 @@ mono_class_get_parent (MonoClass *klass)
 
 /**
  * mono_class_get_nesting_type:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
- * Use this function to obtain the class that the provided `MonoClass*` is nested on.
+ * Use this function to obtain the class that the provided \c 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.
+ * \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)
@@ -9069,9 +8826,9 @@ mono_class_get_nesting_type (MonoClass *klass)
 
 /**
  * mono_class_get_rank:
- * @klass: the MonoClass to act on
+ * \param 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)
@@ -9081,9 +8838,9 @@ mono_class_get_rank (MonoClass *klass)
 
 /**
  * mono_class_get_name
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
- * Returns: The name of the class.
+ * \returns The name of the class.
  */
 const char*
 mono_class_get_name (MonoClass *klass)
@@ -9093,9 +8850,9 @@ mono_class_get_name (MonoClass *klass)
 
 /**
  * mono_class_get_namespace:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
- * Returns: The namespace of the class.
+ * \returns The namespace of the class.
  */
 const char*
 mono_class_get_namespace (MonoClass *klass)
@@ -9105,11 +8862,11 @@ mono_class_get_namespace (MonoClass *klass)
 
 /**
  * mono_class_get_type:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
- * This method returns the internal Type representation for the class.
+ * This method returns the internal \c MonoType representation for the class.
  *
- * Returns: The MonoType from the class.
+ * \returns The \c MonoType from the class.
  */
 MonoType*
 mono_class_get_type (MonoClass *klass)
@@ -9119,11 +8876,11 @@ mono_class_get_type (MonoClass *klass)
 
 /**
  * mono_class_get_type_token:
- * @klass: the MonoClass to act on
+ * \param klass the \c 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)
@@ -9133,7 +8890,7 @@ mono_class_get_type_token (MonoClass *klass)
 
 /**
  * mono_class_get_byref_type:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
  * 
  */
@@ -9145,9 +8902,9 @@ mono_class_get_byref_type (MonoClass *klass)
 
 /**
  * mono_class_num_fields:
- * @klass: the MonoClass to act on
+ * \param klass the \c 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)
@@ -9157,9 +8914,9 @@ mono_class_num_fields (MonoClass *klass)
 
 /**
  * mono_class_num_methods:
- * @klass: the MonoClass to act on
+ * \param klass the \c 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)
@@ -9169,43 +8926,43 @@ mono_class_num_methods (MonoClass *klass)
 
 /**
  * mono_class_num_properties
- * @klass: the MonoClass to act on
+ * \param klass the \c 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)
 {
        mono_class_setup_properties (klass);
 
-       return mono_class_get_ext (klass)->property.count;
+       return mono_class_get_property_info (klass)->count;
 }
 
 /**
  * mono_class_num_events:
- * @klass: the MonoClass to act on
+ * \param klass the \c 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)
 {
        mono_class_setup_events (klass);
 
-       return mono_class_get_ext (klass)->event.count;
+       return mono_class_get_event_info (klass)->count;
 }
 
 /**
  * mono_class_get_fields:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
  * This routine is an iterator routine for retrieving the fields in a class.
  *
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
  * iterate over all of the elements.  When no more values are
  * available, the return value is NULL.
  *
- * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
+ * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
  */
 MonoClassField*
 mono_class_get_fields (MonoClass* klass, gpointer *iter)
@@ -9236,16 +8993,16 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter)
 }
 
 /**
- * mono_class_get_methods
- * @klass: the MonoClass to act on
+ * mono_class_get_methods:
+ * \param klass the \c MonoClass to act on
  *
  * This routine is an iterator routine for retrieving the fields in a class.
  *
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
  * iterate over all of the elements.  When no more values are
  * available, the return value is NULL.
  *
- * Returns: a MonoMethod on each iteration or NULL when no more methods are available.
+ * \returns a \c MonoMethod on each iteration or NULL when no more methods are available.
  */
 MonoMethod*
 mono_class_get_methods (MonoClass* klass, gpointer *iter)
@@ -9359,7 +9116,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
 
 /**
  * mono_class_get_properties:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
  * This routine is an iterator routine for retrieving the properties in a class.
  *
@@ -9367,7 +9124,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
  * iterate over all of the elements.  When no more values are
  * available, the return value is NULL.
  *
- * Returns: a @MonoProperty* on each invocation, or NULL when no more are available.
+ * Returns: a \c MonoProperty* on each invocation, or NULL when no more are available.
  */
 MonoProperty*
 mono_class_get_properties (MonoClass* klass, gpointer *iter)
@@ -9377,10 +9134,10 @@ mono_class_get_properties (MonoClass* klass, gpointer *iter)
                return NULL;
        if (!*iter) {
                mono_class_setup_properties (klass);
-               MonoClassExt *ext = mono_class_get_ext (klass);
+               MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
                /* start from the first */
-               if (ext->property.count) {
-                       *iter = &ext->properties [0];
+               if (info->count) {
+                       *iter = &info->properties [0];
                        return (MonoProperty *)*iter;
                } else {
                        /* no fields */
@@ -9389,8 +9146,8 @@ mono_class_get_properties (MonoClass* klass, gpointer *iter)
        }
        property = (MonoProperty *)*iter;
        property++;
-       MonoClassExt *ext = mono_class_get_ext (klass);
-       if (property < &ext->properties [ext->property.count]) {
+       MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
+       if (property < &info->properties [info->count]) {
                *iter = property;
                return (MonoProperty *)*iter;
        }
@@ -9399,15 +9156,15 @@ mono_class_get_properties (MonoClass* klass, gpointer *iter)
 
 /**
  * mono_class_get_events:
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
  * This routine is an iterator routine for retrieving the properties in a class.
  *
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
  * iterate over all of the elements.  When no more values are
  * available, the return value is NULL.
  *
- * Returns: a @MonoEvent* on each invocation, or NULL when no more are available.
+ * \returns a \c MonoEvent* on each invocation, or NULL when no more are available.
  */
 MonoEvent*
 mono_class_get_events (MonoClass* klass, gpointer *iter)
@@ -9417,10 +9174,10 @@ mono_class_get_events (MonoClass* klass, gpointer *iter)
                return NULL;
        if (!*iter) {
                mono_class_setup_events (klass);
-               MonoClassExt *ext = mono_class_get_ext (klass);
+               MonoClassEventInfo *info = mono_class_get_event_info (klass);
                /* start from the first */
-               if (ext->event.count) {
-                       *iter = &ext->events [0];
+               if (info->count) {
+                       *iter = &info->events [0];
                        return (MonoEvent *)*iter;
                } else {
                        /* no fields */
@@ -9429,8 +9186,8 @@ mono_class_get_events (MonoClass* klass, gpointer *iter)
        }
        event = (MonoEvent *)*iter;
        event++;
-       MonoClassExt *ext = mono_class_get_ext (klass);
-       if (event < &ext->events [ext->event.count]) {
+       MonoClassEventInfo *info = mono_class_get_event_info (klass);
+       if (event < &info->events [info->count]) {
                *iter = event;
                return (MonoEvent *)*iter;
        }
@@ -9439,15 +9196,15 @@ mono_class_get_events (MonoClass* klass, gpointer *iter)
 
 /**
  * mono_class_get_interfaces
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
  * This routine is an iterator routine for retrieving the interfaces implemented by this class.
  *
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
  * iterate over all of the elements.  When no more values are
  * available, the return value is NULL.
  *
- * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
+ * \returns a \c MonoClass* on each invocation, or NULL when no more are available.
  */
 MonoClass*
 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
@@ -9494,8 +9251,12 @@ setup_nested_types (MonoClass *klass)
        if (klass->nested_classes_inited)
                return;
 
-       if (!klass->type_token)
+       if (!klass->type_token) {
+               mono_loader_lock ();
                klass->nested_classes_inited = TRUE;
+               mono_loader_unlock ();
+               return;
+       }
 
        i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
        classes = NULL;
@@ -9517,37 +9278,32 @@ setup_nested_types (MonoClass *klass)
                i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
        }
 
-       mono_class_alloc_ext (klass);
-
        nested_classes = NULL;
        for (l = classes; l; l = l->next)
                nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data);
        g_list_free (classes);
 
-       mono_image_lock (klass->image);
-
-       mono_memory_barrier ();
+       mono_loader_lock ();
        if (!klass->nested_classes_inited) {
-               mono_class_get_ext (klass)->nested_classes = nested_classes;
+               mono_class_set_nested_classes_property (klass, nested_classes);
                mono_memory_barrier ();
                klass->nested_classes_inited = TRUE;
        }
-
-       mono_image_unlock (klass->image);
+       mono_loader_unlock ();
 }
 
 /**
  * mono_class_get_nested_types
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
  * This routine is an iterator routine for retrieving the nested types of a class.
- * This works only if @klass is non-generic, or a generic type definition.
+ * This works only if \p klass is non-generic, or a generic type definition.
  *
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
  * iterate over all of the elements.  When no more values are
  * available, the return value is NULL.
  *
- * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
+ * \returns a \c Monoclass* on each invocation, or NULL when no more are available.
  */
 MonoClass*
 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
@@ -9560,11 +9316,11 @@ mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
                setup_nested_types (klass);
 
        if (!*iter) {
-               MonoClassExt *ext = mono_class_get_ext (klass);
+               GList *nested_classes = mono_class_get_nested_classes_property (klass);
                /* start from the first */
-               if (ext && ext->nested_classes) {
-                       *iter = ext->nested_classes;
-                       return (MonoClass *)ext->nested_classes->data;
+               if (nested_classes) {
+                       *iter = nested_classes;
+                       return (MonoClass *)nested_classes->data;
                } else {
                        /* no nested types */
                        return NULL;
@@ -9582,9 +9338,9 @@ mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
 
 /**
  * mono_class_is_delegate
- * @klass: the MonoClass to act on
+ * \param klass the \c MonoClass to act on
  *
- * Returns: TRUE if the MonoClass represents a System.Delegate.
+ * \returns TRUE if the \c MonoClass represents a \c System.Delegate.
  */
 mono_bool
 mono_class_is_delegate (MonoClass *klass)
@@ -9594,10 +9350,10 @@ mono_class_is_delegate (MonoClass *klass)
 
 /**
  * mono_class_implements_interface
- * @klass: The MonoClass to act on
- * @interface: The interface to check if @klass implements.
+ * \param klass The MonoClass to act on
+ * \param interface The interface to check if \p klass implements.
  *
- * Returns: TRUE if @klass implements @interface.
+ * \returns TRUE if \p klass implements \p interface.
  */
 mono_bool
 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
@@ -9607,9 +9363,9 @@ mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
 
 /**
  * mono_field_get_name:
- * @field: the MonoClassField to act on
+ * \param field the \c MonoClassField to act on
  *
- * Returns: The name of the field.
+ * \returns The name of the field.
  */
 const char*
 mono_field_get_name (MonoClassField *field)
@@ -9619,9 +9375,8 @@ mono_field_get_name (MonoClassField *field)
 
 /**
  * mono_field_get_type:
- * @field: the MonoClassField to act on
- *
- * Returns: MonoType of the field.
+ * \param field the \c MonoClassField to act on
+ * \returns \c MonoType of the field.
  */
 MonoType*
 mono_field_get_type (MonoClassField *field)
@@ -9638,15 +9393,15 @@ mono_field_get_type (MonoClassField *field)
 
 /**
  * mono_field_get_type_checked:
- * @field: the MonoClassField to act on
- * @error: used to return any erro found while retrieving @field type
+ * \param field the \c MonoClassField to act on
+ * \param error used to return any error found while retrieving \p field type
  *
- * Returns: MonoType of the field.
+ * \returns \c MonoType of the field.
  */
 MonoType*
 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
 {
-       mono_error_init (error);
+       error_init (error);
        if (!field->type)
                mono_field_resolve_type (field, error);
        return field->type;
@@ -9654,9 +9409,9 @@ mono_field_get_type_checked (MonoClassField *field, MonoError *error)
 
 /**
  * mono_field_get_parent:
- * @field: the MonoClassField to act on
+ * \param field the \c MonoClassField to act on
  *
- * Returns: MonoClass where the field was defined.
+ * \returns \c MonoClass where the field was defined.
  */
 MonoClass*
 mono_field_get_parent (MonoClassField *field)
@@ -9666,12 +9421,12 @@ mono_field_get_parent (MonoClassField *field)
 
 /**
  * mono_field_get_flags;
- * @field: the MonoClassField to act on
+ * \param field the \c MonoClassField to act on
  *
  * The metadata flags for a field are encoded using the
- * FIELD_ATTRIBUTE_* constants.  See the tabledefs.h file for details.
+ * \c FIELD_ATTRIBUTE_* constants.  See the \c tabledefs.h file for details.
  *
- * Returns: The flags for the field.
+ * \returns The flags for the field.
  */
 guint32
 mono_field_get_flags (MonoClassField *field)
@@ -9683,9 +9438,9 @@ mono_field_get_flags (MonoClassField *field)
 
 /**
  * mono_field_get_offset:
- * @field: the MonoClassField to act on
+ * \param field the \c MonoClassField to act on
  *
- * Returns: The field offset.
+ * \returns The field offset.
  */
 guint32
 mono_field_get_offset (MonoClassField *field)
@@ -9699,41 +9454,35 @@ mono_field_get_rva (MonoClassField *field)
        guint32 rva;
        int field_index;
        MonoClass *klass = field->parent;
-       MonoFieldDefaultValue *field_def_values;
+       MonoFieldDefaultValue *def_values;
 
        g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
 
-       MonoClassExt *ext = mono_class_get_ext (klass);
-       if (!ext || !ext->field_def_values) {
-               mono_class_alloc_ext (klass);
-               ext = mono_class_get_ext (klass);
-
-               field_def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
+       def_values = mono_class_get_field_def_values (klass);
+       if (!def_values) {
+               def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
 
-               mono_image_lock (klass->image);
-               if (!ext->field_def_values)
-                       ext->field_def_values = field_def_values;
-               mono_image_unlock (klass->image);
+               mono_class_set_field_def_values (klass, def_values);
        }
 
        field_index = mono_field_get_index (field);
                
-       if (!ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
+       if (!def_values [field_index].data && !image_is_dynamic (klass->image)) {
                int first_field_idx = mono_class_get_first_field_idx (klass);
                mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL);
                if (!rva)
                        g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
-               ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
+               def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
        }
 
-       return ext->field_def_values [field_index].data;
+       return def_values [field_index].data;
 }
 
 /**
  * mono_field_get_data:
- * @field: the MonoClassField to act on
+ * \param field the \c MonoClassField to act on
  *
- * Returns: A pointer to the metadata constant value or to the field
+ * \returns A pointer to the metadata constant value or to the field
  * data if it has an RVA flag.
  */
 const char *
@@ -9752,9 +9501,8 @@ mono_field_get_data (MonoClassField *field)
 
 /**
  * mono_property_get_name: 
- * @prop: the MonoProperty to act on
- *
- * Returns: The name of the property
+ * \param prop the \c MonoProperty to act on
+ * \returns The name of the property
  */
 const char*
 mono_property_get_name (MonoProperty *prop)
@@ -9764,9 +9512,8 @@ 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)
+ * \param prop the \c MonoProperty to act on.
+ * \returns The setter method of the property, a \c MonoMethod.
  */
 MonoMethod*
 mono_property_get_set_method (MonoProperty *prop)
@@ -9776,9 +9523,8 @@ 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)
+ * \param prop the MonoProperty to act on.
+ * \returns The getter method of the property (A \c MonoMethod)
  */
 MonoMethod*
 mono_property_get_get_method (MonoProperty *prop)
@@ -9788,9 +9534,8 @@ 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.
+ * \param prop the \c MonoProperty to act on.
+ * \returns The \c MonoClass where the property was defined.
  */
 MonoClass*
 mono_property_get_parent (MonoProperty *prop)
@@ -9800,12 +9545,12 @@ mono_property_get_parent (MonoProperty *prop)
 
 /**
  * mono_property_get_flags:
- * @prop: the MonoProperty to act on.
+ * \param prop the \c MonoProperty to act on.
  *
  * The metadata flags for a property are encoded using the
- * PROPERTY_ATTRIBUTE_* constants.  See the tabledefs.h file for details.
+ * \c PROPERTY_ATTRIBUTE_* constants.  See the \c tabledefs.h file for details.
  *
- * Returns: The flags for the property.
+ * \returns The flags for the property.
  */
 guint32
 mono_property_get_flags (MonoProperty *prop)
@@ -9815,9 +9560,8 @@ mono_property_get_flags (MonoProperty *prop)
 
 /**
  * mono_event_get_name:
- * @event: the MonoEvent to act on
- *
- * Returns: The name of the event.
+ * \param event the MonoEvent to act on
+ * \returns The name of the event.
  */
 const char*
 mono_event_get_name (MonoEvent *event)
@@ -9827,9 +9571,8 @@ 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).
+ * \param event The \c MonoEvent to act on.
+ * \returns The \c add method for the event, a \c MonoMethod.
  */
 MonoMethod*
 mono_event_get_add_method (MonoEvent *event)
@@ -9839,9 +9582,8 @@ 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).
+ * \param event The \c MonoEvent to act on.
+ * \returns The \c remove method for the event, a \c MonoMethod.
  */
 MonoMethod*
 mono_event_get_remove_method (MonoEvent *event)
@@ -9851,9 +9593,8 @@ 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).
+ * \param event The \c MonoEvent to act on.
+ * \returns The \c raise method for the event, a \c MonoMethod.
  */
 MonoMethod*
 mono_event_get_raise_method (MonoEvent *event)
@@ -9863,9 +9604,8 @@ 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.
+ * \param event the MonoEvent to act on.
+ * \returns The \c MonoClass where the event is defined.
  */
 MonoClass*
 mono_event_get_parent (MonoEvent *event)
@@ -9875,12 +9615,12 @@ mono_event_get_parent (MonoEvent *event)
 
 /**
  * mono_event_get_flags
- * @event: the MonoEvent to act on.
+ * \param event the \c MonoEvent to act on.
  *
  * The metadata flags for an event are encoded using the
- * EVENT_* constants.  See the tabledefs.h file for details.
+ * \c EVENT_* constants.  See the \c tabledefs.h file for details.
  *
- * Returns: The flags for the event.
+ * \returns The flags for the event.
  */
 guint32
 mono_event_get_flags (MonoEvent *event)
@@ -9890,11 +9630,11 @@ mono_event_get_flags (MonoEvent *event)
 
 /**
  * mono_class_get_method_from_name:
- * @klass: where to look for the method
- * @name: name of the method
- * @param_count: number of parameters. -1 for any number.
+ * \param klass where to look for the method
+ * \param name name of the method
+ * \param param_count number of parameters. -1 for any number.
  *
- * Obtains a MonoMethod with a given name and number of parameters.
+ * Obtains a \c MonoMethod with a given name and number of parameters.
  * It only works if there are no multiple signatures for any given method name.
  */
 MonoMethod *
@@ -9948,12 +9688,12 @@ find_method_in_metadata (MonoClass *klass, const char *name, int param_count, in
 
 /**
  * mono_class_get_method_from_name_flags:
- * @klass: where to look for the method
- * @name_space: name of the method
- * @param_count: number of parameters. -1 for any number.
- * @flags: flags which must be set in the method
+ * \param klass where to look for the method
+ * \param name_space name of the method
+ * \param param_count number of parameters. -1 for any number.
+ * \param flags flags which must be set in the method
  *
- * Obtains a MonoMethod with a given name and number of parameters.
+ * Obtains a \c MonoMethod with a given name and number of parameters.
  * It only works if there are no multiple signatures for any given method name.
  */
 MonoMethod *
@@ -10006,9 +9746,9 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p
 
 /**
  * mono_class_set_failure:
- * @klass: class in which the failure was detected
- * @ex_type: the kind of exception/error to be thrown (later)
- * @ex_data: exception data (specific to each type of exception/error)
+ * \param klass class in which the failure was detected
+ * \param ex_type the kind of exception/error to be thrown (later)
+ * \param ex_data exception data (specific to each type of exception/error)
  *
  * Keep a detected failure informations in the class for later processing.
  * Note that only the first failure is kept.
@@ -10025,7 +9765,7 @@ mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error)
 
        mono_loader_lock ();
        klass->has_failure = 1;
-       mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, boxed_error);
+       mono_class_set_exception_data (klass, boxed_error);
        mono_loader_unlock ();
 
        return TRUE;
@@ -10041,16 +9781,16 @@ mono_class_has_failure (const MonoClass *klass)
 
 /**
  * mono_class_set_type_load_failure:
- * @klass: class in which the failure was detected
- * @fmt: Printf-style error message string.
+ * \param klass class in which the failure was detected
+ * \param fmt \c 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 ()
+ * 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.
+ *
+ * \returns FALSE if a failure was already set on the class, or TRUE otherwise.
  */
 gboolean
 mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
@@ -10061,7 +9801,7 @@ mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
        if (mono_class_has_failure (klass))
                return FALSE;
        
-       mono_error_init (&prepare_error);
+       error_init (&prepare_error);
        
        va_start (args, fmt);
        mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
@@ -10072,19 +9812,6 @@ mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
        return mono_class_set_failure (klass, box);
 }
 
-/*
- * mono_class_get_exception_data:
- *
- *   Return the exception_data property of KLASS.
- *
- * LOCKING: Acquires the loader lock.
- */
-static gpointer
-mono_class_get_exception_data (const MonoClass *klass)
-{
-       return mono_image_property_lookup (klass->image, (MonoClass*)klass, MONO_CLASS_PROP_EXCEPTION_DATA);
-}
-
 /**
  * mono_classes_init:
  *
@@ -10116,11 +9843,6 @@ mono_classes_init (void)
                                                        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);
 }
 
 /**
@@ -10142,9 +9864,9 @@ mono_classes_cleanup (void)
 
 /**
  * mono_class_get_exception_for_failure:
- * @klass: class in which the failure was detected
+ * \param klass class in which the failure was detected
  *
- * Return a constructed MonoException than the caller can then throw
+ * \returns a constructed MonoException than the caller can then throw
  * using mono_raise_exception - or NULL if no failure is present (or
  * doesn't result in an exception).
  */
@@ -10154,7 +9876,7 @@ mono_class_get_exception_for_failure (MonoClass *klass)
        if (!mono_class_has_failure (klass))
                return NULL;
        MonoError unboxed_error;
-       mono_error_init (&unboxed_error);
+       error_init (&unboxed_error);
        mono_error_set_for_class_failure (&unboxed_error, klass);
        return mono_error_convert_to_exception (&unboxed_error);
 }
@@ -10431,12 +10153,12 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass*
 
 /**
  * mono_method_can_access_field:
- * @method: Method that will attempt to access the field
- * @field: the field to access
+ * \param method Method that will attempt to access the field
+ * \param 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
+ * \returns TRUE if the given \p method is allowed to access the \p field while following
  * the accessibility rules of the CLI.
  */
 gboolean
@@ -10458,12 +10180,12 @@ mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
 
 /**
  * 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.
+ * \param method Method that will attempt to access the other method
+ * \param called the method that we want to probe for accessibility.
  *
- * Used to determine if the @method is allowed to access the specified @called method.
+ * Used to determine if the \p method is allowed to access the specified \p called method.
  *
- * Returns: TRUE if the given @method is allowed to invoke the @called while following
+ * \returns TRUE if the given \p method is allowed to invoke the \p called while following
  * the accessibility rules of the CLI.
  */
 gboolean
@@ -10596,9 +10318,8 @@ mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
 
 /**
  * mono_type_is_valid_enum_basetype:
- * @type: The MonoType to check
- *
- * Returns: TRUE if the type can be used as the basetype of an enum
+ * \param type The MonoType to check
+ * \returns TRUE if the type can be used as the basetype of an enum
  */
 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
        switch (type->type) {
@@ -10622,15 +10343,15 @@ gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
 
 /**
  * mono_class_is_valid_enum:
- * @klass: An enum class to be validated
+ * \param klass An enum class to be validated
  *
  * This method verify the required properties an enum should have.
- *  
- * Returns: TRUE if the informed enum class is valid 
  *
  * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
  * 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)
+ *
+ * \returns TRUE if the informed enum class is valid 
  */
 gboolean
 mono_class_is_valid_enum (MonoClass *klass)
@@ -10689,29 +10410,6 @@ mono_class_setup_interface_id (MonoClass *klass)
        mono_loader_unlock ();
 }
 
-/*
- * mono_class_alloc_ext:
- *
- *   Allocate klass->ext if not already done.
- */
-void
-mono_class_alloc_ext (MonoClass *klass)
-{
-       MonoClassExt *ext;
-
-       if (mono_class_get_ext (klass))
-               return;
-
-       ext = (MonoClassExt *)mono_class_alloc0 (klass, sizeof (MonoClassExt));
-       mono_image_lock (klass->image);
-       mono_memory_barrier ();
-       if (!mono_class_get_ext (klass))
-               mono_class_set_ext (klass, ext);
-       class_ext_size += sizeof (MonoClassExt);
-       ++class_ext_count;
-       mono_image_unlock (klass->image);
-}
-
 /*
  * mono_class_setup_interfaces:
  *
@@ -10725,7 +10423,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
        int i, interface_count;
        MonoClass **interfaces;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (klass->interfaces_inited)
                return;
@@ -10734,14 +10432,13 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
                MonoType *args [1];
 
                /* generic IList, ICollection, IEnumerable */
-               interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
+               interface_count = 2;
                interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
 
                args [0] = &klass->element_class->byval_arg;
                interfaces [0] = mono_class_bind_generic_parameters (
                        mono_defaults.generic_ilist_class, 1, args, FALSE);
-               if (interface_count > 1)
-                       interfaces [1] = mono_class_bind_generic_parameters (
+               interfaces [1] = mono_class_bind_generic_parameters (
                           mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
        } else if (mono_class_is_ginst (klass)) {
                MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
@@ -10766,8 +10463,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
                interfaces = NULL;
        }
 
-       mono_image_lock (klass->image);
-
+       mono_loader_lock ();
        if (!klass->interfaces_inited) {
                klass->interface_count = interface_count;
                klass->interfaces = interfaces;
@@ -10776,8 +10472,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
 
                klass->interfaces_inited = TRUE;
        }
-
-       mono_image_unlock (klass->image);
+       mono_loader_unlock ();
 }
 
 static void
@@ -10789,7 +10484,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error)
        MonoType *ftype;
        int field_idx = field - klass->fields;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (gtd) {
                MonoClassField *gfield = &gtd->fields [field_idx];
@@ -10858,7 +10553,6 @@ mono_field_resolve_flags (MonoClassField *field)
        MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
        int field_idx = field - klass->fields;
 
-
        if (gtd) {
                MonoClassField *gfield = &gtd->fields [field_idx];
                return mono_field_get_flags (gfield);
@@ -10874,7 +10568,7 @@ mono_field_resolve_flags (MonoClassField *field)
 
 /**
  * mono_class_get_fields_lazy:
- * @klass: the MonoClass to act on
+ * \param klass the MonoClass to act on
  *
  * This routine is an iterator routine for retrieving the fields in a class.
  * Only minimal information about fields are loaded. Accessors must be used
@@ -10884,7 +10578,7 @@ mono_field_resolve_flags (MonoClassField *field)
  * iterate over all of the elements.  When no more values are
  * available, the return value is NULL.
  *
- * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
+ * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
  */
 MonoClassField*
 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
@@ -10921,4 +10615,157 @@ mono_class_full_name (MonoClass *klass)
 }
 
 /* Declare all shared lazy type lookup functions */
-GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)
+GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, "System.Runtime.InteropServices", "SafeHandle")
+
+/**
+ * mono_method_get_base_method:
+ * \param method a method
+ * \param definition if true, get the definition
+ * \param error set on failure
+ *
+ * Given a virtual method associated with a subclass, return the corresponding
+ * method from an ancestor.  If \p definition is FALSE, returns the method in the
+ * superclass of the given method.  If \p definition is TRUE, return the method
+ * in the ancestor class where it was first declared.  The type arguments will
+ * be inflated in the ancestor classes.  If the method is not associated with a
+ * class, or isn't virtual, returns the method itself.  On failure returns NULL
+ * and sets \p error.
+ */
+MonoMethod*
+mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error)
+{
+       MonoClass *klass, *parent;
+       MonoGenericContext *generic_inst = NULL;
+       MonoMethod *result = NULL;
+       int slot;
+
+       if (method->klass == NULL)
+               return method;
+
+       if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
+           MONO_CLASS_IS_INTERFACE (method->klass) ||
+           method->flags & METHOD_ATTRIBUTE_NEW_SLOT)
+               return method;
+
+       slot = mono_method_get_vtable_slot (method);
+       if (slot == -1)
+               return method;
+
+       klass = method->klass;
+       if (mono_class_is_ginst (klass)) {
+               generic_inst = mono_class_get_context (klass);
+               klass = mono_class_get_generic_class (klass)->container_class;
+       }
+
+retry:
+       if (definition) {
+               /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */
+               for (parent = klass->parent; parent != NULL; parent = parent->parent) {
+                       /* on entry, klass is either a plain old non-generic class and generic_inst == NULL
+                          or klass is the generic container class and generic_inst is the instantiation.
+
+                          when we go to the parent, if the parent is an open constructed type, we need to
+                          replace the type parameters by the definitions from the generic_inst, and then take it
+                          apart again into the klass and the generic_inst.
+
+                          For cases like this:
+                          class C<T> : B<T, int> {
+                              public override void Foo () { ... }
+                          }
+                          class B<U,V> : A<HashMap<U,V>> {
+                              public override void Foo () { ... }
+                          }
+                          class A<X> {
+                              public virtual void Foo () { ... }
+                          }
+
+                          if at each iteration the parent isn't open, we can skip inflating it.  if at some
+                          iteration the parent isn't generic (after possible inflation), we set generic_inst to
+                          NULL;
+                       */
+                       MonoGenericContext *parent_inst = NULL;
+                       if (mono_class_is_open_constructed_type (mono_class_get_type (parent))) {
+                               parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error);
+                               return_val_if_nok  (error, NULL);
+                       }
+                       if (mono_class_is_ginst (parent)) {
+                               parent_inst = mono_class_get_context (parent);
+                               parent = mono_class_get_generic_class (parent)->container_class;
+                       }
+
+                       mono_class_setup_vtable (parent);
+                       if (parent->vtable_size <= slot)
+                               break;
+                       klass = parent;
+                       generic_inst = parent_inst;
+               }
+       } else {
+               klass = klass->parent;
+               if (!klass)
+                       return method;
+               if (mono_class_is_open_constructed_type (mono_class_get_type (klass))) {
+                       klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
+                       return_val_if_nok (error, NULL);
+
+                       generic_inst = NULL;
+               }
+               if (mono_class_is_ginst (klass)) {
+                       generic_inst = mono_class_get_context (klass);
+                       klass = mono_class_get_generic_class (klass)->container_class;
+               }
+
+       }
+
+       if (generic_inst) {
+               klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
+               return_val_if_nok (error, NULL);
+       }
+
+       if (klass == method->klass)
+               return method;
+
+       /*This is possible if definition == FALSE.
+        * Do it here to be really sure we don't read invalid memory.
+        */
+       if (slot >= klass->vtable_size)
+               return method;
+
+       mono_class_setup_vtable (klass);
+
+       result = klass->vtable [slot];
+       if (result == NULL) {
+               /* It is an abstract method */
+               gboolean found = FALSE;
+               gpointer iter = NULL;
+               while ((result = mono_class_get_methods (klass, &iter))) {
+                       if (result->slot == slot) {
+                               found = TRUE;
+                               break;
+                       }
+               }
+               /* found might be FALSE if we looked in an abstract class
+                * that doesn't override an abstract method of its
+                * parent: 
+                *   abstract class Base {
+                *     public abstract void Foo ();
+                *   }
+                *   abstract class Derived : Base { }
+                *   class Child : Derived {
+                *     public override void Foo () { }
+                *  }
+                *
+                *  if m was Child.Foo and we ask for the base method,
+                *  then we get here with klass == Derived and found == FALSE
+                */
+               /* but it shouldn't be the case that if we're looking
+                * for the definition and didn't find a result; the
+                * loop above should've taken us as far as we could
+                * go! */
+               g_assert (!(definition && !found));
+               if (!found)
+                       goto retry;
+       }
+
+       g_assert (result != NULL);
+       return result;
+}