2009-11-18 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mono / metadata / class.c
index 4b725b759a12d3896649d2160efa3635b725f620..717f93c7b8ce1558c4944335b1099534e26f6e34 100644 (file)
@@ -4,15 +4,17 @@
  * Author:
  *   Miguel de Icaza (miguel@ximian.com)
  *
- * (C) 2001-2006 Novell, Inc.
- *
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
  */
 #include <config.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
 #include <glib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <signal.h>
 #if !PLATFORM_WIN32
 #include <mono/io-layer/atomic.h>
 #endif
 #include <mono/metadata/attrdefs.h>
 #include <mono/metadata/gc-internal.h>
 #include <mono/metadata/verify-internals.h>
+#include <mono/metadata/mono-debug.h>
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-string.h>
+#include <mono/utils/mono-error-internals.h>
 
 MonoStats mono_stats;
 
@@ -48,6 +53,10 @@ gboolean mono_print_vtable = FALSE;
  */
 gboolean mono_setup_vtable_in_class_init = TRUE;
 
+/* Statistics */
+guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
+guint32 classes_size, class_ext_size;
+
 /* Function supplied by the runtime to find classes by name using information from the AOT file */
 static MonoGetClassFromName get_class_from_name = NULL;
 
@@ -58,6 +67,8 @@ static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name,
 static int generic_array_methods (MonoClass *class);
 static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos);
 
+static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
+
 void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
 void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
 
@@ -112,9 +123,12 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
                MonoClass *enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx);
                GList *tmp;
 
-               if (enclosing->nested_classes_inited) {
+               if (!enclosing)
+                       return NULL;
+
+               if (enclosing->nested_classes_inited && enclosing->ext) {
                        /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
-                       for (tmp = enclosing->nested_classes; tmp; tmp = tmp->next) {
+                       for (tmp = enclosing->ext->nested_classes; tmp; tmp = tmp->next) {
                                res = tmp->data;
                                if (strcmp (res->name, name) == 0)
                                        return res;
@@ -162,25 +176,23 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
 
 
 static void *
-mono_mempool_dup (MonoMemPool *mp, void *data, guint size)
+mono_image_memdup (MonoImage *image, void *data, guint size)
 {
-       void *res = mono_mempool_alloc (mp, size);
+       void *res = mono_image_alloc (image, size);
        memcpy (res, data, size);
        return res;
 }
        
 /* Copy everything mono_metadata_free_array free. */
 MonoArrayType *
-mono_dup_array_type (MonoMemPool *mp, MonoArrayType *a)
+mono_dup_array_type (MonoImage *image, MonoArrayType *a)
 {
-       if (mp) {
-               mono_loader_lock ();
-               a = mono_mempool_dup (mp, a, sizeof (MonoArrayType));
+       if (image) {
+               a = mono_image_memdup (image, a, sizeof (MonoArrayType));
                if (a->sizes)
-                       a->sizes = mono_mempool_dup (mp, a->sizes, a->numsizes * sizeof (int));
+                       a->sizes = mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
                if (a->lobounds)
-                       a->lobounds = mono_mempool_dup (mp, a->lobounds, a->numlobounds * sizeof (int));
-               mono_loader_unlock ();          
+                       a->lobounds = mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
        } else {
                a = g_memdup (a, sizeof (MonoArrayType));
                if (a->sizes)
@@ -193,15 +205,15 @@ mono_dup_array_type (MonoMemPool *mp, MonoArrayType *a)
 
 /* Copy everything mono_metadata_free_method_signature free. */
 MonoMethodSignature*
-mono_metadata_signature_deep_dup (MonoMemPool *mp, MonoMethodSignature *sig)
+mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
 {
        int i;
        
-       sig = mono_metadata_signature_dup_full (mp, sig);
+       sig = mono_metadata_signature_dup_full (image, sig);
        
-       sig->ret = mono_metadata_type_dup (mp, sig->ret);
+       sig->ret = mono_metadata_type_dup (image, sig->ret);
        for (i = 0; i < sig->param_count; ++i)
-               sig->params [i] = mono_metadata_type_dup (mp, sig->params [i]);
+               sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
        
        return sig;
 }
@@ -290,9 +302,11 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
        }
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
-               g_assert (type->data.generic_param->name);
-               g_string_append (str, type->data.generic_param->name);
-       
+               if (!mono_generic_param_info (type->data.generic_param))
+                       g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
+               else
+                       g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
+
                mono_type_name_check_byref (type, str);
 
                break;
@@ -360,7 +374,7 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                        for (i = 0; i < klass->generic_container->type_argc; i++) {
                                if (i)
                                        g_string_append_c (str, ',');
-                               g_string_append (str, klass->generic_container->type_params [i].name);
+                               g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
                        }
                        if (format == MONO_TYPE_NAME_FORMAT_IL) 
                                g_string_append_c (str, '>');
@@ -378,7 +392,7 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
 }
 
 /**
- * mono_type_get_name:
+ * mono_type_get_name_full:
  * @type: a type
  * @format: the format for the return string.
  *
@@ -444,9 +458,9 @@ MonoType*
 mono_type_get_underlying_type (MonoType *type)
 {
        if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype && !type->byref)
-               return type->data.klass->enum_basetype;
+               return mono_class_enum_basetype (type->data.klass);
        if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype && !type->byref)
-               return type->data.generic_class->container_class->enum_basetype;
+               return mono_class_enum_basetype (type->data.generic_class->container_class);
        return type;
 }
 
@@ -479,57 +493,67 @@ mono_class_is_open_constructed_type (MonoType *t)
 }
 
 static MonoType*
-inflate_generic_type (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context)
+inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
 {
+       mono_error_init (error);
+
        switch (type->type) {
        case MONO_TYPE_MVAR: {
                MonoType *nt;
-               int num = type->data.generic_param->num;
+               int num = mono_type_get_generic_param_num (type);
                MonoGenericInst *inst = context->method_inst;
                if (!inst || !inst->type_argv)
                        return NULL;
-               if (num >= inst->type_argc)
-                       g_error ("MVAR %d (%s) cannot be expanded in this context with %d instantiations", num, type->data.generic_param->name, inst->type_argc);
+               if (num >= inst->type_argc) {
+                       MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
+                       mono_error_set_bad_image (error, image->module_name, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
+                               num, info ? info->name : "", inst->type_argc);
+                       return NULL;
+               }
 
                /*
                 * Note that the VAR/MVAR cases are different from the rest.  The other cases duplicate @type,
                 * while the VAR/MVAR duplicates a type from the context.  So, we need to ensure that the
                 * ->byref and ->attrs from @type are propagated to the returned type.
                 */
-               nt = mono_metadata_type_dup (mempool, inst->type_argv [num]);
+               nt = mono_metadata_type_dup (image, inst->type_argv [num]);
                nt->byref = type->byref;
                nt->attrs = type->attrs;
                return nt;
        }
        case MONO_TYPE_VAR: {
                MonoType *nt;
-               int num = type->data.generic_param->num;
+               int num = mono_type_get_generic_param_num (type);
                MonoGenericInst *inst = context->class_inst;
                if (!inst)
                        return NULL;
-               if (num >= inst->type_argc)
-                       g_error ("VAR %d (%s) cannot be expanded in this context with %d instantiations", num, type->data.generic_param->name, inst->type_argc);
-               nt = mono_metadata_type_dup (mempool, inst->type_argv [num]);
+               if (num >= inst->type_argc) {
+                       MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
+                       mono_error_set_bad_image (error, image->module_name, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
+                               num, info ? info->name : "", inst->type_argc);
+                       return NULL;
+               }
+               nt = mono_metadata_type_dup (image, inst->type_argv [num]);
                nt->byref = type->byref;
                nt->attrs = type->attrs;
                return nt;
        }
        case MONO_TYPE_SZARRAY: {
                MonoClass *eclass = type->data.klass;
-               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
-               if (!inflated)
+               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
+               if (!inflated || !mono_error_ok (error))
                        return NULL;
-               nt = mono_metadata_type_dup (mempool, type);
+               nt = mono_metadata_type_dup (image, type);
                nt->data.klass = mono_class_from_mono_type (inflated);
                mono_metadata_free_type (inflated);
                return nt;
        }
        case MONO_TYPE_ARRAY: {
                MonoClass *eclass = type->data.array->eklass;
-               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
-               if (!inflated)
+               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
+               if (!inflated || !mono_error_ok (error))
                        return NULL;
-               nt = mono_metadata_type_dup (mempool, type);
+               nt = mono_metadata_type_dup (image, type);
                nt->data.array = g_memdup (nt->data.array, sizeof (MonoArrayType));
                nt->data.array->eklass = mono_class_from_mono_type (inflated);
                mono_metadata_free_type (inflated);
@@ -549,7 +573,7 @@ inflate_generic_type (MonoMemPool *mempool, MonoType *type, MonoGenericContext *
                if (gclass == type->data.generic_class)
                        return NULL;
 
-               nt = mono_metadata_type_dup (mempool, type);
+               nt = mono_metadata_type_dup (image, type);
                nt->data.generic_class = gclass;
                return nt;
        }
@@ -571,7 +595,7 @@ inflate_generic_type (MonoMemPool *mempool, MonoType *type, MonoGenericContext *
 
                gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
 
-               nt = mono_metadata_type_dup (mempool, type);
+               nt = mono_metadata_type_dup (image, type);
                nt->type = MONO_TYPE_GENERICINST;
                nt->data.generic_class = gclass;
                return nt;
@@ -594,26 +618,65 @@ mono_class_get_context (MonoClass *class)
        return class->generic_class ? mono_generic_class_get_context (class->generic_class) : NULL;
 }
 
+/*
+ * mono_class_get_generic_container:
+ *
+ *   Return the generic container of KLASS which should be a generic type definition.
+ */
+MonoGenericContainer*
+mono_class_get_generic_container (MonoClass *klass)
+{
+       g_assert (klass->is_generic);
+
+       return klass->generic_container;
+}
+
+/*
+ * mono_class_get_generic_class:
+ *
+ *   Return the MonoGenericClass of KLASS, which should be a generic instance.
+ */
+MonoGenericClass*
+mono_class_get_generic_class (MonoClass *klass)
+{
+       g_assert (klass->is_inflated);
+
+       return klass->generic_class;
+}
+
 /*
  * mono_class_inflate_generic_type_with_mempool:
  * @mempool: a mempool
  * @type: a type
  * @context: a generics context
+ * @error: error context
  *
  * The same as mono_class_inflate_generic_type, but allocates the MonoType
  * from mempool if it is non-NULL.  If it is NULL, the MonoType is
  * allocated on the heap and is owned by the caller.
+ * The returned type can potentially be the same as TYPE, so it should not be
+ * modified by the caller, and it should be freed using mono_metadata_free_type ().
  */
 MonoType*
-mono_class_inflate_generic_type_with_mempool (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context)
+mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
 {
-       MonoType *inflated = NULL; 
+       MonoType *inflated = NULL;
+       mono_error_init (error);
 
        if (context)
-               inflated = inflate_generic_type (mempool, type, context);
+               inflated = inflate_generic_type (image, type, context, error);
+       if (!mono_error_ok (error))
+               return NULL;
 
-       if (!inflated)
-               return mono_metadata_type_dup (mempool, type);
+       if (!inflated) {
+               MonoType *shared = mono_metadata_get_shared_type (type);
+
+               if (shared) {
+                       return shared;
+               } else {
+                       return mono_metadata_type_dup (image, type);
+               }
+       }
 
        mono_stats.inflated_type_count++;
        return inflated;
@@ -628,14 +691,86 @@ mono_class_inflate_generic_type_with_mempool (MonoMemPool *mempool, MonoType *ty
  * generics context @context.
  *
  * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
- * on the heap and is owned by the caller.
+ * on the heap and is owned by the caller. Returns NULL on error.
+ *
+ * @deprecated Please use mono_class_inflate_generic_type_checked instead
  */
 MonoType*
 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
 {
-       return mono_class_inflate_generic_type_with_mempool (NULL, type, context);
+       MonoError error;
+       MonoType *result;
+       result = mono_class_inflate_generic_type_checked (type, context, &error);
+
+       if (!mono_error_ok (&error)) {
+               mono_error_cleanup (&error);
+               return NULL;
+       }
+       return result;
+}
+
+/*
+ * mono_class_inflate_generic_type:
+ * @type: a type
+ * @context: a generics context
+ * @error: error context to use
+ *
+ * If @type is a generic type and @context is not NULL, instantiate it using the 
+ * generics context @context.
+ *
+ * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
+ * on the heap and is owned by the caller.
+ */
+MonoType*
+mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
+{
+       return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
+}
+
+/*
+ * mono_class_inflate_generic_type_no_copy:
+ *
+ *   Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
+ * was done.
+ */
+static MonoType*
+mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context)
+{
+       MonoError error;
+       MonoType *inflated = NULL; 
+
+       if (context) {
+               inflated = inflate_generic_type (image, type, context, &error);
+               g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+       }
+
+       if (!inflated)
+               return type;
+
+       mono_stats.inflated_type_count++;
+       return inflated;
 }
 
+/*
+ * mono_class_inflate_generic_class:
+ *
+ *   Inflate the class GKLASS with CONTEXT.
+ */
+MonoClass*
+mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
+{
+       MonoError error;
+       MonoClass *res;
+       MonoType *inflated;
+
+       inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, &error);
+       g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+
+       res = mono_class_from_mono_type (inflated);
+       mono_metadata_free_type (inflated);
+
+       return res;
+}
 
 static MonoGenericContext
 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with)
@@ -672,7 +807,7 @@ mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *conte
 }
 
 /**
- * mono_class_inflate_generic_method:
+ * mono_class_inflate_generic_method_full:
  *
  * Instantiate method @method with the generic context @context.
  * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
@@ -741,7 +876,7 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
        iresult = g_new0 (MonoMethodInflated, 1);
        iresult->context = *context;
        iresult->declaring = method;
-       iresult->is_mb_open = is_mb_open;
+       iresult->method.method.is_mb_open = is_mb_open;
 
        if (!context->method_inst && method->is_generic)
                iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
@@ -764,6 +899,8 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
 
        mono_stats.inflated_method_count++;
 
+       inflated_methods_size += sizeof (MonoMethodInflated);
+
        sig = mono_method_signature (method);
        if (sig->pinvoke) {
                memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
@@ -776,6 +913,7 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
        result->is_inflated = TRUE;
        result->is_generic = FALSE;
        result->signature = NULL;
+       result->is_mb_open = is_mb_open;
 
        if (!context->method_inst) {
                /* Set the generic_container of the result to the generic_container of method */
@@ -796,7 +934,11 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
                result->klass = klass_hint;
 
        if (!result->klass) {
-               MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context);
+               MonoError error;
+               MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, &error);
+
+               g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+
                result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
                if (inflated)
                        mono_metadata_free_type (inflated);
@@ -818,14 +960,43 @@ mono_get_inflated_method (MonoMethod *method)
        return method;
 }
 
+/*
+ * mono_method_get_context_general:
+ * @method: a method
+ * @uninflated: handle uninflated methods?
+ *
+ * Returns the generic context of a method or NULL if it doesn't have
+ * one.  For an inflated method that's the context stored in the
+ * method.  Otherwise it's in the method's generic container or in the
+ * generic container of the method's class.
+ */
 MonoGenericContext*
-mono_method_get_context (MonoMethod *method)
+mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
 {
-       MonoMethodInflated *imethod;
-       if (!method->is_inflated)
+       if (method->is_inflated) {
+               MonoMethodInflated *imethod = (MonoMethodInflated *) method;
+               return &imethod->context;
+       }
+       if (!uninflated)
                return NULL;
-       imethod = (MonoMethodInflated *) method;
-       return &imethod->context;
+       if (method->is_generic)
+               return &(mono_method_get_generic_container (method)->context);
+       if (method->klass->generic_container)
+               return &method->klass->generic_container->context;
+       return NULL;
+}
+
+/*
+ * mono_method_get_context:
+ * @method: a method
+ *
+ * Returns the generic context for method if it's inflated, otherwise
+ * NULL.
+ */
+MonoGenericContext*
+mono_method_get_context (MonoMethod *method)
+{
+       return mono_method_get_context_general (method, FALSE);
 }
 
 /*
@@ -843,9 +1014,7 @@ mono_method_get_generic_container (MonoMethod *method)
        if (!method->is_generic)
                return NULL;
 
-       mono_loader_lock ();
-       container = mono_property_hash_lookup (method->klass->image->property_hash, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
-       mono_loader_unlock ();
+       container = mono_image_property_lookup (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
        g_assert (container);
 
        return container;
@@ -862,9 +1031,7 @@ mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* con
 {
        g_assert (method->is_generic);
 
-       mono_loader_lock ();
-       mono_property_hash_insert (method->klass->image->property_hash, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
-       mono_loader_unlock ();
+       mono_image_property_insert (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
 }
 
 /** 
@@ -877,12 +1044,22 @@ mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* con
 static MonoType*
 mono_class_find_enum_basetype (MonoClass *class)
 {
+       MonoGenericContainer *container = NULL;
        MonoImage *m = class->image; 
        const int top = class->field.count;
        int i;
 
        g_assert (class->enumtype);
 
+       if (class->generic_container)
+               container = class->generic_container;
+       else if (class->generic_class) {
+               MonoClass *gklass = class->generic_class->container_class;
+
+               container = gklass->generic_container;
+               g_assert (container);
+       }
+
        /*
         * Fetch all the field information.
         */
@@ -890,23 +1067,23 @@ mono_class_find_enum_basetype (MonoClass *class)
                const char *sig;
                guint32 cols [MONO_FIELD_SIZE];
                int idx = class->field.first + i;
-               MonoGenericContainer *container = NULL;
                MonoType *ftype;
 
                /* class->field.first and idx points into the fieldptr table */
                mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
+
+               if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
+                       continue;
+
+               if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL))
+                       return NULL;
+
                sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
                mono_metadata_decode_value (sig, &sig);
                /* FIELD signature == 0x06 */
-               g_assert (*sig == 0x06);
-               if (class->generic_container)
-                       container = class->generic_container;
-               else if (class->generic_class) {
-                       MonoClass *gklass = class->generic_class->container_class;
+               if (*sig != 0x06)
+                       return NULL;
 
-                       container = gklass->generic_container;
-                       g_assert (container);
-               }
                ftype = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
                if (!ftype)
                        return NULL;
@@ -916,8 +1093,7 @@ mono_class_find_enum_basetype (MonoClass *class)
                        ftype->attrs = cols [MONO_FIELD_FLAGS];
                }
 
-               if (class->enumtype && !(cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC))
-                       return ftype;
+               return ftype;
        }
 
        return NULL;
@@ -942,7 +1118,7 @@ mono_class_setup_fields (MonoClass *class)
        gboolean explicit_size;
        MonoClassField *field;
        MonoGenericContainer *container = NULL;
-       MonoClass *gklass = NULL;
+       MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
 
        if (class->size_inited)
                return;
@@ -957,11 +1133,16 @@ mono_class_setup_fields (MonoClass *class)
                return;
        }
 
-       if (class->generic_class) {
-               MonoClass *gklass = class->generic_class->container_class;
-               mono_class_setup_fields (gklass);
-               top = gklass->field.count;
-               class->field.count = gklass->field.count;
+       if (gtd) {
+               mono_class_setup_fields (gtd);
+               if (gtd->exception_type) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       return;
+               }
+
+               top = gtd->field.count;
+               class->field.first = gtd->field.first;
+               class->field.count = gtd->field.count;
        }
 
        class->instance_size = 0;
@@ -971,8 +1152,13 @@ mono_class_setup_fields (MonoClass *class)
        if (class->parent) {
                /* For generic instances, class->parent might not have been initialized */
                mono_class_init (class->parent);
-               if (!class->parent->size_inited)
+               if (!class->parent->size_inited) {
                        mono_class_setup_fields (class->parent);
+                       if (class->parent->exception_type) {
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                               return;
+                       }
+               }
                class->instance_size += class->parent->instance_size;
                class->min_align = class->parent->min_align;
                /* we use |= since it may have been set already */
@@ -983,6 +1169,14 @@ mono_class_setup_fields (MonoClass *class)
                class->min_align = 1;
        }
 
+       /* We can't really enable 16 bytes alignment until the GC supports it.
+       The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
+       boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
+       Bug #506144 is an example of this issue.
+
+        if (class->simd_type)
+               class->min_align = 16;
+        */
        /* Get the real size */
        explicit_size = mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size);
 
@@ -1011,12 +1205,9 @@ mono_class_setup_fields (MonoClass *class)
 
        if (class->generic_container) {
                container = class->generic_container;
-       } else if (class->generic_class) {
-               gklass = class->generic_class->container_class;
-               container = gklass->generic_container;
+       } else if (gtd) {
+               container = gtd->generic_container;
                g_assert (container);
-
-               mono_class_setup_fields (gklass);
        }
 
        /*
@@ -1028,22 +1219,17 @@ mono_class_setup_fields (MonoClass *class)
 
                field->parent = class;
 
-               if (class->generic_class) {
-                       MonoClassField *gfield = &gklass->fields [i];
-                       MonoInflatedField *ifield = g_new0 (MonoInflatedField, 1);
+               if (gtd) {
+                       MonoClassField *gfield = &gtd->fields [i];
 
-                       ifield->generic_type = gfield->type;
-                       field->name = gfield->name;
-                       field->generic_info = ifield;
+                       field->name = mono_field_get_name (gfield);
                        /*This memory must come from the image mempool as we don't have a chance to free it.*/
-                       field->type = mono_class_inflate_generic_type_with_mempool (class->image->mempool, gfield->type, mono_class_get_context (class));
-                       field->type->attrs = gfield->type->attrs;
+                       field->type = mono_class_inflate_generic_type_no_copy (class->image, gfield->type, mono_class_get_context (class));
+                       g_assert (field->type->attrs == gfield->type->attrs);
                        if (mono_field_is_deleted (field))
                                continue;
                        field->offset = gfield->offset;
-                       field->data = gfield->data;
                } else {
-                       guint32 rva;
                        const char *sig;
                        guint32 cols [MONO_FIELD_SIZE];
 
@@ -1051,6 +1237,10 @@ mono_class_setup_fields (MonoClass *class)
                        mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
                        /* The name is needed for fieldrefs */
                        field->name = mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]);
+                       if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL)) {
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                               break;
+                       }
                        sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
                        mono_metadata_decode_value (sig, &sig);
                        /* FIELD signature == 0x06 */
@@ -1068,14 +1258,7 @@ mono_class_setup_fields (MonoClass *class)
                                field->offset = offset;
                                if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
                                        g_warning ("%s not initialized correctly (missing field layout info for %s)",
-                                                  class->name, field->name);
-                       }
-
-                       if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
-                               mono_metadata_field_info (m, idx, NULL, &rva, NULL);
-                               if (!rva)
-                                       g_warning ("field %s in %s should have RVA data, but hasn't", field->name, class->name);
-                               field->data = mono_image_rva_map (class->image, rva);
+                                                          class->name, mono_field_get_name (field));
                        }
                }
 
@@ -1085,16 +1268,20 @@ mono_class_setup_fields (MonoClass *class)
                                blittable = FALSE;
                        } else {
                                MonoClass *field_class = mono_class_from_mono_type (field->type);
-                               if (field_class)
+                               if (field_class) {
                                        mono_class_setup_fields (field_class);
+                                       if (field_class->exception_type) {
+                                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                                               break;
+                                       }
+                               }
                                if (!field_class || !field_class->blittable)
                                        blittable = FALSE;
                        }
                }
 
                if (class->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
-                       class->enum_basetype = field->type;
-                       class->cast_class = class->element_class = mono_class_from_mono_type (class->enum_basetype);
+                       class->cast_class = class->element_class = mono_class_from_mono_type (field->type);
                        blittable = class->element_class->blittable;
                }
 
@@ -1106,7 +1293,7 @@ mono_class_setup_fields (MonoClass *class)
 
        class->blittable = blittable;
 
-       if (class->enumtype && !class->enum_basetype) {
+       if (class->enumtype && !mono_class_enum_basetype (class)) {
                if (!((strcmp (class->name, "Enum") == 0) && (strcmp (class->name_space, "System") == 0)))
                        G_BREAKPOINT ();
        }
@@ -1319,7 +1506,7 @@ mono_class_layout_fields (MonoClass *class)
                                }
 
                                if ((top == 1) && (class->instance_size == sizeof (MonoObject)) &&
-                                       (strcmp (field->name, "$PRIVATE$") == 0)) {
+                                       (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
                                        /* This field is a hack inserted by MCS to empty structures */
                                        continue;
                                }
@@ -1498,6 +1685,8 @@ mono_class_setup_methods (MonoClass *class)
 
                class->method.count = 3 + (class->rank > 1? 2: 1);
 
+               mono_class_setup_interfaces (class);
+
                if (class->interface_count) {
                        count_generic = generic_array_methods (class);
                        first_generic = class->method.count;
@@ -1565,9 +1754,14 @@ mono_class_setup_methods (MonoClass *class)
                }
        }
 
-       if (MONO_CLASS_IS_INTERFACE (class))
-               for (i = 0; i < class->method.count; ++i)
-                       methods [i]->slot = i;
+       if (MONO_CLASS_IS_INTERFACE (class)) {
+               int slot = 0;
+               /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
+               for (i = 0; i < class->method.count; ++i) {
+                       if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
+                               methods [i]->slot = slot++;
+               }
+       }
 
        /* Needed because of the double-checking locking pattern */
        mono_memory_barrier ();
@@ -1614,6 +1808,79 @@ mono_class_get_method_by_index (MonoClass *class, int index)
        }
 }      
 
+/*
+ * mono_class_get_inflated_method:
+ *
+ *   Given an inflated class CLASS and a method METHOD which should be a method of
+ * CLASS's generic definition, return the inflated method corresponding to METHOD.
+ */
+MonoMethod*
+mono_class_get_inflated_method (MonoClass *class, MonoMethod *method)
+{
+       MonoClass *gklass = class->generic_class->container_class;
+       int i;
+
+       mono_class_setup_methods (gklass);
+       for (i = 0; i < gklass->method.count; ++i) {
+               if (gklass->methods [i] == method) {
+                       if (class->methods)
+                               return class->methods [i];
+                       else
+                               return mono_class_inflate_generic_method_full (gklass->methods [i], class, mono_class_get_context (class));
+               }
+       }
+
+       return NULL;
+}      
+
+/*
+ * mono_class_get_vtable_entry:
+ *
+ *   Returns class->vtable [offset], computing it if neccesary.
+ * LOCKING: Acquires the loader lock.
+ */
+MonoMethod*
+mono_class_get_vtable_entry (MonoClass *class, int offset)
+{
+       MonoMethod *m;
+
+       if (class->rank == 1) {
+               /* 
+                * szarrays do not overwrite any methods of Array, so we can avoid
+                * initializing their vtables in some cases.
+                */
+               mono_class_setup_vtable (class->parent);
+               if (offset < class->parent->vtable_size)
+                       return class->parent->vtable [offset];
+       }
+
+       if (class->generic_class) {
+               MonoClass *gklass = class->generic_class->container_class;
+               mono_class_setup_vtable (gklass);
+               m = gklass->vtable [offset];
+
+               m = mono_class_inflate_generic_method_full (m, class, mono_class_get_context (class));
+       } else {
+               mono_class_setup_vtable (class);
+               m = class->vtable [offset];
+       }
+
+       return m;
+}
+
+/*
+ * mono_class_get_vtable_size:
+ *
+ *   Return the vtable size for KLASS.
+ */
+int
+mono_class_get_vtable_size (MonoClass *klass)
+{
+       mono_class_setup_vtable (klass);
+
+       return klass->vtable_size;
+}
+
 static void
 mono_class_setup_properties (MonoClass *class)
 {
@@ -1623,30 +1890,32 @@ mono_class_setup_properties (MonoClass *class)
        MonoProperty *properties;
        guint32 last;
 
-       if (class->properties)
+       if (class->ext && class->ext->properties)
                return;
 
        mono_loader_lock ();
 
-       if (class->properties) {
+       if (class->ext && class->ext->properties) {
                mono_loader_unlock ();
                return;
        }
 
+       mono_class_alloc_ext (class);
+
        if (class->generic_class) {
                MonoClass *gklass = class->generic_class->container_class;
 
-               class->property = gklass->property;
-
                mono_class_init (gklass);
                mono_class_setup_properties (gklass);
 
-               properties = g_new0 (MonoProperty, class->property.count + 1);
+               class->ext->property = gklass->ext->property;
+
+               properties = g_new0 (MonoProperty, class->ext->property.count + 1);
 
-               for (i = 0; i < class->property.count; i++) {
+               for (i = 0; i < class->ext->property.count; i++) {
                        MonoProperty *prop = &properties [i];
 
-                       *prop = gklass->properties [i];
+                       *prop = gklass->ext->properties [i];
 
                        if (prop->get)
                                prop->get = mono_class_inflate_generic_method_full (
@@ -1658,18 +1927,18 @@ mono_class_setup_properties (MonoClass *class)
                        prop->parent = class;
                }
        } else {
-               class->property.first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
-               class->property.count = last - class->property.first;
+               class->ext->property.first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
+               class->ext->property.count = last - class->ext->property.first;
 
-               if (class->property.count)
+               if (class->ext->property.count)
                        mono_class_setup_methods (class);
 
-               properties = mono_image_alloc0 (class->image, sizeof (MonoProperty) * class->property.count);
-               for (i = class->property.first; i < last; ++i) {
+               properties = mono_image_alloc0 (class->image, sizeof (MonoProperty) * class->ext->property.count);
+               for (i = class->ext->property.first; i < last; ++i) {
                        mono_metadata_decode_table_row (class->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
-                       properties [i - class->property.first].parent = class;
-                       properties [i - class->property.first].attrs = cols [MONO_PROPERTY_FLAGS];
-                       properties [i - class->property.first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
+                       properties [i - class->ext->property.first].parent = class;
+                       properties [i - class->ext->property.first].attrs = cols [MONO_PROPERTY_FLAGS];
+                       properties [i - class->ext->property.first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
 
                        startm = mono_metadata_methods_from_property (class->image, i, &endm);
                        for (j = startm; j < endm; ++j) {
@@ -1685,10 +1954,10 @@ mono_class_setup_properties (MonoClass *class)
 
                                switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
                                case METHOD_SEMANTIC_SETTER:
-                                       properties [i - class->property.first].set = method;
+                                       properties [i - class->ext->property.first].set = method;
                                        break;
                                case METHOD_SEMANTIC_GETTER:
-                                       properties [i - class->property.first].get = method;
+                                       properties [i - class->ext->property.first].get = method;
                                        break;
                                default:
                                        break;
@@ -1700,7 +1969,7 @@ mono_class_setup_properties (MonoClass *class)
        mono_memory_barrier ();
 
        /* Leave this assignment as the last op in the function */
-       class->properties = properties;
+       class->ext->properties = properties;
 
        mono_loader_unlock ();
 }
@@ -1731,31 +2000,33 @@ mono_class_setup_events (MonoClass *class)
        guint32 last;
        MonoEvent *events;
 
-       if (class->events)
+       if (class->ext && class->ext->events)
                return;
 
        mono_loader_lock ();
 
-       if (class->events) {
+       if (class->ext && class->ext->events) {
                mono_loader_unlock ();
                return;
        }
 
+       mono_class_alloc_ext (class);
+
        if (class->generic_class) {
                MonoClass *gklass = class->generic_class->container_class;
                MonoGenericContext *context;
 
                mono_class_setup_events (gklass);
-               class->event = gklass->event;
+               class->ext->event = gklass->ext->event;
 
-               class->events = g_new0 (MonoEvent, class->event.count);
+               class->ext->events = g_new0 (MonoEvent, class->ext->event.count);
 
-               if (class->event.count)
+               if (class->ext->event.count)
                        context = mono_class_get_context (class);
 
-               for (i = 0; i < class->event.count; i++) {
-                       MonoEvent *event = &class->events [i];
-                       MonoEvent *gevent = &gklass->events [i];
+               for (i = 0; i < class->ext->event.count; i++) {
+                       MonoEvent *event = &class->ext->events [i];
+                       MonoEvent *gevent = &gklass->ext->events [i];
 
                        event->parent = class;
                        event->name = gevent->name;
@@ -1770,15 +2041,15 @@ mono_class_setup_events (MonoClass *class)
                return;
        }
 
-       class->event.first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
-       class->event.count = last - class->event.first;
+       class->ext->event.first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
+       class->ext->event.count = last - class->ext->event.first;
 
-       if (class->event.count)
+       if (class->ext->event.count)
                mono_class_setup_methods (class);
 
-       events = mono_image_alloc0 (class->image, sizeof (MonoEvent) * class->event.count);
-       for (i = class->event.first; i < last; ++i) {
-               MonoEvent *event = &events [i - class->event.first];
+       events = mono_image_alloc0 (class->image, sizeof (MonoEvent) * class->ext->event.count);
+       for (i = class->ext->event.first; i < last; ++i) {
+               MonoEvent *event = &events [i - class->ext->event.first];
 
                mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
                event->parent = class;
@@ -1831,7 +2102,7 @@ mono_class_setup_events (MonoClass *class)
        mono_memory_barrier ();
 
        /* Leave this assignment as the last op in the function */
-       class->events = events;
+       class->ext->events = events;
 
        mono_loader_unlock ();
 }
@@ -1921,6 +2192,8 @@ collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res)
 {
        int i;
        MonoClass *ic;
+
+       mono_class_setup_interfaces (klass);
        
        for (i = 0; i < klass->interface_count; i++) {
                ic = klass->interfaces [i];
@@ -2012,9 +2285,57 @@ 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 *class, guint rank)
+{
+       return rank ? mono_array_class_get (class, rank) :  class;
+}
+
+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));
+}
+
 /* 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 *class, int *num, int *is_enumerator)
@@ -2023,9 +2344,9 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume
        static MonoClass* generic_icollection_class = NULL;
        static MonoClass* generic_ienumerable_class = NULL;
        static MonoClass* generic_ienumerator_class = NULL;
-       MonoClass *fclass = NULL;
+       MonoClass *valuetype_types[2] = { NULL, NULL };
        MonoClass **interfaces = NULL;
-       int i, interface_count, real_count;
+       int i, interface_count, real_count, original_rank;
        int all_interfaces;
        gboolean internal_enumerator;
        gboolean eclass_is_valuetype;
@@ -2036,12 +2357,14 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume
        }
        internal_enumerator = FALSE;
        eclass_is_valuetype = FALSE;
+       original_rank = eclass->rank;
        if (class->byval_arg.type != MONO_TYPE_SZARRAY) {
                if (class->generic_class && class->nested_in == mono_defaults.array_class && strcmp (class->name, "InternalEnumerator`1") == 0)  {
                        /*
                         * For a Enumerator<T[]> we need to get the list of interfaces for T.
                         */
                        eclass = mono_class_from_mono_type (class->generic_class->context.class_inst->type_argv [0]);
+                       original_rank = eclass->rank;
                        eclass = eclass->element_class;
                        internal_enumerator = TRUE;
                        *is_enumerator = TRUE;
@@ -2076,32 +2399,21 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume
         * the generic interfaces needed to implement.
         */
        if (eclass->valuetype) {
-               if (eclass == mono_defaults.int16_class)
-                       fclass = mono_defaults.uint16_class;
-               else if (eclass == mono_defaults.uint16_class)
-                       fclass = mono_defaults.int16_class;
-               else if (eclass == mono_defaults.int32_class)
-                       fclass = mono_defaults.uint32_class;
-               else if (eclass == mono_defaults.uint32_class)
-                       fclass = mono_defaults.int32_class;
-               else if (eclass == mono_defaults.int64_class)
-                       fclass = mono_defaults.uint64_class;
-               else if (eclass == mono_defaults.uint64_class)
-                       fclass = mono_defaults.int64_class;
-               else if (eclass == mono_defaults.byte_class)
-                       fclass = mono_defaults.sbyte_class;
-               else if (eclass == mono_defaults.sbyte_class)
-                       fclass = mono_defaults.byte_class;
-               else {
-                       /* No additional interfaces for other value types */
-                       *num = 0;
-                       return NULL;
-               }
+               fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank);
 
                /* IList, ICollection, IEnumerable */
-               real_count = interface_count = 3;
-               interfaces = g_malloc0 (sizeof (MonoClass*) * interface_count);
-               interfaces [0] = fclass;
+               real_count = interface_count = valuetype_types [1] ? 6 : 3;
+               if (internal_enumerator) {
+                       ++real_count;
+                       if (valuetype_types [1])
+                               ++real_count;
+               }
+
+               interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
+               interfaces [0] = valuetype_types [0];
+               if (valuetype_types [1])
+                       interfaces [3] = valuetype_types [1];
+
                eclass_is_valuetype = TRUE;
        } else {
                int j;
@@ -2118,11 +2430,19 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume
                        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 */
                interface_count *= 3;
                real_count = interface_count;
-               if (internal_enumerator)
-                       real_count += idepth + eclass->interface_offsets_count;
+               if (internal_enumerator) {
+                       real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count;
+                       if (valuetype_types [1])
+                               ++real_count;
+               }
                interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
                if (MONO_CLASS_IS_INTERFACE (eclass)) {
                        interfaces [0] = mono_defaults.object_class;
@@ -2146,77 +2466,118 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume
                                j += 3;
                        }
                }
+               if (valuetype_types [1]) {
+                       interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank);
+                       j += 3;
+               }
        }
 
        /* instantiate the generic interfaces */
        for (i = 0; i < interface_count; i += 3) {
-               MonoType *args [1];
                MonoClass *iface = interfaces [i];
 
-               args [0] = &iface->byval_arg;
-               interfaces [i] = mono_class_bind_generic_parameters (
-                       mono_defaults.generic_ilist_class, 1, args, FALSE);
-               //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));
-               args [0] = &iface->byval_arg;
-               interfaces [i + 1] = mono_class_bind_generic_parameters (
-                       generic_icollection_class, 1, args, FALSE);
-               args [0] = &iface->byval_arg;
-               interfaces [i + 2] = mono_class_bind_generic_parameters (
-                       generic_ienumerable_class, 1, args, FALSE);
-               //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i + 1]->byval_arg, 0));
-               //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i + 2]->byval_arg, 0));
+               interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface);
+               interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface);
+               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++) {
-                       MonoType *args [1];
-                       MonoClass *iface = interfaces [i];
-
-                       args [0] = &iface->byval_arg;
-                       interfaces [i] = mono_class_bind_generic_parameters (
-                               generic_ienumerator_class, 1, args, FALSE);
-                       /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+                       interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]);
                }
+               j = interface_count;
                if (!eclass_is_valuetype) {
-                       j = interface_count;
-                       for (i = 0; i < eclass->idepth; i++) {
-                               MonoType *args [1];
-                               args [0] = &eclass->supertypes [i]->byval_arg;
-                               interfaces [j] = mono_class_bind_generic_parameters (
-                                       generic_ienumerator_class, 1, args, FALSE);
-                               /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+                       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++) {
-                               MonoClass *iface = eclass->interfaces_packed [i];
-                               MonoType *args [1];
-                               args [0] = &iface->byval_arg;
-                               interfaces [j] = mono_class_bind_generic_parameters (
-                                       generic_ienumerator_class, 1, args, FALSE);
-                               /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+                               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 (&class->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;
+}
+
 /*
- * LOCKING: this is supposed to be called with the loader lock held.
+ * Return the number of virtual methods.
+ * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
+ * FIXME It would be nice if this information could be cached somewhere.
  */
 static int
-setup_interface_offsets (MonoClass *class, int cur_slot)
+count_virtual_methods (MonoClass *class)
 {
-       MonoClass *k, *ic;
-       int i, max_iid;
-       MonoClass **interfaces_full;
-       int *interface_offsets_full;
-       GPtrArray *ifaces;
-       int interface_offsets_count;
-       MonoClass **array_interfaces;
-       int num_array_interfaces;
+       int i, count = 0;
+       guint32 flags;
+       class = mono_class_get_generic_type_definition (class); /*We can find this information by looking at the GTD*/
+
+       if (class->methods || !MONO_CLASS_HAS_STATIC_METADATA (class)) {
+               mono_class_setup_methods (class);
+
+               for (i = 0; i < class->method.count; ++i) {
+                       flags = class->methods [i]->flags;
+                       if (flags & METHOD_ATTRIBUTE_VIRTUAL)
+                               ++count;
+               }
+       } else {
+               for (i = 0; i < class->method.count; ++i) {
+                       flags = mono_metadata_decode_table_row_col (class->image, MONO_TABLE_METHOD, class->method.first + i, MONO_METHOD_FLAGS);
+
+                       if (flags & METHOD_ATTRIBUTE_VIRTUAL)
+                               ++count;
+               }
+       }
+       return count;
+}
+
+/*
+ * LOCKING: this is supposed to be called with the loader lock held.
+ */
+static int
+setup_interface_offsets (MonoClass *class, int cur_slot)
+{
+       MonoClass *k, *ic;
+       int i, max_iid;
+       MonoClass **interfaces_full;
+       int *interface_offsets_full;
+       GPtrArray *ifaces;
+       int interface_offsets_count;
+       MonoClass **array_interfaces;
+       int num_array_interfaces;
        int is_enumerator = FALSE;
 
        /* 
@@ -2269,36 +2630,37 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
                interface_offsets_full [i] = -1;
        }
 
-       ifaces = mono_class_get_implemented_interfaces (class);
-       if (ifaces) {
-               for (i = 0; i < ifaces->len; ++i) {
-                       ic = g_ptr_array_index (ifaces, i);
-                       interfaces_full [ic->interface_id] = ic;
-                       interface_offsets_full [ic->interface_id] = cur_slot;
-                       cur_slot += ic->method.count;
-               }
-               g_ptr_array_free (ifaces, TRUE);
-       }
-
        for (k = class->parent; k ; k = k->parent) {
                ifaces = mono_class_get_implemented_interfaces (k);
                if (ifaces) {
                        for (i = 0; i < ifaces->len; ++i) {
+                               int io;
                                ic = g_ptr_array_index (ifaces, i);
-
-                               if (interface_offsets_full [ic->interface_id] == -1) {
-                                       int io = mono_class_interface_offset (k, ic);
-
-                                       g_assert (io >= 0);
-
-                                       interfaces_full [ic->interface_id] = ic;
-                                       interface_offsets_full [ic->interface_id] = io;
-                               }
+                               
+                               /*Force the sharing of interface offsets between parent and subtypes.*/
+                               io = mono_class_interface_offset (k, ic);
+                               g_assert (io >= 0);
+                               interfaces_full [ic->interface_id] = ic;
+                               interface_offsets_full [ic->interface_id] = io;
                        }
                        g_ptr_array_free (ifaces, TRUE);
                }
        }
 
+
+       ifaces = mono_class_get_implemented_interfaces (class);
+       if (ifaces) {
+               for (i = 0; i < ifaces->len; ++i) {
+                       ic = g_ptr_array_index (ifaces, i);
+                       if (interfaces_full [ic->interface_id] != NULL)
+                               continue;
+                       interfaces_full [ic->interface_id] = ic;
+                       interface_offsets_full [ic->interface_id] = cur_slot;
+                       cur_slot += count_virtual_methods (ic);
+               }
+               g_ptr_array_free (ifaces, TRUE);
+       }
+
        if (MONO_CLASS_IS_INTERFACE (class)) {
                interfaces_full [class->interface_id] = class;
                interface_offsets_full [class->interface_id] = cur_slot;
@@ -2307,8 +2669,8 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
        if (num_array_interfaces) {
                if (is_enumerator) {
                        int ienumerator_offset;
-                       g_assert (strcmp (class->interfaces [0]->name, "IEnumerator`1") == 0);
-                       ienumerator_offset = interface_offsets_full [class->interfaces [0]->interface_id];
+                       int ienumerator_idx = find_array_interface (class, "IEnumerator`1");
+                       ienumerator_offset = interface_offsets_full [class->interfaces [ienumerator_idx]->interface_id];
                        for (i = 0; i < num_array_interfaces; ++i) {
                                ic = array_interfaces [i];
                                interfaces_full [ic->interface_id] = ic;
@@ -2320,12 +2682,12 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
                        }
                } else {
                        int ilist_offset, icollection_offset, ienumerable_offset;
-                       g_assert (strcmp (class->interfaces [0]->name, "IList`1") == 0);
-                       g_assert (strcmp (class->interfaces [0]->interfaces [0]->name, "ICollection`1") == 0);
-                       g_assert (strcmp (class->interfaces [0]->interfaces [1]->name, "IEnumerable`1") == 0);
-                       ilist_offset = interface_offsets_full [class->interfaces [0]->interface_id];
-                       icollection_offset = interface_offsets_full [class->interfaces [0]->interfaces [0]->interface_id];
-                       ienumerable_offset = interface_offsets_full [class->interfaces [0]->interfaces [1]->interface_id];
+                       int ilist_iface_idx = find_array_interface (class, "IList`1");
+                       int icollection_iface_idx = find_array_interface (class->interfaces [ilist_iface_idx], "ICollection`1");
+                       int ienumerable_iface_idx = find_array_interface (class->interfaces [ilist_iface_idx], "IEnumerable`1");
+                       ilist_offset = interface_offsets_full [class->interfaces [ilist_iface_idx]->interface_id];
+                       icollection_offset = interface_offsets_full [class->interfaces [ilist_iface_idx]->interfaces [icollection_iface_idx]->interface_id];
+                       ienumerable_offset = interface_offsets_full [class->interfaces [ilist_iface_idx]->interfaces [ienumerable_iface_idx]->interface_id];
                        g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
                        for (i = 0; i < num_array_interfaces; ++i) {
                                ic = array_interfaces [i];
@@ -2383,7 +2745,13 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
 }
 
 /*
- * Setup interface offsets for interfaces. Used by Ref.Emit.
+ * Setup interface offsets for interfaces. 
+ * Initializes:
+ * - class->max_interface_id
+ * - class->interface_offsets_count
+ * - class->interfaces_packed
+ * - class->interface_offsets_packed
+ * - class->interface_bitmap
  */
 void
 mono_class_setup_interface_offsets (MonoClass *class)
@@ -2420,11 +2788,15 @@ mono_class_setup_vtable (MonoClass *class)
        if (class->vtable)
                return;
 
-       /* This sets method->slot for all methods if this is an interface */
-       mono_class_setup_methods (class);
+       if (mono_debug_using_mono_debugger ())
+               /* The debugger currently depends on this */
+               mono_class_setup_methods (class);
 
-       if (MONO_CLASS_IS_INTERFACE (class))
+       if (MONO_CLASS_IS_INTERFACE (class)) {
+               /* This sets method->slot for all methods if this is an interface */
+               mono_class_setup_methods (class);
                return;
+       }
 
        mono_loader_lock ();
 
@@ -2481,41 +2853,14 @@ mono_class_setup_vtable (MonoClass *class)
        return;
 }
 
-static void
-check_core_clr_override_method (MonoClass *class, MonoMethod *override, MonoMethod *base)
-{
-       MonoSecurityCoreCLRLevel override_level = mono_security_core_clr_method_level (override, FALSE);
-       MonoSecurityCoreCLRLevel base_level = mono_security_core_clr_method_level (base, FALSE);
-
-       if (override_level != base_level && base_level == MONO_SECURITY_CORE_CLR_CRITICAL)
-               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
-}
-
-
-static int __use_new_interface_vtable_code = -1;
-static gboolean
-use_new_interface_vtable_code (void) {
-       if (__use_new_interface_vtable_code == -1) {
-               char *env_var = getenv ("MONO_USE_NEW_INTERFACE_VTABLE_CODE");
-               if (env_var == NULL) {
-                       __use_new_interface_vtable_code = TRUE;
-               } else {
-                       if ((strcmp (env_var, "0") == 0) || (strcmp (env_var, "false") == 0) || (strcmp (env_var, "FALSE") == 0)) {
-                               __use_new_interface_vtable_code = FALSE;
-                       } else {
-                               __use_new_interface_vtable_code = TRUE;
-                       }
-               }
-       }
-       return __use_new_interface_vtable_code;
-}
-
-
 #define DEBUG_INTERFACE_VTABLE_CODE 0
 #define TRACE_INTERFACE_VTABLE_CODE 0
+#define VERIFY_INTERFACE_VTABLE_CODE 0
+#define VTABLE_SELECTOR (1)
 
 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
+       if (!(VTABLE_SELECTOR)) break; \
        stmt;\
 } while (0)
 #else
@@ -2524,12 +2869,22 @@ use_new_interface_vtable_code (void) {
 
 #if TRACE_INTERFACE_VTABLE_CODE
 #define TRACE_INTERFACE_VTABLE(stmt) do {\
+       if (!(VTABLE_SELECTOR)) break; \
        stmt;\
 } while (0)
 #else
 #define TRACE_INTERFACE_VTABLE(stmt)
 #endif
 
+#if VERIFY_INTERFACE_VTABLE_CODE
+#define VERIFY_INTERFACE_VTABLE(stmt) do {\
+       if (!(VTABLE_SELECTOR)) break; \
+       stmt;\
+} while (0)
+#else
+#define VERIFY_INTERFACE_VTABLE(stmt)
+#endif
+
 
 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
 static char*
@@ -2600,7 +2955,7 @@ check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *c
                }
 
                if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
-                       check_core_clr_override_method (class, cm, im);
+                       mono_security_core_clr_check_override (class, cm, im);
                TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
                return TRUE;
        } else {
@@ -2669,7 +3024,7 @@ check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *c
                }
 
                if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
-                       check_core_clr_override_method (class, cm, im);
+                       mono_security_core_clr_check_override (class, cm, im);
                
                TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
                return TRUE;
@@ -2730,19 +3085,77 @@ print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_no
 }
 #endif
 
+#if VERIFY_INTERFACE_VTABLE_CODE
+static int
+mono_method_try_get_vtable_index (MonoMethod *method)
+{
+       if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+               MonoMethodInflated *imethod = (MonoMethodInflated*)method;
+               if (imethod->declaring->is_generic)
+                       return imethod->declaring->slot;
+       }
+       return method->slot;
+}
+
+static void
+mono_class_verify_vtable (MonoClass *class)
+{
+       int i;
+       char *full_name = mono_type_full_name (&class->byval_arg);
+
+       printf ("*** Verifying VTable of class '%s' \n", full_name);
+       g_free (full_name);
+       full_name = NULL;
+       
+       if (!class->methods)
+               return;
+
+       for (i = 0; i < class->method.count; ++i) {
+               MonoMethod *cm = class->methods [i];
+               int slot;
+
+               if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
+                       continue;
+
+               g_free (full_name);
+               full_name = mono_method_full_name (cm, TRUE);
+
+               slot = mono_method_try_get_vtable_index (cm);
+               if (slot >= 0) {
+                       if (slot >= class->vtable_size) {
+                               printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, class->vtable_size);
+                               continue;
+                       }
+
+                       if (slot >= 0 && class->vtable [slot] != cm && (class->vtable [slot])) {
+                               char *other_name = class->vtable [slot] ? mono_method_full_name (class->vtable [slot], TRUE) : g_strdup ("[null value]");
+                               printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
+                               g_free (other_name);
+                       }
+               } else
+                       printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
+       }
+       g_free (full_name);
+}
+#endif
+
 static void
 print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
        int index;
        char *method_signature;
+       char *type_name;
        
        for (index = 0; index < onum; ++index) {
                g_print (" at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name, 
                         overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
        }
        method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
-       printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
-               mono_type_get_name (&ic->byval_arg), im->name, method_signature, class->name_space, class->name);
+       type_name = mono_type_full_name (&class->byval_arg);
+       printf ("no implementation for interface method %s::%s(%s) in class %s\n",
+               mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name);
        g_free (method_signature);
+       g_free (type_name);
+       mono_class_setup_methods (class);
        for (index = 0; index < class->method.count; ++index) {
                MonoMethod *cm = class->methods [index];
                method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
@@ -2752,6 +3165,43 @@ print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, Mono
        }
 }
 
+static gboolean
+verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
+{
+       int i;
+
+       for (i = 0; i < onum; ++i) {
+               MonoMethod *decl = overrides [i * 2];
+               MonoMethod *body = overrides [i * 2 + 1];
+
+               if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (class)) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
+                       return FALSE;
+               }
+
+               if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
+                       if (body->flags & METHOD_ATTRIBUTE_STATIC)
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
+                       else
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
+                       return FALSE;
+               }
+
+               if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
+                       if (body->flags & METHOD_ATTRIBUTE_STATIC)
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
+                       else
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
+                       return FALSE;
+               }
+
+               if (!mono_class_is_assignable_from_slow (decl->klass, class)) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type"));
+                       return FALSE;
+               }
+       }
+       return TRUE;
+}
 /*
  * LOCKING: this is supposed to be called with the loader lock held.
  */
@@ -2761,9 +3211,11 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
        MonoClass *k, *ic;
        MonoMethod **vtable;
        int i, max_vtsize = 0, max_iid, cur_slot = 0;
-       GPtrArray *ifaces, *pifaces = NULL;
+       GPtrArray *ifaces = NULL;
        GHashTable *override_map = NULL;
        gboolean security_enabled = mono_is_security_manager_active ();
+       MonoMethod *cm;
+       gpointer class_iter;
 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
        int first_non_interface_slot;
 #endif
@@ -2771,7 +3223,11 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
        if (class->vtable)
                return;
 
+       if (overrides && !verify_class_overrides (class, overrides, onum))
+               return;
+
        ifaces = mono_class_get_implemented_interfaces (class);
+
        if (ifaces) {
                for (i = 0; i < ifaces->len; i++) {
                        MonoClass *ic = g_ptr_array_index (ifaces, i);
@@ -2799,40 +3255,69 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
        max_iid = class->max_interface_id;
        DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
 
-       if (use_new_interface_vtable_code ()) {
-               if (class->parent && class->parent->vtable_size) {
-                       MonoClass *parent = class->parent;
-                       int i;
-                       
-                       memcpy (vtable, parent->vtable,  sizeof (gpointer) * parent->vtable_size);
-                       
-                       // Also inherit parent interface vtables, just as a starting point.
-                       // This is needed otherwise bug-77127.exe fails when the property methods
-                       // have different names in the iterface and the class, because for child
-                       // classes the ".override" information is not used anymore.
-                       for (i = 0; i < parent->interface_offsets_count; i++) {
-                               MonoClass *parent_interface = parent->interfaces_packed [i];
-                               int interface_offset = mono_class_interface_offset (class, parent_interface);
+       /* Optimized version for generic instances */
+       if (class->generic_class) {
+               MonoClass *gklass = class->generic_class->container_class;
+               MonoMethod **tmp;
+
+               mono_class_setup_vtable (gklass);
+               if (gklass->exception_type != MONO_EXCEPTION_NONE) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       return;
+               }
+
+               tmp = mono_image_alloc0 (class->image, sizeof (gpointer) * gklass->vtable_size);
+               class->vtable_size = gklass->vtable_size;
+               for (i = 0; i < gklass->vtable_size; ++i)
+                       if (gklass->vtable [i]) {
+                               tmp [i] = mono_class_inflate_generic_method_full (gklass->vtable [i], class, mono_class_get_context (class));
+                               tmp [i]->slot = gklass->vtable [i]->slot;
+                       }
+               mono_memory_barrier ();
+               class->vtable = tmp;
+
+               /* Have to set method->slot for abstract virtual methods */
+               if (class->methods && gklass->methods) {
+                       for (i = 0; i < class->method.count; ++i)
+                               if (class->methods [i]->slot == -1)
+                                       class->methods [i]->slot = gklass->methods [i]->slot;
+               }
+
+               return;
+       }
+
+       if (class->parent && class->parent->vtable_size) {
+               MonoClass *parent = class->parent;
+               int i;
+               
+               memcpy (vtable, parent->vtable,  sizeof (gpointer) * parent->vtable_size);
+               
+               // Also inherit parent interface vtables, just as a starting point.
+               // This is needed otherwise bug-77127.exe fails when the property methods
+               // have different names in the iterface and the class, because for child
+               // classes the ".override" information is not used anymore.
+               for (i = 0; i < parent->interface_offsets_count; i++) {
+                       MonoClass *parent_interface = parent->interfaces_packed [i];
+                       int interface_offset = mono_class_interface_offset (class, parent_interface);
+                       /*FIXME this is now dead code as this condition will never hold true.
+                       Since interface offsets are inherited then the offset of an interface implemented
+                       by a parent will never be the out of it's vtable boundary.
+                       */
+                       if (interface_offset >= parent->vtable_size) {
+                               int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
+                               int j;
                                
-                               if (interface_offset >= parent->vtable_size) {
-                                       int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
-                                       int j;
-                                       
-                                       mono_class_setup_methods (parent_interface);
-                                       TRACE_INTERFACE_VTABLE (printf ("    +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
-                                       for (j = 0; j < parent_interface->method.count; j++) {
-                                               vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
-                                               TRACE_INTERFACE_VTABLE (printf ("    --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
-                                                               parent_interface_offset + j, parent_interface_offset, j,
-                                                               interface_offset + j, interface_offset, j));
-                                       }
+                               mono_class_setup_methods (parent_interface);
+                               TRACE_INTERFACE_VTABLE (printf ("    +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
+                               for (j = 0; j < parent_interface->method.count; j++) {
+                                       vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
+                                       TRACE_INTERFACE_VTABLE (printf ("    --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
+                                                       parent_interface_offset + j, parent_interface_offset, j,
+                                                       interface_offset + j, interface_offset, j));
                                }
-                               
                        }
+                       
                }
-       } else {
-               if (class->parent && class->parent->vtable_size)
-                       memcpy (vtable, class->parent->vtable,  sizeof (gpointer) * class->parent->vtable_size);
        }
 
        TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
@@ -2841,9 +3326,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                MonoMethod *decl = overrides [i*2];
                if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
                        int dslot;
-                       mono_class_setup_methods (decl->klass);
-                       g_assert (decl->slot != -1);
-                       dslot = decl->slot + mono_class_interface_offset (class, decl->klass);
+                       dslot = mono_method_get_vtable_slot (decl) + mono_class_interface_offset (class, decl->klass);
                        vtable [dslot] = overrides [i*2 + 1];
                        vtable [dslot]->slot = dslot;
                        if (!override_map)
@@ -2852,376 +3335,131 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                        g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
 
                        if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
-                               check_core_clr_override_method (class, vtable [dslot], decl);
+                               mono_security_core_clr_check_override (class, vtable [dslot], decl);
                }
        }
        TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
        TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
 
-       if (use_new_interface_vtable_code ()) {
-               // Loop on all implemented interfaces...
-               for (i = 0; i < class->interface_offsets_count; i++) {
-                       MonoClass *parent = class->parent;
-                       int ic_offset;
-                       gboolean interface_is_explicitly_implemented_by_class;
-                       int im_index;
-                       
-                       ic = class->interfaces_packed [i];
-                       ic_offset = mono_class_interface_offset (class, ic);
+       // Loop on all implemented interfaces...
+       for (i = 0; i < class->interface_offsets_count; i++) {
+               MonoClass *parent = class->parent;
+               int ic_offset;
+               gboolean interface_is_explicitly_implemented_by_class;
+               int im_index;
+               
+               ic = class->interfaces_packed [i];
+               ic_offset = mono_class_interface_offset (class, ic);
 
-                       mono_class_setup_methods (ic);
-                       
-                       // Check if this interface is explicitly implemented (instead of just inherited)
-                       if (parent != NULL) {
-                               int implemented_interfaces_index;
-                               interface_is_explicitly_implemented_by_class = FALSE;
-                               for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
-                                       if (ic == class->interfaces [implemented_interfaces_index]) {
-                                               interface_is_explicitly_implemented_by_class = TRUE;
-                                               break;
-                                       }
+               mono_class_setup_methods (ic);
+               
+               // Check if this interface is explicitly implemented (instead of just inherited)
+               if (parent != NULL) {
+                       int implemented_interfaces_index;
+                       interface_is_explicitly_implemented_by_class = FALSE;
+                       for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
+                               if (ic == class->interfaces [implemented_interfaces_index]) {
+                                       interface_is_explicitly_implemented_by_class = TRUE;
+                                       break;
                                }
-                       } else {
-                               interface_is_explicitly_implemented_by_class = TRUE;
                        }
+               } else {
+                       interface_is_explicitly_implemented_by_class = TRUE;
+               }
+               
+               // Loop on all interface methods...
+               for (im_index = 0; im_index < ic->method.count; im_index++) {
+                       MonoMethod *im = ic->methods [im_index];
+                       int im_slot = ic_offset + im->slot;
+                       MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
                        
-                       // Loop on all interface methods...
-                       for (im_index = 0; im_index < ic->method.count; im_index++) {
-                               MonoMethod *im = ic->methods [im_index];
-                               int im_slot = ic_offset + im->slot;
-                               MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
-                               
-                               if (im->flags & METHOD_ATTRIBUTE_STATIC)
-                                       continue;
+                       if (im->flags & METHOD_ATTRIBUTE_STATIC)
+                               continue;
 
-                               // If there is an explicit implementation, just use it right away,
-                               // otherwise look for a matching method
-                               if (override_im == NULL) {
-                                       int cm_index;
-                                       
-                                       // First look for a suitable method among the class methods
-                                       for (cm_index = 0; cm_index < class->method.count; cm_index++) {
-                                               MonoMethod *cm = class->methods [cm_index];
+                       // If there is an explicit implementation, just use it right away,
+                       // otherwise look for a matching method
+                       if (override_im == NULL) {
+                               int cm_index;
+                               gpointer iter;
+                               MonoMethod *cm;
+
+                               // First look for a suitable method among the class methods
+                               iter = NULL;
+                               while ((cm = mono_class_get_virtual_methods (class, &iter))) {
+                                       TRACE_INTERFACE_VTABLE (printf ("    For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
+                                       if (check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
+                                               TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
+                                               vtable [im_slot] = cm;
+                                               /* Why do we need this? */
+                                               if (cm->slot < 0) {
+                                                       cm->slot = im_slot;
+                                               }
+                                       }
+                                       TRACE_INTERFACE_VTABLE (printf ("\n"));
+                               }
+                               
+                               // If the slot is still empty, look in all the inherited virtual methods...
+                               if ((vtable [im_slot] == NULL) && class->parent != NULL) {
+                                       MonoClass *parent = class->parent;
+                                       // Reverse order, so that last added methods are preferred
+                                       for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
+                                               MonoMethod *cm = parent->vtable [cm_index];
                                                
-                                               TRACE_INTERFACE_VTABLE (printf ("    For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
-                                               if ((cm->flags & METHOD_ATTRIBUTE_VIRTUAL) && check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
-                                                       TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
+                                               TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("    For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
+                                               if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
+                                                       TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
                                                        vtable [im_slot] = cm;
                                                        /* Why do we need this? */
                                                        if (cm->slot < 0) {
                                                                cm->slot = im_slot;
                                                        }
+                                                       break;
                                                }
-                                               TRACE_INTERFACE_VTABLE (printf ("\n"));
-                                       }
-                                       
-                                       // If the slot is still empty, look in all the inherited virtual methods...
-                                       if ((vtable [im_slot] == NULL) && class->parent != NULL) {
-                                               MonoClass *parent = class->parent;
-                                               // Reverse order, so that last added methods are preferred
-                                               for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
-                                                       MonoMethod *cm = parent->vtable [cm_index];
-                                                       
-                                                       TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("    For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
-                                                       if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
-                                                               TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
-                                                               vtable [im_slot] = cm;
-                                                               /* Why do we need this? */
-                                                               if (cm->slot < 0) {
-                                                                       cm->slot = im_slot;
-                                                               }
-                                                               break;
-                                                       }
-                                                       TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
-                                               }
+                                               TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
                                        }
-                               } else {
-                                       g_assert (vtable [im_slot] == override_im);
                                }
+                       } else {
+                               g_assert (vtable [im_slot] == override_im);
                        }
                }
-               
-               // If the class is not abstract, check that all its interface slots are full.
-               // The check is done here and not directly at the end of the loop above because
-               // it can happen (for injected generic array interfaces) that the same slot is
-               // processed multiple times (those interfaces have overlapping slots), and it
-               // will not always be the first pass the one that fills the slot.
-               if (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
-                       for (i = 0; i < class->interface_offsets_count; i++) {
-                               int ic_offset;
-                               int im_index;
-                               
-                               ic = class->interfaces_packed [i];
-                               ic_offset = mono_class_interface_offset (class, ic);
+       }
+       
+       // If the class is not abstract, check that all its interface slots are full.
+       // The check is done here and not directly at the end of the loop above because
+       // it can happen (for injected generic array interfaces) that the same slot is
+       // processed multiple times (those interfaces have overlapping slots), and it
+       // will not always be the first pass the one that fills the slot.
+       if (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+               for (i = 0; i < class->interface_offsets_count; i++) {
+                       int ic_offset;
+                       int im_index;
+                       
+                       ic = class->interfaces_packed [i];
+                       ic_offset = mono_class_interface_offset (class, ic);
+                       
+                       for (im_index = 0; im_index < ic->method.count; im_index++) {
+                               MonoMethod *im = ic->methods [im_index];
+                               int im_slot = ic_offset + im->slot;
                                
-                               for (im_index = 0; im_index < ic->method.count; im_index++) {
-                                       MonoMethod *im = ic->methods [im_index];
-                                       int im_slot = ic_offset + im->slot;
-                                       
-                                       if (im->flags & METHOD_ATTRIBUTE_STATIC)
-                                               continue;
-
-                                       TRACE_INTERFACE_VTABLE (printf ("      [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
-                                                       im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
-                                       if (vtable [im_slot] == NULL) {
-                                               print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum);
-                                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
-                                               if (override_map)
-                                                       g_hash_table_destroy (override_map);
-                                               return;
-                                       }
-                               }
-                       }
-               }
-       } else {
-               for (k = class; k ; k = k->parent) {
-                       int nifaces = 0;
-
-                       ifaces = mono_class_get_implemented_interfaces (k);
-                       if (ifaces) {
-                               nifaces = ifaces->len;
-                               if (k->generic_class) {
-                                       pifaces = mono_class_get_implemented_interfaces (
-                                               k->generic_class->container_class);
-                                       g_assert (pifaces && (pifaces->len == nifaces));
-                               }
-                       }
-                       for (i = 0; i < nifaces; i++) {
-                               MonoClass *pic = NULL;
-                               int j, l, io;
-
-                               ic = g_ptr_array_index (ifaces, i);
-                               if (pifaces)
-                                       pic = g_ptr_array_index (pifaces, i);
-                               g_assert (ic->interface_id <= k->max_interface_id);
-                               io = mono_class_interface_offset (k, ic);
-
-                               g_assert (io >= 0);
-                               g_assert (io <= max_vtsize);
-
-                               if (k == class) {
-                                       mono_class_setup_methods (ic);
-                                       for (l = 0; l < ic->method.count; l++) {
-                                               MonoMethod *im = ic->methods [l];                                               
-
-                                               if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
-                                                       continue;
-
-                                               for (j = 0; j < class->method.count; ++j) {
-                                                       MonoMethod *cm = class->methods [j];
-                                                       if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
-                                                           !((cm->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) ||
-                                                           !(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT))
-                                                               continue;
-                                                       if (!strcmp(cm->name, im->name) && 
-                                                           mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
-
-                                                               /* CAS - SecurityAction.InheritanceDemand on interface */
-                                                               if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
-                                                                       mono_secman_inheritancedemand_method (cm, im);
-                                                               }
-
-                                                               if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
-                                                                       check_core_clr_override_method (class, cm, im);
-
-                                                               g_assert (io + l <= max_vtsize);
-                                                               vtable [io + l] = cm;
-                                                               TRACE_INTERFACE_VTABLE (printf ("    [NOA] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
-                                                               TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
-                                                               TRACE_INTERFACE_VTABLE (printf ("\n"));
-                                                       }
-                                               }
-                                       }
-                               } else {
-                                       /* already implemented */
-                                       if (io >= k->vtable_size)
-                                               continue;
-                               }
-
-                               // Override methods with the same fully qualified name
-                               for (l = 0; l < ic->method.count; l++) {
-                                       MonoMethod *im = ic->methods [l];                                               
-                                       char *qname, *fqname, *cname, *the_cname;
-                                       MonoClass *k1;
-                                       
-                                       if (vtable [io + l])
-                                               continue;
-
-                                       if (pic) {
-                                               the_cname = mono_type_get_name_full (&pic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
-                                               cname = the_cname;
-                                       } else {
-                                               the_cname = NULL;
-                                               cname = (char*)ic->name;
-                                       }
-                                               
-                                       qname = g_strconcat (cname, ".", im->name, NULL);
-                                       if (ic->name_space && ic->name_space [0])
-                                               fqname = g_strconcat (ic->name_space, ".", cname, ".", im->name, NULL);
-                                       else
-                                               fqname = NULL;
-
-                                       for (k1 = class; k1; k1 = k1->parent) {
-                                               for (j = 0; j < k1->method.count; ++j) {
-                                                       MonoMethod *cm = k1->methods [j];
-
-                                                       if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
-                                                               continue;
-
-                                                       if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
-                                                                       mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im)) &&
-                                                                       ((vtable [io + l] == NULL) || mono_class_is_subclass_of (cm->klass, vtable [io + l]->klass, FALSE))) {
-
-                                                               /* CAS - SecurityAction.InheritanceDemand on interface */
-                                                               if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
-                                                                       mono_secman_inheritancedemand_method (cm, im);
-                                                               }
-
-                                                               if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
-                                                                       check_core_clr_override_method (class, cm, im);
-
-                                                               g_assert (io + l <= max_vtsize);
-                                                               vtable [io + l] = cm;
-                                                               TRACE_INTERFACE_VTABLE (printf ("    [FQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
-                                                               TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
-                                                               TRACE_INTERFACE_VTABLE (printf ("\n"));
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                                       g_free (the_cname);
-                                       g_free (qname);
-                                       g_free (fqname);
-                               }
-
-                               // Override methods with the same name
-                               for (l = 0; l < ic->method.count; l++) {
-                                       MonoMethod *im = ic->methods [l];                                               
-                                       MonoClass *k1;
-
-                                       g_assert (io + l <= max_vtsize);
-
-                                       if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
-                                               continue;
-                                               
-                                       for (k1 = class; k1; k1 = k1->parent) {
-                                               for (j = 0; j < k1->method.count; ++j) {
-                                                       MonoMethod *cm = k1->methods [j];
-
-                                                       if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
-                                                           !(cm->flags & METHOD_ATTRIBUTE_PUBLIC))
-                                                               continue;
-                                                       
-                                                       if (!strcmp(cm->name, im->name) && 
-                                                           mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
-
-                                                               /* CAS - SecurityAction.InheritanceDemand on interface */
-                                                               if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
-                                                                       mono_secman_inheritancedemand_method (cm, im);
-                                                               }
-
-                                                               if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
-                                                                       check_core_clr_override_method (class, cm, im);
-
-                                                               g_assert (io + l <= max_vtsize);
-                                                               vtable [io + l] = cm;
-                                                               TRACE_INTERFACE_VTABLE (printf ("    [SQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
-                                                               TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
-                                                               TRACE_INTERFACE_VTABLE (printf ("\n"));
-                                                               break;
-                                                       }
-                                                       
-                                               }
-                                               g_assert (io + l <= max_vtsize);
-                                               if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
-                                                       break;
-                                       }
-                               }
-
-                               if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
-                                       for (l = 0; l < ic->method.count; l++) {
-                                               char *msig;
-                                               MonoMethod *im = ic->methods [l];
-                                               if (im->flags & METHOD_ATTRIBUTE_STATIC)
-                                                               continue;
-                                               g_assert (io + l <= max_vtsize);
-
-                                               /* 
-                                                * If one of our parents already implements this interface
-                                                * we can inherit the implementation.
-                                                */
-                                               if (!(vtable [io + l])) {
-                                                       MonoClass *parent = class->parent;
-                                                       
-                                                       for (; parent; parent = parent->parent) {
-                                                               if (MONO_CLASS_IMPLEMENTS_INTERFACE (parent, ic->interface_id) &&
-                                                                               parent->vtable) {
-                                                                       vtable [io + l] = parent->vtable [mono_class_interface_offset (parent, ic) + l];
-                                                                       TRACE_INTERFACE_VTABLE (printf ("    [INH] Filling slot %d (%d+%d) with method '%s'.'%s':'%s'\n", io + l, io, l, vtable [io + l]->klass->name_space, vtable [io + l]->klass->name, vtable [io + l]->name));
-                                                               }
-                                                       }
-                                               }
-
-                                               if (!(vtable [io + l])) {
-                                                       for (j = 0; j < onum; ++j) {
-                                                               g_print (" at slot %d: %s (%d) overrides %s (%d)\n", io+l, overrides [j*2+1]->name, 
-                                                                        overrides [j*2+1]->slot, overrides [j*2]->name, overrides [j*2]->slot);
-                                                       }
-                                                       msig = mono_signature_get_desc (mono_method_signature (im), FALSE);
-                                                       printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
-                                                               mono_type_get_name (&ic->byval_arg), im->name, msig, class->name_space, class->name);
-                                                       g_free (msig);
-                                                       for (j = 0; j < class->method.count; ++j) {
-                                                               MonoMethod *cm = class->methods [j];
-                                                               msig = mono_signature_get_desc (mono_method_signature (cm), TRUE);
-                                                               
-                                                               printf ("METHOD %s(%s)\n", cm->name, msig);
-                                                               g_free (msig);
-                                                       }
-
-                                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
-
-                                                       if (ifaces)
-                                                               g_ptr_array_free (ifaces, TRUE);
-                                                       if (override_map)
-                                                               g_hash_table_destroy (override_map);
+                               if (im->flags & METHOD_ATTRIBUTE_STATIC)
+                                       continue;
 
-                                                       return;
-                                               }
-                                       }
-                               }
-                       
-                               for (l = 0; l < ic->method.count; l++) {
-                                       MonoMethod *im = vtable [io + l];
-
-                                       if (im) {
-                                               g_assert (io + l <= max_vtsize);
-                                               if (im->slot < 0) {
-                                                       /* FIXME: why do we need this ? */
-                                                       im->slot = io + l;
-                                                       /* g_assert_not_reached (); */
-                                               }
-                                       }
+                               TRACE_INTERFACE_VTABLE (printf ("      [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
+                                               im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
+                               if (vtable [im_slot] == NULL) {
+                                       print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum);
+                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                                       if (override_map)
+                                               g_hash_table_destroy (override_map);
+                                       return;
                                }
                        }
-                       if (ifaces)
-                               g_ptr_array_free (ifaces, TRUE);
-               } 
+               }
        }
 
        TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
-       for (i = 0; i < class->method.count; ++i) {
-               MonoMethod *cm;
-              
-               cm = class->methods [i];
-               
-               /*
-                * Non-virtual method have no place in the vtable.
-                * This also catches static methods (since they are not virtual).
-                */
-               if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
-                       continue;
-               
+       class_iter = NULL;
+       while ((cm = mono_class_get_virtual_methods (class, &class_iter))) {
                /*
                 * If the method is REUSE_SLOT, we must check in the
                 * base class for a method to override.
@@ -3229,13 +3467,12 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
                        int slot = -1;
                        for (k = class->parent; k ; k = k->parent) {
-                               int j;
-                               for (j = 0; j < k->method.count; ++j) {
-                                       MonoMethod *m1 = k->methods [j];
-                                       MonoMethodSignature *cmsig, *m1sig;
+                               gpointer k_iter;
+                               MonoMethod *m1;
 
-                                       if (!(m1->flags & METHOD_ATTRIBUTE_VIRTUAL))
-                                               continue;
+                               k_iter = NULL;
+                               while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
+                                       MonoMethodSignature *cmsig, *m1sig;
 
                                        cmsig = mono_method_signature (cm);
                                        m1sig = mono_method_signature (m1);
@@ -3254,9 +3491,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                }
 
                                                if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
-                                                       check_core_clr_override_method (class, cm, m1);
+                                                       mono_security_core_clr_check_override (class, cm, m1);
 
-                                               slot = k->methods [j]->slot;
+                                               slot = mono_method_get_vtable_slot (m1);
                                                g_assert (cm->slot < max_vtsize);
                                                if (!override_map)
                                                        override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
@@ -3271,6 +3508,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                cm->slot = slot;
                }
 
+               /*Non final newslot methods must be given a non-interface vtable slot*/
+               if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
+                       cm->slot = -1;
+
                if (cm->slot < 0)
                        cm->slot = cur_slot++;
 
@@ -3290,7 +3531,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                        g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
 
                        if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
-                               check_core_clr_override_method (class, vtable [decl->slot], decl);
+                               mono_security_core_clr_check_override (class, vtable [decl->slot], decl);
                }
        }
 
@@ -3309,6 +3550,20 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                g_hash_table_destroy (override_map);
        }
 
+       /* Ensure that all vtable slots are filled with concrete instance methods */
+       if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+               for (i = 0; i < cur_slot; ++i) {
+                       if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
+                               char *type_name = mono_type_get_full_name (class);
+                               char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name));
+                               g_free (type_name);
+                               g_free (method_name);
+                               return;
+                       }
+               }
+       }
+
        if (class->generic_class) {
                MonoClass *gklass = class->generic_class->container_class;
 
@@ -3322,15 +3577,6 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                class->vtable_size = cur_slot;
        }
 
-       /* FIXME: only do this if the class is actually sharable */
-       if (class->valuetype && (class->generic_class || class->generic_container) &&
-                       mono_class_generic_sharing_enabled (class)) {
-               for (i = 0; i < max_vtsize; ++i) {
-                       if (vtable [i] && vtable [i]->wrapper_type == MONO_WRAPPER_NONE)
-                               vtable [i] = mono_marshal_get_static_rgctx_invoke (vtable [i]);
-               }
-       }
-
        /* Try to share the vtable with our parent. */
        if (class->parent && (class->parent->vtable_size == class->vtable_size) && (memcmp (class->parent->vtable, vtable, sizeof (gpointer) * class->vtable_size) == 0)) {
                mono_memory_barrier ();
@@ -3355,7 +3601,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&class->byval_arg), 
                        class->vtable_size, icount); 
 
-               for (i = 0; i < class->vtable_size; ++i) {
+               for (i = 0; i < cur_slot; ++i) {
                        MonoMethod *cm;
               
                        cm = vtable [i];
@@ -3374,19 +3620,56 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                ic = class->interfaces [i];
                                printf ("  slot offset: %03d, method count: %03d, iid: %03d %s\n",  
                                        mono_class_interface_offset (class, ic),
-                                       ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg));
+                                       count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
                        }
 
                        for (k = class->parent; k ; k = k->parent) {
                                for (i = 0; i < k->interface_count; i++) {
                                        ic = k->interfaces [i]; 
-                                       printf ("  slot offset: %03d, method count: %03d, iid: %03d %s\n",  
+                                       printf ("  parent slot offset: %03d, method count: %03d, iid: %03d %s\n",  
                                                mono_class_interface_offset (class, ic),
-                                               ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg));
+                                               count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
                                }
                        }
                }
        }
+
+       VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (class));
+}
+
+/*
+ * mono_method_get_vtable_slot:
+ *
+ *   Returns method->slot, computing it if neccesary.
+ * LOCKING: Acquires the loader lock.
+ */
+int
+mono_method_get_vtable_slot (MonoMethod *method)
+{
+       if (method->slot == -1) {
+               mono_class_setup_vtable (method->klass);
+               g_assert (method->slot != -1);
+       }
+       return method->slot;
+}
+
+/**
+ * mono_method_get_vtable_index:
+ * @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
+ * thunk.
+ */
+int
+mono_method_get_vtable_index (MonoMethod *method)
+{
+       if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+               MonoMethodInflated *imethod = (MonoMethodInflated*)method;
+               if (imethod->declaring->is_generic)
+                       return mono_method_get_vtable_slot (imethod->declaring);
+       }
+       return mono_method_get_vtable_slot (method);
 }
 
 static MonoMethod *default_ghc = NULL;
@@ -3419,16 +3702,6 @@ initialize_object_slots (MonoClass *class)
        }
 }
 
-static GList*
-g_list_prepend_mempool (GList* l, MonoMemPool* mp, gpointer datum)
-{
-       GList* n = mono_mempool_alloc (mp, sizeof (GList));
-       n->next = l;
-       n->prev = NULL;
-       n->data = datum;
-       return n;
-}
-
 typedef struct {
        MonoMethod *array_method;
        char *name;
@@ -3482,6 +3755,7 @@ generic_array_methods (MonoClass *class)
        /*g_print ("array generic methods: %d\n", count_generic);*/
 
        generic_array_method_num = count_generic;
+       g_list_free (list);
        return generic_array_method_num;
 }
 
@@ -3570,22 +3844,6 @@ set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
        mono_class_set_failure (class, error->exception_type, exception_data);
 }
 
-static void
-check_core_clr_inheritance (MonoClass *class)
-{
-       MonoSecurityCoreCLRLevel class_level, parent_level;
-       MonoClass *parent = class->parent;
-
-       if (!parent)
-               return;
-
-       class_level = mono_security_core_clr_class_level (class);
-       parent_level = mono_security_core_clr_class_level (parent);
-
-       if (class_level < parent_level)
-               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
-}
-
 /**
  * mono_class_init:
  * @class: the class to initialize
@@ -3630,13 +3888,23 @@ mono_class_init (MonoClass *class)
 
        class->init_pending = 1;
 
+       if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
+               MonoClass *element_class = class->element_class;
+               if (!element_class->inited) 
+                       mono_class_init (element_class);
+               if (element_class->exception_type != MONO_EXCEPTION_NONE) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       goto fail;
+               }
+       }
+
        /* CAS - SecurityAction.InheritanceDemand */
        if (mono_is_security_manager_active () && class->parent && (class->parent->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) {
                mono_secman_inheritancedemand_class (class, class->parent);
        }
 
        if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
-               check_core_clr_inheritance (class);
+               mono_security_core_clr_check_inheritance (class);
 
        mono_stats.initialized_class_count++;
 
@@ -3649,13 +3917,11 @@ mono_class_init (MonoClass *class)
                class->field = gklass->field;
 
                mono_class_init (gklass);
+               // FIXME: Why is this needed ?
                mono_class_setup_methods (gklass);
-               mono_class_setup_properties (gklass);
 
                if (MONO_CLASS_IS_INTERFACE (class))
                        class->interface_id = mono_get_unique_iid (class);
-
-               g_assert (class->interface_count == gklass->interface_count);
        }
 
        if (class->parent && !class->parent->inited)
@@ -3733,8 +3999,10 @@ mono_class_init (MonoClass *class)
                class->has_cctor = gklass->has_cctor;
 
                mono_class_setup_vtable (gklass);
-               if (gklass->exception_type)
+               if (gklass->exception_type) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
                        goto fail;
+               }
 
                class->vtable_size = gklass->vtable_size;
        } else {
@@ -3756,29 +4024,33 @@ mono_class_init (MonoClass *class)
                if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
                        MonoMethod *cmethod = NULL;
 
-                       if (class->type_token) {
-                               cmethod = find_method_in_metadata (class, "Finalize", 0, METHOD_ATTRIBUTE_VIRTUAL);
-                       } else if (class->parent) {
-                               /* FIXME: Optimize this */
-                               mono_class_setup_vtable (class);
-                               if (class->exception_type || mono_loader_get_last_error ())
-                                       goto fail;
-                               cmethod = class->vtable [finalize_slot];
-                       }
+                       if (class->parent && class->parent->has_finalize) {
+                               class->has_finalize = 1;
+                       } else {
+                               if (class->type_token) {
+                                       cmethod = find_method_in_metadata (class, "Finalize", 0, METHOD_ATTRIBUTE_VIRTUAL);
+                               } else if (class->parent) {
+                                       /* FIXME: Optimize this */
+                                       mono_class_setup_vtable (class);
+                                       if (class->exception_type || mono_loader_get_last_error ())
+                                               goto fail;
+                                       cmethod = class->vtable [finalize_slot];
+                               }
 
-                       if (cmethod) {
-                               /* Check that this is really the finalizer method */
-                               mono_class_setup_vtable (class);
-                               if (class->exception_type || mono_loader_get_last_error ())
+                               if (cmethod) {
+                                       /* Check that this is really the finalizer method */
+                                       mono_class_setup_vtable (class);
+                                       if (class->exception_type || mono_loader_get_last_error ())
                                        goto fail;
 
-                               class->has_finalize = 0;
-                               if (class->parent) { 
-                                       cmethod = class->vtable [finalize_slot];
-                                       if (cmethod->is_inflated)
-                                               cmethod = ((MonoMethodInflated*)cmethod)->declaring;
-                                       if (cmethod != default_finalize) {
-                                               class->has_finalize = 1;
+                                       class->has_finalize = 0;
+                                       if (class->parent) { 
+                                               cmethod = class->vtable [finalize_slot];
+                                               if (cmethod->is_inflated)
+                                                       cmethod = ((MonoMethodInflated*)cmethod)->declaring;
+                                               if (cmethod != default_finalize) {
+                                                       class->has_finalize = 1;
+                                               }
                                        }
                                }
                        }
@@ -3818,12 +4090,20 @@ mono_class_init (MonoClass *class)
                if (class->parent) {
                        /* This will compute class->parent->vtable_size for some classes */
                        mono_class_init (class->parent);
-                       if (class->parent->exception_type || mono_loader_get_last_error ())
+                       if (class->parent->exception_type) {
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                               goto fail;
+                       }
+                       if (mono_loader_get_last_error ())
                                goto fail;
                        if (!class->parent->vtable_size) {
                                /* FIXME: Get rid of this somehow */
                                mono_class_setup_vtable (class->parent);
-                               if (class->parent->exception_type || mono_loader_get_last_error ())
+                               if (class->parent->exception_type) {
+                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                                       goto fail;
+                               }
+                               if (mono_loader_get_last_error ())
                                        goto fail;
                        }
                        setup_interface_offsets (class, class->parent->vtable_size);
@@ -4003,6 +4283,30 @@ mono_class_setup_mono_type (MonoClass *class)
 
 }
 
+/*
+ * COM initialization (using mono_init_com_types) is delayed until needed. 
+ * However when a [ComImport] attribute is present on a type it will trigger
+ * the initialization. This is not a problem unless the BCL being executed 
+ * lacks the types that COM depends on (e.g. Variant on Silverlight).
+ */
+static void
+init_com_from_comimport (MonoClass *class)
+{
+       /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
+       if ((mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)) {
+               /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
+               if (!mono_security_core_clr_determine_platform_image (class->image)) {
+                       /* but it can not be made available for application (i.e. user code) since all COM calls
+                        * are considered native calls. In this case we fail with a TypeLoadException (just like
+                        * Silverlight 2 does */
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       return;
+               }
+       }
+       /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
+       mono_init_com_types ();
+}
+
 /*
  * LOCKING: this assumes the loader lock is held
  */
@@ -4029,7 +4333,7 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
        if (!MONO_CLASS_IS_INTERFACE (class)) {
                /* Imported COM Objects always derive from __ComObject. */
                if (MONO_CLASS_IS_IMPORT (class)) {
-                       mono_init_com_types ();
+                       init_com_from_comimport (class);
                        if (parent == mono_defaults.object_class)
                                parent = mono_defaults.com_object_class;
                }
@@ -4080,7 +4384,7 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
        } else {
                /* initialize com types if COM interfaces are present */
                if (MONO_CLASS_IS_IMPORT (class))
-                       mono_init_com_types ();
+                       init_com_from_comimport (class);
                class->parent = NULL;
        }
 
@@ -4175,18 +4479,31 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
 
        mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), class);
 
+       classes_size += sizeof (MonoClass);
+
        /*
         * Check whether we're a generic type definition.
         */
        class->generic_container = mono_metadata_load_generic_params (image, class->type_token, NULL);
        if (class->generic_container) {
+               class->is_generic = 1;
                class->generic_container->owner.klass = class;
                context = &class->generic_container->context;
        }
 
        if (cols [MONO_TYPEDEF_EXTENDS]) {
-               parent = mono_class_get_full (
-                       image, mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]), context);
+               guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
+
+               if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
+                       /*WARNING: this must satisfy mono_metadata_type_hash*/
+                       class->this_arg.byref = 1;
+                       class->this_arg.data.klass = class;
+                       class->this_arg.type = MONO_TYPE_CLASS;
+                       class->byval_arg.data.klass = class;
+                       class->byval_arg.type = MONO_TYPE_CLASS;
+               }
+               parent = mono_class_get_full (image, parent_token, context);
+
                if (parent == NULL){
                        mono_internal_hash_table_remove (&image->class_cache, GUINT_TO_POINTER (type_token));
                        mono_loader_unlock ();
@@ -4204,9 +4521,19 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
        mono_class_setup_mono_type (class);
 
+       if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
+               class->unicode = 1;
+
+#ifdef PLATFORM_WIN32
+       if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
+               class->unicode = 1;
+#endif
+
+       class->cast_class = class->element_class = class;
+
        if (!class->enumtype) {
                if (!mono_metadata_interfaces_from_typedef_full (
-                           image, type_token, &interfaces, &icount, context)){
+                           image, type_token, &interfaces, &icount, FALSE, context)){
                        mono_loader_unlock ();
                        mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
                        return NULL;
@@ -4214,18 +4541,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
 
                class->interfaces = interfaces;
                class->interface_count = icount;
+               class->interfaces_inited = 1;
        }
 
-       if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
-               class->unicode = 1;
-
-#if PLATFORM_WIN32
-       if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
-               class->unicode = 1;
-#endif
-
-       class->cast_class = class->element_class = class;
-
        /*g_print ("Load class %s\n", name);*/
 
        /*
@@ -4255,19 +4573,20 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
                class->method.count = 0;
 
        /* reserve space to store vector pointer in arrays */
-       if (!strcmp (nspace, "System") && !strcmp (name, "Array")) {
+       if (is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
                class->instance_size += 2 * sizeof (gpointer);
                g_assert (class->field.count == 0);
        }
 
        if (class->enumtype) {
-               class->enum_basetype = mono_class_find_enum_basetype (class);
-               if (!class->enum_basetype) {
+               MonoType *enum_basetype = mono_class_find_enum_basetype (class);
+               if (!enum_basetype) {
                        mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
                        mono_loader_unlock ();
+                       mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
                        return NULL;
                }
-               class->cast_class = class->element_class = mono_class_from_mono_type (class->enum_basetype);
+               class->cast_class = class->element_class = mono_class_from_mono_type (enum_basetype);
        }
 
        /*
@@ -4275,9 +4594,20 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
         * We must do this after the class has been constructed to make certain recursive scenarios
         * work.
         */
-       if (class->generic_container)
-               mono_metadata_load_generic_param_constraints (
-                       image, type_token, class->generic_container);
+       if (class->generic_container && !mono_metadata_load_generic_param_constraints_full (image, type_token, class->generic_container)){
+               char *class_name = g_strdup_printf("%s.%s", class->name_space, class->name);
+               char *error = concat_two_strings_with_zero (class->image, class_name, class->image->assembly_name);
+               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, error);
+               g_free (class_name);
+               mono_loader_unlock ();
+               mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
+               return NULL;
+       }
+
+       if (class->image->assembly_name && !strcmp (class->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
+               if (!strncmp (name, "Vector", 6))
+                       class->simd_type = !strcmp (name + 6, "2d") || !strcmp (name + 6, "2ul") || !strcmp (name + 6, "2l") || !strcmp (name + 6, "4f") || !strcmp (name + 6, "4ui") || !strcmp (name + 6, "4i") || !strcmp (name + 6, "8s") || !strcmp (name + 6, "8us") || !strcmp (name + 6, "16b") || !strcmp (name + 6, "16sb");
+       }
 
        mono_loader_unlock ();
 
@@ -4311,7 +4641,6 @@ MonoClass*
 mono_generic_class_get_class (MonoGenericClass *gclass)
 {
        MonoClass *klass, *gklass;
-       int i;
 
        mono_loader_lock ();
        if (gclass->cached_class) {
@@ -4330,10 +4659,8 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
                 * nesting context should have, but it may also have additional
                 * generic parameters...
                 */
-               MonoType *inflated = mono_class_inflate_generic_type (
-                       &gklass->nested_in->byval_arg, mono_generic_class_get_context (gclass));
-               klass->nested_in = mono_class_from_mono_type (inflated);
-               mono_metadata_free_type (inflated);
+               klass->nested_in = mono_class_inflate_generic_class (gklass->nested_in,
+                                                                                                                        mono_generic_class_get_context (gclass));
        }
 
        klass->name = gklass->name;
@@ -4345,8 +4672,8 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        klass->flags = gklass->flags;
        klass->type_token = gklass->type_token;
        klass->field.count = gklass->field.count;
-       klass->property.count = gklass->property.count;
 
+       klass->is_inflated = 1;
        klass->generic_class = gclass;
 
        klass->this_arg.type = klass->byval_arg.type = MONO_TYPE_GENERICINST;
@@ -4360,35 +4687,21 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        if (mono_class_is_nullable (klass))
                klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
 
-       klass->interface_count = gklass->interface_count;
-       klass->interfaces = g_new0 (MonoClass *, klass->interface_count);
-       for (i = 0; i < klass->interface_count; i++) {
-               MonoType *it = &gklass->interfaces [i]->byval_arg;
-               MonoType *inflated = mono_class_inflate_generic_type (it, mono_generic_class_get_context (gclass));
-               klass->interfaces [i] = mono_class_from_mono_type (inflated);
-               mono_metadata_free_type (inflated);
-       }
-
        /*
         * We're not interested in the nested classes of a generic instance.
         * We use the generic type definition to look for nested classes.
         */
-       klass->nested_classes = NULL;
 
        if (gklass->parent) {
-               MonoType *inflated = mono_class_inflate_generic_type (
-                       &gklass->parent->byval_arg, mono_generic_class_get_context (gclass));
-
-               klass->parent = mono_class_from_mono_type (inflated);
-               mono_metadata_free_type (inflated);
+               klass->parent = mono_class_inflate_generic_class (gklass->parent, mono_generic_class_get_context (gclass));
        }
 
        if (klass->parent)
                mono_class_setup_parent (klass, klass->parent);
 
        if (klass->enumtype) {
-               klass->enum_basetype = gklass->enum_basetype;
                klass->cast_class = gklass->cast_class;
+               klass->element_class = gklass->element_class;
        }
 
        if (gclass->is_dynamic) {
@@ -4409,113 +4722,172 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        }
 
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+
+       inflated_classes ++;
+       inflated_classes_size += sizeof (MonoClass);
        
        mono_loader_unlock ();
 
        return klass;
 }
 
-MonoClass *
-mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
+static MonoClass*
+make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is_mvar, MonoGenericParamInfo *pinfo)
 {
        MonoClass *klass, **ptr;
        int count, pos, i;
 
-       mono_loader_lock ();
-
-       if (param->pklass) {
-               mono_loader_unlock ();
-               return param->pklass;
-       }
-
-       if (!image && param->owner) {
-               if (is_mvar) {
-                       MonoMethod *method = param->owner->owner.method;
-                       image = (method && method->klass) ? method->klass->image : NULL;
-               } else {
-                       MonoClass *klass = param->owner->owner.klass;
-                       // FIXME: 'klass' should not be null
-                       //        But, monodis creates GenericContainers without associating a owner to it
-                       image = klass ? klass->image : NULL;
-               }
-       }
        if (!image)
                /* FIXME: */
                image = mono_defaults.corlib;
 
-       klass = param->pklass = mono_image_alloc0 (image, sizeof (MonoClass));
+       klass = mono_image_alloc0 (image, sizeof (MonoClass));
+       classes_size += sizeof (MonoClass);
 
-       if (param->name)
-               klass->name = param->name;
-       else {
+       if (pinfo) {
+               klass->name = pinfo->name;
+       } else {
+               int n = mono_generic_param_num (param);
                klass->name = mono_image_alloc0 (image, 16);
-               sprintf ((char*)klass->name, is_mvar ? "!!%d" : "!%d", param->num);
+               sprintf ((char*)klass->name, "%d", n);
        }
+
        klass->name_space = "";
        mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
-       
-       for (count = 0, ptr = param->constraints; ptr && *ptr; ptr++, count++)
-               ;
+
+       count = 0;
+       if (pinfo)
+               for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
+                       ;
 
        pos = 0;
-       if ((count > 0) && !MONO_CLASS_IS_INTERFACE (param->constraints [0])) {
-               klass->parent = param->constraints [0];
+       if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
+               klass->parent = pinfo->constraints [0];
                pos++;
-       } else if (param->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
+       } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
                klass->parent = mono_class_from_name (mono_defaults.corlib, "System", "ValueType");
        else
                klass->parent = mono_defaults.object_class;
 
+
        if (count - pos > 0) {
                klass->interface_count = count - pos;
                klass->interfaces = mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos));
                for (i = pos; i < count; i++)
-                       klass->interfaces [i - pos] = param->constraints [i];
+                       klass->interfaces [i - pos] = pinfo->constraints [i];
        }
 
-       if (!image)
-               image = mono_defaults.corlib;
-
        klass->image = image;
 
        klass->inited = TRUE;
        klass->cast_class = klass->element_class = klass;
-       klass->enum_basetype = &klass->element_class->byval_arg;
        klass->flags = TYPE_ATTRIBUTE_PUBLIC;
 
        klass->this_arg.type = klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
        klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param;
        klass->this_arg.byref = TRUE;
 
-       if (param->owner) {
-               guint32 owner;
-               guint32 cols [MONO_GENERICPARAM_SIZE];
-               MonoTableInfo *tdef  = &image->tables [MONO_TABLE_GENERICPARAM];
-               i = 0;
-
-               if (is_mvar && param->owner->owner.method)
-                        i = mono_metadata_get_generic_param_row (image, param->owner->owner.method->token, &owner);
-               else if (!is_mvar && param->owner->owner.klass)
-                        i = mono_metadata_get_generic_param_row (image, param->owner->owner.klass->type_token, &owner);
-
-               if (i) {
-                       mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
-                       do {
-                               if (cols [MONO_GENERICPARAM_NUMBER] == param->num) {
-                                       klass->sizes.generic_param_token = i | MONO_TOKEN_GENERIC_PARAM;
-                                       break;
-                               }
-                               if (++i > tdef->rows)
-                                       break;
-                               mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
-                       } while (cols [MONO_GENERICPARAM_OWNER] == owner);
+       /* FIXME: shouldn't this be ->type_token? */
+       klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
+
+       mono_class_setup_supertypes (klass);
+
+       return klass;
+}
+
+#define FAST_CACHE_SIZE 1024
+static MonoClass *var_cache_fast [FAST_CACHE_SIZE];
+static MonoClass *mvar_cache_fast [FAST_CACHE_SIZE];
+static GHashTable *var_cache_slow;
+static GHashTable *mvar_cache_slow;
+
+static MonoClass *
+get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
+{
+       int n = mono_generic_param_num (param);
+       GHashTable *ht;
+
+       if (n < FAST_CACHE_SIZE)
+               return (is_mvar ? mvar_cache_fast : var_cache_fast) [n];
+       ht = is_mvar ? mvar_cache_slow : var_cache_slow;
+       return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
+}
+
+static void
+set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
+{
+       int n = mono_generic_param_num (param);
+       GHashTable *ht;
+
+       if (n < FAST_CACHE_SIZE) {
+               (is_mvar ? mvar_cache_fast : var_cache_fast) [n] = klass;
+               return;
+       }
+       ht = is_mvar ? mvar_cache_slow : var_cache_slow;
+       if (!ht) {
+               ht = g_hash_table_new (NULL, NULL);
+               if (is_mvar)
+                       mvar_cache_slow = ht;
+               else
+                       var_cache_slow = ht;
+       }
+
+       g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
+}
+
+/*
+ * LOCKING: Acquires the loader lock.
+ */
+MonoClass *
+mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
+{
+       MonoGenericContainer *container = mono_generic_param_owner (param);
+       MonoGenericParamInfo *pinfo;
+       MonoClass *klass;
+
+       mono_loader_lock ();
+
+       if (container) {
+               pinfo = mono_generic_param_info (param);
+               if (pinfo->pklass) {
+                       mono_loader_unlock ();
+                       return pinfo->pklass;
+               }
+       } else {
+               pinfo = NULL;
+               image = NULL;
+
+               klass = get_anon_gparam_class (param, is_mvar);
+               if (klass) {
+                       mono_loader_unlock ();
+                       return klass;
                }
        }
 
-       mono_class_setup_supertypes (klass);
+       if (!image && container) {
+               if (is_mvar) {
+                       MonoMethod *method = container->owner.method;
+                       image = (method && method->klass) ? method->klass->image : NULL;
+               } else {
+                       MonoClass *klass = container->owner.klass;
+                       // FIXME: 'klass' should not be null
+                       //        But, monodis creates GenericContainers without associating a owner to it
+                       image = klass ? klass->image : NULL;
+               }
+       }
+
+       klass = make_generic_param_class (param, image, is_mvar, pinfo);
+
+       mono_memory_barrier ();
+
+       if (container)
+               pinfo->pklass = klass;
+       else
+               set_anon_gparam_class (param, is_mvar, klass);
 
        mono_loader_unlock ();
 
+       /* FIXME: Should this go inside 'make_generic_param_klass'? */
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
 
        return klass;
@@ -4543,6 +4915,8 @@ mono_ptr_class_get (MonoType *type)
        }
        result = mono_image_alloc0 (image, sizeof (MonoClass));
 
+       classes_size += sizeof (MonoClass);
+
        result->parent = NULL; /* no parent for PTR types */
        result->name_space = el_class->name_space;
        name = g_strdup_printf ("%s*", el_class->name);
@@ -4557,11 +4931,10 @@ mono_ptr_class_get (MonoType *type)
        /* Can pointers get boxed? */
        result->instance_size = sizeof (gpointer);
        result->cast_class = result->element_class = el_class;
-       result->enum_basetype = &result->element_class->byval_arg;
        result->blittable = TRUE;
 
        result->this_arg.type = result->byval_arg.type = MONO_TYPE_PTR;
-       result->this_arg.data.type = result->byval_arg.data.type = result->enum_basetype;
+       result->this_arg.data.type = result->byval_arg.data.type = &result->element_class->byval_arg;
        result->this_arg.byref = TRUE;
 
        mono_class_setup_supertypes (result);
@@ -4611,7 +4984,6 @@ mono_fnptr_class_get (MonoMethodSignature *sig)
        result->this_arg.type = result->byval_arg.type = MONO_TYPE_FNPTR;
        result->this_arg.data.method = result->byval_arg.data.method = sig;
        result->this_arg.byref = TRUE;
-       result->enum_basetype = &result->element_class->byval_arg;
        result->blittable = TRUE;
 
        mono_class_setup_supertypes (result);
@@ -4699,11 +5071,14 @@ mono_class_from_mono_type (MonoType *type)
 static MonoType *
 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate)
 {
+       MonoError error;
        MonoType *t = mono_type_create_from_typespec (image, type_spec);
        if (!t)
                return NULL;
        if (context && (context->class_inst || context->method_inst)) {
-               MonoType *inflated = inflate_generic_type (NULL, t, context);
+               MonoType *inflated = inflate_generic_type (NULL, t, context, &error);
+               g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+
                if (inflated) {
                        t = inflated;
                        *did_inflate = TRUE;
@@ -4747,7 +5122,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
        MonoImage *image;
        MonoClass *class;
        MonoClass *parent = NULL;
-       GSList *list, *rootlist;
+       GSList *list, *rootlist = NULL;
        int nsize;
        char *name;
        gboolean corlib_type = FALSE;
@@ -4760,17 +5135,34 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        image = eclass->image;
 
-       mono_loader_lock ();
+       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 (), 
+                * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
+                */
+               EnterCriticalSection (&image->szarray_cache_lock);
+               if (!image->szarray_cache)
+                       image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
+               class = g_hash_table_lookup (image->szarray_cache, eclass);
+               LeaveCriticalSection (&image->szarray_cache_lock);
+               if (class)
+                       return class;
 
-       if (!image->array_cache)
-               image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
+               mono_loader_lock ();
+       } else {
+               mono_loader_lock ();
 
-       if ((rootlist = list = g_hash_table_lookup (image->array_cache, eclass))) {
-               for (; list; list = list->next) {
-                       class = list->data;
-                       if ((class->rank == rank) && (class->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
-                               mono_loader_unlock ();
-                               return class;
+               if (!image->array_cache)
+                       image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
+
+               if ((rootlist = list = g_hash_table_lookup (image->array_cache, eclass))) {
+                       for (; list; list = list->next) {
+                               class = list->data;
+                               if ((class->rank == rank) && (class->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
+                                       mono_loader_unlock ();
+                                       return class;
+                               }
                        }
                }
        }
@@ -4804,6 +5196,8 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
 
+       classes_size += sizeof (MonoClass);
+
        class->type_token = 0;
        /* all arrays are marked serializable and sealed, bug #42779 */
        class->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED |
@@ -4811,7 +5205,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
        class->parent = parent;
        class->instance_size = mono_class_instance_size (class->parent);
 
-       if (eclass->enumtype && !eclass->enum_basetype) {
+       if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
                if (!eclass->reflection_info || eclass->wastypebuilder) {
                        g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
                        g_assert (eclass->reflection_info && !eclass->wastypebuilder);
@@ -4823,22 +5217,13 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        mono_class_setup_supertypes (class);
 
-       if (mono_defaults.generic_ilist_class && !bounded && rank == 1) {
-               MonoType *args [1];
-
-               /* generic IList, ICollection, IEnumerable */
-               class->interface_count = 1;
-               class->interfaces = mono_image_alloc0 (image, sizeof (MonoClass*) * class->interface_count);
-
-               args [0] = &eclass->byval_arg;
-               class->interfaces [0] = mono_class_bind_generic_parameters (
-                       mono_defaults.generic_ilist_class, 1, args, FALSE);
-       }
-
        if (eclass->generic_class)
                mono_class_init (eclass);
        if (!eclass->size_inited)
                mono_class_setup_fields (eclass);
+       if (eclass->exception_type) /*FIXME we fail the array type, but we have to let other fields be set.*/
+               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+
        class->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
 
        class->rank = rank;
@@ -4869,8 +5254,21 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        class->generic_container = eclass->generic_container;
 
-       list = g_slist_append (rootlist, class);
-       g_hash_table_insert (image->array_cache, eclass, list);
+       if (rank == 1 && !bounded) {
+               MonoClass *prev_class;
+
+               EnterCriticalSection (&image->szarray_cache_lock);
+               prev_class = g_hash_table_lookup (image->szarray_cache, eclass);
+               if (prev_class)
+                       /* Someone got in before us */
+                       class = prev_class;
+               else
+                       g_hash_table_insert (image->szarray_cache, eclass, class);
+               LeaveCriticalSection (&image->szarray_cache_lock);
+       } else {
+               list = g_slist_append (rootlist, class);
+               g_hash_table_insert (image->array_cache, eclass, list);
+       }
 
        mono_loader_unlock ();
 
@@ -4979,6 +5377,8 @@ static MonoClassField *
 mono_class_get_field_idx (MonoClass *class, int idx)
 {
        mono_class_setup_fields_locking (class);
+       if (class->exception_type)
+               return NULL;
 
        while (class) {
                if (class->image->uncompressed_metadata) {
@@ -4986,11 +5386,12 @@ mono_class_get_field_idx (MonoClass *class, int idx)
                         * class->field.first points to the FieldPtr table, while idx points into the
                         * Field table, so we have to do a search.
                         */
+                       /*FIXME this is broken for types with multiple fields with the same name.*/
                        const char *name = mono_metadata_string_heap (class->image, mono_metadata_decode_row_col (&class->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
                        int i;
 
                        for (i = 0; i < class->field.count; ++i)
-                               if (class->fields [i].name == name)
+                               if (mono_field_get_name (&class->fields [i]) == name)
                                        return &class->fields [i];
                        g_assert_not_reached ();
                } else {                        
@@ -5035,14 +5436,45 @@ mono_class_get_field (MonoClass *class, guint32 field_token)
  */
 MonoClassField *
 mono_class_get_field_from_name (MonoClass *klass, const char *name)
+{
+       return mono_class_get_field_from_name_full (klass, name, NULL);
+}
+
+/**
+ * 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.
+ *
+ * Search the class @klass and it's parents for a field with the name @name and type @type.
+ *
+ * If @klass is an inflated generic type, the type comparison is done with the equivalent field
+ * of its generic type definition.
+ *
+ * Returns: the MonoClassField pointer of the named field or NULL
+ */
+MonoClassField *
+mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
 {
        int i;
 
        mono_class_setup_fields_locking (klass);
+       if (klass->exception_type)
+               return NULL;
+
        while (klass) {
                for (i = 0; i < klass->field.count; ++i) {
-                       if (strcmp (name, klass->fields [i].name) == 0)
-                               return &klass->fields [i];
+                       MonoClassField *field = &klass->fields [i];
+
+                       if (strcmp (name, mono_field_get_name (field)) != 0)
+                               continue;
+
+                       if (type) {
+                               MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
+                               if (!mono_metadata_type_equal_full (type, field_type, TRUE))
+                                       continue;
+                       }
+                       return field;
                }
                klass = klass->parent;
        }
@@ -5065,6 +5497,9 @@ mono_class_get_field_token (MonoClassField *field)
        int i;
 
        mono_class_setup_fields_locking (klass);
+       if (klass->exception_type)
+               return 0;
+
        while (klass) {
                for (i = 0; i < klass->field.count; ++i) {
                        if (&klass->fields [i] == field) {
@@ -5082,6 +5517,16 @@ mono_class_get_field_token (MonoClassField *field)
        return 0;
 }
 
+static int
+mono_field_get_index (MonoClassField *field)
+{
+       int index = field - field->parent->fields;
+
+       g_assert (index >= 0 && index < field->parent->field.count);
+
+       return index;
+}
+
 /*
  * mono_class_get_field_default_value:
  *
@@ -5092,21 +5537,33 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ
 {
        guint32 cindex;
        guint32 constant_cols [MONO_CONSTANT_SIZE];
+       int field_index;
+       MonoClass *klass = field->parent;
 
        g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
 
-       if (!field->data) {
+       if (!klass->ext || !klass->ext->field_def_values) {
+               mono_loader_lock ();
+               mono_class_alloc_ext (klass);
+               if (!klass->ext->field_def_values)
+                       klass->ext->field_def_values = mono_image_alloc0 (klass->image, sizeof (MonoFieldDefaultValue) * klass->field.count);
+               mono_loader_unlock ();
+       }
+
+       field_index = mono_field_get_index (field);
+               
+       if (!klass->ext->field_def_values [field_index].data) {
                cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
                g_assert (cindex);
                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);
-               field->def_type = constant_cols [MONO_CONSTANT_TYPE];
-               field->data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
+               klass->ext->field_def_values [field_index].def_type = constant_cols [MONO_CONSTANT_TYPE];
+               klass->ext->field_def_values [field_index].data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
        }
 
-       *def_type = field->def_type;
-       return field->data;
+       *def_type = klass->ext->field_def_values [field_index].def_type;
+       return klass->ext->field_def_values [field_index].data;
 }
 
 guint32
@@ -5116,9 +5573,11 @@ mono_class_get_event_token (MonoEvent *event)
        int i;
 
        while (klass) {
-               for (i = 0; i < klass->event.count; ++i) {
-                       if (&klass->events [i] == event)
-                               return mono_metadata_make_token (MONO_TABLE_EVENT, klass->event.first + i + 1);
+               if (klass->ext) {
+                       for (i = 0; i < klass->ext->event.count; ++i) {
+                               if (&klass->ext->events [i] == event)
+                                       return mono_metadata_make_token (MONO_TABLE_EVENT, klass->ext->event.first + i + 1);
+                       }
                }
                klass = klass->parent;
        }
@@ -5151,8 +5610,8 @@ mono_class_get_property_token (MonoProperty *prop)
                int i = 0;
                gpointer iter = NULL;
                while ((p = mono_class_get_properties (klass, &iter))) {
-                       if (&klass->properties [i] == prop)
-                               return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->property.first + i + 1);
+                       if (&klass->ext->properties [i] == prop)
+                               return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->ext->property.first + i + 1);
                        
                        i ++;
                }
@@ -5332,9 +5791,8 @@ mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *co
        if (!type) {
                char *name = mono_class_name_from_token (image, type_token);
                char *assembly = mono_assembly_name_from_token (image, type_token);
-               if (inflated)
-                       mono_metadata_free_type (type);
                mono_loader_set_error_type_load (name, assembly);
+               return NULL;
        }
 
        if (inflated) {
@@ -5366,7 +5824,7 @@ mono_class_get (MonoImage *image, guint32 type_token)
  *
  *  Initializes the class name cache stored in image->name_cache.
  *
- * LOCKING: Acquires the loader lock.
+ * LOCKING: Acquires the corresponding image lock.
  */
 void
 mono_image_init_name_cache (MonoImage *image)
@@ -5378,12 +5836,17 @@ mono_image_init_name_cache (MonoImage *image)
        guint32 i, visib, nspace_index;
        GHashTable *name_cache2, *nspace_table;
 
-       mono_loader_lock ();
+       mono_image_lock (image);
+
+       if (image->name_cache) {
+               mono_image_unlock (image);
+               return;
+       }
 
        image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
 
        if (image->dynamic) {
-               mono_loader_unlock ();
+               mono_image_unlock (image);
                return;
        }
 
@@ -5437,18 +5900,19 @@ mono_image_init_name_cache (MonoImage *image)
        }
 
        g_hash_table_destroy (name_cache2);
-
-       mono_loader_unlock ();
+       mono_image_unlock (image);
 }
 
+/*FIXME Only dynamic assemblies should allow this operation.*/
 void
 mono_image_add_to_name_cache (MonoImage *image, const char *nspace, 
                                                          const char *name, guint32 index)
 {
        GHashTable *nspace_table;
        GHashTable *name_cache;
+       guint32 old_index;
 
-       mono_loader_lock ();
+       mono_image_lock (image);
 
        if (!image->name_cache)
                mono_image_init_name_cache (image);
@@ -5458,9 +5922,13 @@ mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
                nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
                g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
        }
+
+       if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
+               g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
+
        g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
 
-       mono_loader_unlock ();
+       mono_image_unlock (image);
 }
 
 typedef struct {
@@ -5474,7 +5942,7 @@ find_nocase (gpointer key, gpointer value, gpointer user_data)
        char *name = (char*)key;
        FindUserData *data = (FindUserData*)user_data;
 
-       if (!data->value && (g_strcasecmp (name, (char*)data->key) == 0))
+       if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
                data->value = value;
 }
 
@@ -5501,7 +5969,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
                guint32 token = 0;
                FindUserData user_data;
 
-               mono_loader_lock ();
+               mono_image_lock (image);
 
                if (!image->name_cache)
                        mono_image_init_name_cache (image);
@@ -5522,7 +5990,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
                                token = GPOINTER_TO_UINT (user_data.value);
                }
 
-               mono_loader_unlock ();
+               mono_image_unlock (image);
                
                if (token)
                        return mono_class_get (image, MONO_TOKEN_TYPE_DEF | token);
@@ -5543,7 +6011,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
                        continue;
                n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
                nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
-               if (g_strcasecmp (n, name) == 0 && g_strcasecmp (nspace, name_space) == 0)
+               if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
                        return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
        }
        return NULL;
@@ -5645,7 +6113,7 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
                }
        }
 
-       mono_loader_lock ();
+       mono_image_lock (image);
 
        if (!image->name_cache)
                mono_image_init_name_cache (image);
@@ -5655,7 +6123,7 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
        if (nspace_table)
                token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
 
-       mono_loader_unlock ();
+       mono_image_unlock (image);
 
        if (!token && image->dynamic && image->modules) {
                /* Search modules as well */
@@ -5696,20 +6164,17 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
                                return return_nested_in (class, nested);
                        return class;
                } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
-                       MonoAssembly **references = image->references;
                        guint32 assembly_idx;
 
                        assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
 
-                       if (!references [assembly_idx - 1])
-                               mono_assembly_load_reference (image, assembly_idx - 1);
-                       g_assert (references == image->references);
-                       g_assert (references [assembly_idx - 1]);
-                       if (references [assembly_idx - 1] == (gpointer)-1)
+                       mono_assembly_load_reference (image, assembly_idx - 1);
+                       g_assert (image->references [assembly_idx - 1]);
+                       if (image->references [assembly_idx - 1] == (gpointer)-1)
                                return NULL;                    
                        else
                                /* FIXME: Cycle detection */
-                               return mono_class_from_name (references [assembly_idx - 1]->image, name_space, name);
+                               return mono_class_from_name (image->references [assembly_idx - 1]->image, name_space, name);
                } else {
                        g_error ("not yet implemented");
                }
@@ -5766,7 +6231,7 @@ mono_class_has_variant_generic_params (MonoClass *klass)
        container = klass->generic_class->container_class->generic_container;
 
        for (i = 0; i < container->type_argc; ++i)
-               if (container->type_params [i].flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
+               if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
                        return TRUE;
 
        return FALSE;
@@ -5844,9 +6309,9 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                                                 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
                                                 */
                                                if (param1_class != param2_class) {
-                                                       if ((container->type_params [i].flags & MONO_GEN_PARAM_VARIANT) && mono_class_is_assignable_from (param1_class, param2_class))
+                                                       if ((mono_generic_container_get_param_info (container, i)->flags & MONO_GEN_PARAM_VARIANT) && mono_class_is_assignable_from (param1_class, param2_class))
                                                                ;
-                                                       else if (((container->type_params [i].flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
+                                                       else if (((mono_generic_container_get_param_info (container, i)->flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
                                                                ;
                                                        else {
                                                                match = FALSE;
@@ -5897,6 +6362,67 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
        return mono_class_has_parent (oklass, klass);
 }      
 
+/*Check if @candidate implements the interface @target*/
+static gboolean
+mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
+{
+       int i;
+
+       do {
+               if (candidate == target)
+                       return TRUE;
+
+               /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
+               if (candidate->image->dynamic && !candidate->wastypebuilder) {
+                       MonoReflectionTypeBuilder *tb = candidate->reflection_info;
+                       int j;
+                       if (tb->interfaces) {
+                               for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
+                                       MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
+                                       MonoClass *iface_class = mono_class_from_mono_type (iface->type);
+                                       if (iface_class == target || mono_class_implement_interface_slow (target, iface_class))
+                                               return TRUE;
+                               }
+                       }
+               } else {
+                       /*setup_interfaces don't mono_class_init anything*/
+                       mono_class_setup_interfaces (candidate);
+                       for (i = 0; i < candidate->interface_count; ++i) {
+                               if (candidate->interfaces [i] == target || mono_class_implement_interface_slow (target, candidate->interfaces [i]))
+                                       return TRUE;
+                       }
+               }
+               candidate = candidate->parent;
+       } while (candidate);
+
+       return FALSE;
+}
+
+/*
+ * Check if @oklass can be assigned to @klass.
+ * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
+ */
+gboolean
+mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
+{
+       if (candidate == target)
+               return TRUE;
+       if (target == mono_defaults.object_class)
+               return TRUE;
+
+       /*setup_supertypes don't mono_class_init anything */
+       mono_class_setup_supertypes (candidate);
+       mono_class_setup_supertypes (target);
+
+       if (mono_class_has_parent (candidate, target))
+               return TRUE;
+
+       /*If target is not an interface there is no need to check them.*/
+       if (!MONO_CLASS_IS_INTERFACE (target))
+                       return FALSE;
+       return mono_class_implement_interface_slow (target, candidate);
+}
+
 /**
  * mono_class_get_cctor:
  * @klass: A MonoClass pointer
@@ -5914,6 +6440,9 @@ mono_class_get_cctor (MonoClass *klass)
        if (mono_class_get_cached_class_info (klass, &cached_info))
                return mono_get_method (klass->image, cached_info.cctor_token, klass);
 
+       if (klass->generic_class && !klass->methods)
+               return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
+
        return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
 }
 
@@ -5958,7 +6487,7 @@ mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
        if (method)
                return (method == caller) ? FALSE : TRUE;
        else
-               return TRUE;
+               return FALSE;
 }
 
 /**
@@ -6004,7 +6533,7 @@ handle_enum:
                return 8;
        case MONO_TYPE_VALUETYPE:
                if (type->data.klass->enumtype) {
-                       type = type->data.klass->enum_basetype;
+                       type = mono_class_enum_basetype (type->data.klass);
                        klass = klass->element_class;
                        goto handle_enum;
                }
@@ -6012,6 +6541,10 @@ handle_enum:
        case MONO_TYPE_GENERICINST:
                type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
+
+       case MONO_TYPE_VOID:
+               return 0;
+               
        default:
                g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
        }
@@ -6210,7 +6743,11 @@ mono_class_is_enum (MonoClass *klass)
 MonoType*
 mono_class_enum_basetype (MonoClass *klass)
 {
-       return klass->enum_basetype;
+       if (klass->element_class == klass)
+               /* SRE */
+               return NULL;
+       else
+               return &klass->element_class->byval_arg;
 }
 
 /**
@@ -6364,7 +6901,7 @@ mono_class_num_properties (MonoClass *klass)
 {
        mono_class_setup_properties (klass);
 
-       return klass->property.count;
+       return klass->ext->property.count;
 }
 
 /**
@@ -6378,7 +6915,7 @@ mono_class_num_events (MonoClass *klass)
 {
        mono_class_setup_events (klass);
 
-       return klass->event.count;
+       return klass->ext->event.count;
 }
 
 /**
@@ -6401,6 +6938,8 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter)
                return NULL;
        if (!*iter) {
                mono_class_setup_fields_locking (klass);
+               if (klass->exception_type)
+                       return NULL;
                /* start from the first */
                if (klass->field.count) {
                        return *iter = &klass->fields [0];
@@ -6457,6 +6996,71 @@ mono_class_get_methods (MonoClass* klass, gpointer *iter)
        return NULL;
 }
 
+/*
+ * mono_class_get_virtual_methods:
+ *
+ *   Iterate over the virtual methods of KLASS.
+ *
+ * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
+ */
+static MonoMethod*
+mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
+{
+       MonoMethod** method;
+       if (!iter)
+               return NULL;
+       if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass) || mono_debug_using_mono_debugger ()) {
+               if (!*iter) {
+                       mono_class_setup_methods (klass);
+                       /* start from the first */
+                       method = &klass->methods [0];
+               } else {
+                       method = *iter;
+                       method++;
+               }
+               while (method < &klass->methods [klass->method.count]) {
+                       if (((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
+                               break;
+                       method ++;
+               }
+               if (method < &klass->methods [klass->method.count]) {
+                       *iter = method;
+                       return *method;
+               } else {
+                       return NULL;
+               }
+       } else {
+               /* Search directly in metadata to avoid calling setup_methods () */
+               MonoMethod *res = NULL;
+               int i, start_index;
+
+               if (!*iter) {
+                       start_index = 0;
+               } else {
+                       start_index = GPOINTER_TO_UINT (*iter);
+               }
+
+               for (i = start_index; i < klass->method.count; ++i) {
+                       guint32 cols [MONO_METHOD_SIZE];
+
+                       /* class->method.first points into the methodptr table */
+                       mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
+
+                       if (cols [MONO_METHOD_FLAGS] & METHOD_ATTRIBUTE_VIRTUAL)
+                               break;
+               }
+
+               if (i < klass->method.count) {
+                       res = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
+                       /* Add 1 here so the if (*iter) check fails */
+                       *iter = GUINT_TO_POINTER (i + 1);
+                       return res;
+               } else {
+                       return NULL;
+               }
+       }
+}
+
 /**
  * mono_class_get_properties:
  * @klass: the MonoClass to act on
@@ -6480,8 +7084,8 @@ mono_class_get_properties (MonoClass* klass, gpointer *iter)
        if (!*iter) {
                mono_class_setup_properties (klass);
                /* start from the first */
-               if (klass->property.count) {
-                       return *iter = &klass->properties [0];
+               if (klass->ext->property.count) {
+                       return *iter = &klass->ext->properties [0];
                } else {
                        /* no fields */
                        return NULL;
@@ -6489,7 +7093,7 @@ mono_class_get_properties (MonoClass* klass, gpointer *iter)
        }
        property = *iter;
        property++;
-       if (property < &klass->properties [klass->property.count]) {
+       if (property < &klass->ext->properties [klass->ext->property.count]) {
                return *iter = property;
        }
        return NULL;
@@ -6518,8 +7122,8 @@ mono_class_get_events (MonoClass* klass, gpointer *iter)
        if (!*iter) {
                mono_class_setup_events (klass);
                /* start from the first */
-               if (klass->event.count) {
-                       return *iter = &klass->events [0];
+               if (klass->ext->event.count) {
+                       return *iter = &klass->ext->events [0];
                } else {
                        /* no fields */
                        return NULL;
@@ -6527,7 +7131,7 @@ mono_class_get_events (MonoClass* klass, gpointer *iter)
        }
        event = *iter;
        event++;
-       if (event < &klass->events [klass->event.count]) {
+       if (event < &klass->ext->events [klass->ext->event.count]) {
                return *iter = event;
        }
        return NULL;
@@ -6551,9 +7155,11 @@ mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
        MonoClass** iface;
        if (!iter)
                return NULL;
-       if (!klass->inited)
-               mono_class_init (klass);
        if (!*iter) {
+               if (!klass->inited)
+                       mono_class_init (klass);
+               if (!klass->interfaces_inited)
+                       mono_class_setup_interfaces (klass);
                /* start from the first */
                if (klass->interface_count) {
                        *iter = &klass->interfaces [0];
@@ -6606,7 +7212,8 @@ mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
                                guint32 cols [MONO_NESTED_CLASS_SIZE];
                                mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
                                nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
-                               klass->nested_classes = g_list_prepend_mempool (klass->nested_classes, klass->image->mempool, nclass);
+                               mono_class_alloc_ext (klass);
+                               klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, nclass);
 
                                i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
                        }
@@ -6618,9 +7225,9 @@ mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
 
        if (!*iter) {
                /* start from the first */
-               if (klass->nested_classes) {
-                       *iter = klass->nested_classes;
-                       return klass->nested_classes->data;
+               if (klass->ext && klass->ext->nested_classes) {
+                       *iter = klass->ext->nested_classes;
+                       return klass->ext->nested_classes->data;
                } else {
                        /* no nested types */
                        return NULL;
@@ -6660,7 +7267,7 @@ mono_field_get_type (MonoClassField *field)
 }
 
 /**
- * mono_field_get_type:
+ * mono_field_get_parent:
  * @field: the MonoClassField to act on
  *
  * Returns: MonoClass where the field was defined.
@@ -6698,6 +7305,35 @@ mono_field_get_offset (MonoClassField *field)
        return field->offset;
 }
 
+static const char *
+mono_field_get_rva (MonoClassField *field)
+{
+       guint32 rva;
+       int field_index;
+       MonoClass *klass = field->parent;
+
+       g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
+
+       if (!klass->ext || !klass->ext->field_def_values) {
+               mono_loader_lock ();
+               mono_class_alloc_ext (klass);
+               if (!klass->ext->field_def_values)
+                       klass->ext->field_def_values = mono_image_alloc0 (klass->image, sizeof (MonoFieldDefaultValue) * klass->field.count);
+               mono_loader_unlock ();
+       }
+
+       field_index = mono_field_get_index (field);
+               
+       if (!klass->ext->field_def_values [field_index].data && !klass->image->dynamic) {
+               mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
+               if (!rva)
+                       g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
+               klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
+       }
+
+       return klass->ext->field_def_values [field_index].data;
+}
+
 /**
  * mono_field_get_data;
  * @field: the MonoClassField to act on
@@ -6706,9 +7342,17 @@ mono_field_get_offset (MonoClassField *field)
  * data if it has an RVA flag.
  */
 const char *
-mono_field_get_data  (MonoClassField *field)
+mono_field_get_data (MonoClassField *field)
 {
-  return field->data;
+       if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
+               MonoTypeEnum def_type;
+
+               return mono_class_get_field_default_value (field, &def_type);
+       } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
+               return mono_field_get_rva (field);
+       } else {
+               return NULL;
+       }
 }
 
 /**
@@ -6908,7 +7552,14 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p
 
        mono_class_init (klass);
 
-       if (klass->methods || klass->generic_class) {
+       if (klass->generic_class && !klass->methods) {
+               res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
+               if (res)
+                       res = mono_class_inflate_generic_method_full (res, klass, mono_class_get_context (klass));
+               return res;
+       }
+
+       if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
                mono_class_setup_methods (klass);
                for (i = 0; i < klass->method.count; ++i) {
                        MonoMethod *method = klass->methods [i];
@@ -6949,7 +7600,7 @@ mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
        mono_loader_lock ();
        klass->exception_type = ex_type;
        if (ex_data)
-               mono_property_hash_insert (klass->image->property_hash, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
+               mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
        mono_loader_unlock ();
 
        return TRUE;
@@ -6965,12 +7616,7 @@ mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
 gpointer
 mono_class_get_exception_data (MonoClass *klass)
 {
-       gpointer res;
-
-       mono_loader_lock ();
-       res = mono_property_hash_lookup (klass->image->property_hash, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
-       mono_loader_unlock ();
-       return res;
+       return mono_image_property_lookup (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
 }
 
 /**
@@ -6981,6 +7627,16 @@ mono_class_get_exception_data (MonoClass *klass)
 void
 mono_classes_init (void)
 {
+       mono_counters_register ("Inflated methods size",
+                                                       MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
+       mono_counters_register ("Inflated classes",
+                                                       MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes);
+       mono_counters_register ("Inflated classes size",
+                                                       MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
+       mono_counters_register ("MonoClass size",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
+       mono_counters_register ("MonoClassExt size",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
 }
 
 /**
@@ -7105,7 +7761,7 @@ mono_class_get_generic_type_definition (MonoClass *klass)
  * 
  * Visibility checks ignoring generic instantiations.  
  */
-static gboolean
+gboolean
 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
 {
        int i;
@@ -7155,6 +7811,14 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
                return TRUE;
        if (!accessed || !accessing)
                return FALSE;
+
+       /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
+        * anywhere so untrusted friends are not safe to access platform's code internals */
+       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
+               if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
+                       return FALSE;
+       }
+
        mono_assembly_load_friends (accessed);
        for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
                MonoAssemblyName *friend = tmp->data;
@@ -7196,10 +7860,25 @@ can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
        int i;
        for (i = 0; i < ginst->type_argc; ++i) {
                MonoType *type = ginst->type_argv[i];
-               if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
-                       continue;
-               if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
-                       return FALSE;
+               switch (type->type) {
+               case MONO_TYPE_SZARRAY:
+                       if (!can_access_type (access_klass, type->data.klass))
+                               return FALSE;
+                       break;
+               case MONO_TYPE_ARRAY:
+                       if (!can_access_type (access_klass, type->data.array->eklass))
+                               return FALSE;
+                       break;
+               case MONO_TYPE_PTR:
+                       if (!can_access_type (access_klass, mono_class_from_mono_type (type->data.type)))
+                               return FALSE;
+                       break;
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_VALUETYPE:
+               case MONO_TYPE_GENERICINST:
+                       if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
+                               return FALSE;
+               }
        }
        return TRUE;
 }
@@ -7207,7 +7886,18 @@ can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
 static gboolean
 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
 {
-       int access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+       int access_level;
+
+       if (access_klass->element_class && !access_klass->enumtype)
+               access_klass = access_klass->element_class;
+
+       if (member_klass->element_class && !member_klass->enumtype)
+               member_klass = member_klass->element_class;
+
+       access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+
+       if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
+               return TRUE;
 
        if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
                return FALSE;
@@ -7218,6 +7908,10 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass)
        if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
                return FALSE;
 
+       /*Non nested type with nested visibility. We just fail it.*/
+       if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
+               return FALSE;
+
        switch (access_level) {
        case TYPE_ATTRIBUTE_NOT_PUBLIC:
                return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
@@ -7339,13 +8033,13 @@ mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
 }
 
 /*
- * mono_method_can_access_method_with_context:
+ * mono_method_can_access_method_full:
  * @method: The caller method 
  * @called: The called method 
- * @context_klass:TThe static type on stack of the owner @called object used
+ * @context_klass: The static type on stack of the owner @called object used
  * 
  * This function must be used with instance calls, as they have more strict family accessibility.
- * It can be used with static mehthod, but context_klass should be NULL.
+ * It can be used with static methods, but context_klass should be NULL.
  * 
  * Returns: TRUE if caller have proper visibility and acessibility to @called
  */
@@ -7374,7 +8068,7 @@ mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, Mono
        if (called->is_inflated) {
                MonoMethodInflated * infl = (MonoMethodInflated*)called;
                if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
-               return FALSE;
+                       return FALSE;
        }
                
        return TRUE;
@@ -7382,7 +8076,7 @@ mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, Mono
 
 
 /*
- * mono_method_can_access_method_with_context:
+ * mono_method_can_access_field_full:
  * @method: The caller method 
  * @field: The accessed field
  * @context_klass: The static type on stack of the owner @field object used
@@ -7493,6 +8187,14 @@ mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
        return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
 }
 
+static gboolean gshared_supported;
+
+void
+mono_set_generic_sharing_supported (gboolean supported)
+{
+       gshared_supported = supported;
+}
+
 /*
  * mono_class_generic_sharing_enabled:
  * @class: a class
@@ -7506,19 +8208,13 @@ mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
 gboolean
 mono_class_generic_sharing_enabled (MonoClass *class)
 {
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__ppc__) || defined(__powerpc__)
-       static gboolean supported = TRUE;
-#else
-       /* Not supported by the JIT backends */
-       static gboolean supported = FALSE;
-#endif
        static int generic_sharing = MONO_GENERIC_SHARING_NONE;
        static gboolean inited = FALSE;
 
        if (!inited) {
                const char *option;
 
-               if (supported)
+               if (gshared_supported)
                        generic_sharing = MONO_GENERIC_SHARING_ALL;
                else
                        generic_sharing = MONO_GENERIC_SHARING_NONE;
@@ -7536,7 +8232,7 @@ mono_class_generic_sharing_enabled (MonoClass *class)
                                g_warning ("Unknown generic sharing option `%s'.", option);
                }
 
-               if (!supported)
+               if (!gshared_supported)
                        generic_sharing = MONO_GENERIC_SHARING_NONE;
 
                inited = TRUE;
@@ -7559,3 +8255,85 @@ mono_class_generic_sharing_enabled (MonoClass *class)
                g_assert_not_reached ();
        }
 }
+
+/*
+ * mono_class_setup_interface_id:
+ *
+ * Initializes MonoClass::interface_id if required.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
+void
+mono_class_setup_interface_id (MonoClass *class)
+{
+       mono_loader_lock ();
+       if (MONO_CLASS_IS_INTERFACE (class) && !class->interface_id)
+               class->interface_id = mono_get_unique_iid (class);
+       mono_loader_unlock ();
+}
+
+/*
+ * mono_class_alloc_ext:
+ *
+ *   Allocate klass->ext if not already done.
+ * LOCKING: Assumes the loader lock is held.
+ */
+void
+mono_class_alloc_ext (MonoClass *klass)
+{
+       if (!klass->ext) {
+               if (klass->generic_class) {
+                       klass->ext = g_new0 (MonoClassExt, 1);
+               } else {
+                       klass->ext = mono_image_alloc0 (klass->image, sizeof (MonoClassExt));
+               }
+               class_ext_size += sizeof (MonoClassExt);
+       }
+}
+
+/*
+ * mono_class_setup_interfaces:
+ *
+ *   Initialize class->interfaces/interfaces_count.
+ * LOCKING: Acquires the loader lock.
+ */
+void
+mono_class_setup_interfaces (MonoClass *klass)
+{
+       int i;
+
+       if (klass->interfaces_inited)
+               return;
+
+       mono_loader_lock ();
+
+       if (klass->interfaces_inited) {
+               mono_loader_unlock ();
+               return;
+       }
+
+       if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY && mono_defaults.generic_ilist_class) {
+               MonoType *args [1];
+
+               /* generic IList, ICollection, IEnumerable */
+               klass->interface_count = 1;
+               klass->interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * klass->interface_count);
+
+               args [0] = &klass->element_class->byval_arg;
+               klass->interfaces [0] = mono_class_bind_generic_parameters (
+                       mono_defaults.generic_ilist_class, 1, args, FALSE);
+       } else if (klass->generic_class) {
+               MonoClass *gklass = klass->generic_class->container_class;
+
+               klass->interface_count = gklass->interface_count;
+               klass->interfaces = g_new0 (MonoClass *, klass->interface_count);
+               for (i = 0; i < klass->interface_count; i++)
+                       klass->interfaces [i] = mono_class_inflate_generic_class (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class));
+       }
+
+       mono_memory_barrier ();
+
+       klass->interfaces_inited = TRUE;
+
+       mono_loader_unlock ();
+}