Tue Sep 23 15:24:03 CEST 2008 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / class.c
index bd1593253d74fed61d45254dedb04b4db66963eb..bcd4a7a5ae3840b2df50e9b152723e856784688d 100644 (file)
 #include <mono/metadata/security-core-clr.h>
 #include <mono/metadata/attrdefs.h>
 #include <mono/metadata/gc-internal.h>
+#include <mono/metadata/verify-internals.h>
 #include <mono/utils/mono-counters.h>
 
 MonoStats mono_stats;
 
 gboolean mono_print_vtable = FALSE;
 
+/*
+ * Controls whenever mono_class_init () constructs a generic vtable. This is TRUE by
+ * default to avoid breaking embedding apps, but set to FALSE by the runtime executable
+ * startup code.
+ */
+gboolean mono_setup_vtable_in_class_init = TRUE;
+
 /* Function supplied by the runtime to find classes by name using information from the AOT file */
 static MonoGetClassFromName get_class_from_name = NULL;
 
 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token);
 static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
+static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
+static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
+static int generic_array_methods (MonoClass *class);
+static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos);
 
 void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
 void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
@@ -100,7 +112,7 @@ 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->inited) {
+               if (enclosing->nested_classes_inited) {
                        /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
                        for (tmp = enclosing->nested_classes; tmp; tmp = tmp->next) {
                                res = tmp->data;
@@ -121,7 +133,7 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
                                i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
                        }
                }
-               g_warning ("TypeRef ResolutionScope not yet handled (%d)", idx);
+               g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
                return NULL;
        }
        case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
@@ -148,29 +160,48 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
        return mono_class_from_name (image->references [idx - 1]->image, nspace, name);
 }
 
+
+static void *
+mono_mempool_dup (MonoMemPool *mp, void *data, guint size)
+{
+       void *res = mono_mempool_alloc (mp, size);
+       memcpy (res, data, size);
+       return res;
+}
+       
 /* Copy everything mono_metadata_free_array free. */
 MonoArrayType *
-mono_dup_array_type (MonoArrayType *a)
+mono_dup_array_type (MonoMemPool *mp, MonoArrayType *a)
 {
-       a = g_memdup (a, sizeof (MonoArrayType));
-       if (a->sizes)
-               a->sizes = g_memdup (a->sizes, a->numsizes * sizeof (int));
-       if (a->lobounds)
-               a->lobounds = g_memdup (a->lobounds, a->numlobounds * sizeof (int));
+       if (mp) {
+               mono_loader_lock ();
+               a = mono_mempool_dup (mp, a, sizeof (MonoArrayType));
+               if (a->sizes)
+                       a->sizes = mono_mempool_dup (mp, a->sizes, a->numsizes * sizeof (int));
+               if (a->lobounds)
+                       a->lobounds = mono_mempool_dup (mp, a->lobounds, a->numlobounds * sizeof (int));
+               mono_loader_unlock ();          
+       } else {
+               a = g_memdup (a, sizeof (MonoArrayType));
+               if (a->sizes)
+                       a->sizes = g_memdup (a->sizes, a->numsizes * sizeof (int));
+               if (a->lobounds)
+                       a->lobounds = g_memdup (a->lobounds, a->numlobounds * sizeof (int));
+       }
        return a;
 }
 
 /* Copy everything mono_metadata_free_method_signature free. */
 MonoMethodSignature*
-mono_metadata_signature_deep_dup (MonoMethodSignature *sig)
+mono_metadata_signature_deep_dup (MonoMemPool *mp, MonoMethodSignature *sig)
 {
        int i;
        
-       sig = mono_metadata_signature_dup (sig);
+       sig = mono_metadata_signature_dup_full (mp, sig);
        
-       sig->ret = mono_metadata_type_dup (NULL, sig->ret);
+       sig->ret = mono_metadata_type_dup (mp, sig->ret);
        for (i = 0; i < sig->param_count; ++i)
-               sig->params [i] = mono_metadata_type_dup (NULL, sig->params [i]);
+               sig->params [i] = mono_metadata_type_dup (mp, sig->params [i]);
        
        return sig;
 }
@@ -448,7 +479,7 @@ mono_class_is_open_constructed_type (MonoType *t)
 }
 
 static MonoType*
-inflate_generic_type (MonoType *type, MonoGenericContext *context)
+inflate_generic_type (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context)
 {
        switch (type->type) {
        case MONO_TYPE_MVAR: {
@@ -465,7 +496,7 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context)
                 * 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 (NULL, inst->type_argv [num]);
+               nt = mono_metadata_type_dup (mempool, inst->type_argv [num]);
                nt->byref = type->byref;
                nt->attrs = type->attrs;
                return nt;
@@ -478,27 +509,27 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context)
                        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 (NULL, inst->type_argv [num]);
+               nt = mono_metadata_type_dup (mempool, 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 (&eclass->byval_arg, context);
+               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
                if (!inflated)
                        return NULL;
-               nt = mono_metadata_type_dup (NULL, type);
+               nt = mono_metadata_type_dup (mempool, 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 (&eclass->byval_arg, context);
+               MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
                if (!inflated)
                        return NULL;
-               nt = mono_metadata_type_dup (NULL, type);
+               nt = mono_metadata_type_dup (mempool, 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);
@@ -518,7 +549,7 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context)
                if (gclass == type->data.generic_class)
                        return NULL;
 
-               nt = mono_metadata_type_dup (NULL, type);
+               nt = mono_metadata_type_dup (mempool, type);
                nt->data.generic_class = gclass;
                return nt;
        }
@@ -540,7 +571,7 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context)
 
                gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
 
-               nt = mono_metadata_type_dup (NULL, type);
+               nt = mono_metadata_type_dup (mempool, type);
                nt->type = MONO_TYPE_GENERICINST;
                nt->data.generic_class = gclass;
                return nt;
@@ -564,27 +595,48 @@ mono_class_get_context (MonoClass *class)
 }
 
 /*
- * mono_class_inflate_generic_type:
+ * mono_class_inflate_generic_type_with_mempool:
+ * @mempool: a mempool
  * @type: a type
  * @context: a generics context
  *
- * Instantiate the generic type @type, using the generics context @context.
- *
- * Returns: the instantiated type. The returned MonoType is allocated on the heap and is 
- * owned by the caller.
+ * 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.
  */
 MonoType*
-mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
+mono_class_inflate_generic_type_with_mempool (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context)
 {
-       MonoType *inflated = inflate_generic_type (type, context);
+       MonoType *inflated = NULL; 
+
+       if (context)
+               inflated = inflate_generic_type (mempool, type, context);
 
        if (!inflated)
-               return mono_metadata_type_dup (NULL, type);
+               return mono_metadata_type_dup (mempool, type);
 
        mono_stats.inflated_type_count++;
        return inflated;
 }
 
+/*
+ * mono_class_inflate_generic_type:
+ * @type: a type
+ * @context: a generics context
+ *
+ * If @type is a generic type and @context is not NULL, instantiate it using the 
+ * generics context @context.
+ *
+ * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
+ * on the heap and is owned by the caller.
+ */
+MonoType*
+mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
+{
+       return mono_class_inflate_generic_type_with_mempool (NULL, type, context);
+}
+
+
 static MonoGenericContext
 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with)
 {
@@ -633,6 +685,7 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
        MonoMethodInflated *iresult, *cached;
        MonoMethodSignature *sig;
        MonoGenericContext tmp_context;
+       gboolean is_mb_open = FALSE;
 
        /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
        while (method->is_inflated) {
@@ -648,16 +701,58 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
                method = imethod->declaring;
        }
 
-       if (!method->generic_container && !method->klass->generic_container)
+       if (!method->is_generic && !method->klass->generic_container)
                return method;
 
-       mono_stats.inflated_method_count++;
+       /*
+        * The reason for this hack is to fix the behavior of inflating generic methods that come from a MethodBuilder.
+        * What happens is that instantiating a generic MethodBuilder with its own arguments should create a diferent object.
+        * This is opposite to the way non-SRE MethodInfos behave.
+        * 
+        * This happens, for example, when we want to emit a recursive generic method. Given the following C# code:
+        * 
+        * void Example<T> () {
+        *    Example<T> ();
+        * }
+        *  
+        * In Example, the method token must be encoded as: "void Example<!!0>()"
+        * 
+        * The reference to the first generic argument, "!!0", must be explicit otherwise it won't be inflated
+        * properly. To get that we need to inflate the MethodBuilder with its own arguments.
+        * 
+        * On the other hand, inflating a non-SRE generic method with its own arguments should
+        * return itself. For example:
+        * 
+        * MethodInfo m = ... //m is a generic method definition
+        * MethodInfo res = m.MakeGenericMethod (m.GetGenericArguments ());
+        * res == m
+        *
+        * To allow such scenarios we must allow inflation of MethodBuilder to happen in a diferent way than
+        * what happens with regular methods.
+        * 
+        * There is one last touch to this madness, once a TypeBuilder is finished, IOW CreateType() is called,
+        * everything should behave like a regular type or method.
+        * 
+        */
+       is_mb_open = method->is_generic &&
+               method->klass->image->dynamic && !method->klass->wastypebuilder && /* that is a MethodBuilder from an unfinished TypeBuilder */
+               context->method_inst == mono_method_get_generic_container (method)->context.method_inst; /* and it's been instantiated with its own arguments.  */
+
        iresult = g_new0 (MonoMethodInflated, 1);
        iresult->context = *context;
        iresult->declaring = method;
+       iresult->is_mb_open = is_mb_open;
 
-       if (!context->method_inst && method->generic_container)
-               iresult->context.method_inst = method->generic_container->context.method_inst;
+       if (!context->method_inst && method->is_generic)
+               iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
+
+       if (!context->class_inst) {
+               g_assert (!iresult->declaring->klass->generic_class);
+               if (iresult->declaring->klass->generic_container)
+                       iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
+               else if (iresult->declaring->klass->generic_class)
+                       iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
+       }
 
        mono_loader_lock ();
        cached = mono_method_inflated_lookup (iresult, FALSE);
@@ -667,6 +762,8 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
                return (MonoMethod*)cached;
        }
 
+       mono_stats.inflated_method_count++;
+
        sig = mono_method_signature (method);
        if (sig->pinvoke) {
                memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
@@ -676,13 +773,19 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
        }
 
        result = (MonoMethod *) iresult;
-       result->is_inflated = 1;
+       result->is_inflated = TRUE;
+       result->is_generic = FALSE;
        result->signature = NULL;
 
-       if (context->method_inst)
-               result->generic_container = NULL;
+       if (!context->method_inst) {
+               /* Set the generic_container of the result to the generic_container of method */
+               MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
 
-       /* Due to the memcpy above, !context->method_inst => result->generic_container == method->generic_container */
+               if (generic_container) {
+                       result->is_generic = 1;
+                       mono_method_set_generic_container (result, generic_container);
+               }
+       }
 
        if (!klass_hint || !klass_hint->generic_class ||
            klass_hint->generic_class->container_class != method->klass ||
@@ -693,7 +796,7 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
                result->klass = klass_hint;
 
        if (!result->klass) {
-               MonoType *inflated = inflate_generic_type (&method->klass->byval_arg, context);
+               MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context);
                result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
                if (inflated)
                        mono_metadata_free_type (inflated);
@@ -725,6 +828,45 @@ mono_method_get_context (MonoMethod *method)
        return &imethod->context;
 }
 
+/*
+ * mono_method_get_generic_container:
+ *
+ *   Returns the generic container of METHOD, which should be a generic method definition.
+ * Returns NULL if METHOD is not a generic method definition.
+ * LOCKING: Acquires the loader lock.
+ */
+MonoGenericContainer*
+mono_method_get_generic_container (MonoMethod *method)
+{
+       MonoGenericContainer *container;
+
+       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 ();
+       g_assert (container);
+
+       return container;
+}
+
+/*
+ * mono_method_set_generic_container:
+ *
+ *   Sets the generic container of METHOD to CONTAINER.
+ * LOCKING: Acquires the loader lock.
+ */
+void
+mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
+{
+       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_class_find_enum_basetype:
  * @class: The enum class
@@ -769,6 +911,7 @@ mono_class_find_enum_basetype (MonoClass *class)
                if (!ftype)
                        return NULL;
                if (class->generic_class) {
+                       //FIXME do we leak here?
                        ftype = mono_class_inflate_generic_type (ftype, mono_class_get_context (class));
                        ftype->attrs = cols [MONO_FIELD_FLAGS];
                }
@@ -804,6 +947,16 @@ mono_class_setup_fields (MonoClass *class)
        if (class->size_inited)
                return;
 
+       if (class->generic_class && class->generic_class->container_class->image->dynamic && !class->generic_class->container_class->wastypebuilder) {
+               /*
+                * This happens when a generic instance of an unfinished generic typebuilder
+                * is used as an element type for creating an array type. We can't initialize
+                * the fields of this class using the fields of gklass, since gklass is not
+                * finished yet, fields could be added to it later.
+                */
+               return;
+       }
+
        if (class->generic_class) {
                MonoClass *gklass = class->generic_class->container_class;
                mono_class_setup_fields (gklass);
@@ -854,7 +1007,7 @@ mono_class_setup_fields (MonoClass *class)
        /* Prevent infinite loops if the class references itself */
        class->size_inited = 1;
 
-       class->fields = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassField) * top);
+       class->fields = mono_image_alloc0 (class->image, sizeof (MonoClassField) * top);
 
        if (class->generic_container) {
                container = class->generic_container;
@@ -882,7 +1035,8 @@ mono_class_setup_fields (MonoClass *class)
                        ifield->generic_type = gfield->type;
                        field->name = gfield->name;
                        field->generic_info = ifield;
-                       field->type = mono_class_inflate_generic_type (gfield->type, mono_class_get_context (class));
+                       /*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;
                        if (mono_field_is_deleted (field))
                                continue;
@@ -931,6 +1085,8 @@ mono_class_setup_fields (MonoClass *class)
                                blittable = FALSE;
                        } else {
                                MonoClass *field_class = mono_class_from_mono_type (field->type);
+                               if (field_class)
+                                       mono_class_setup_fields (field_class);
                                if (!field_class || !field_class->blittable)
                                        blittable = FALSE;
                        }
@@ -1239,18 +1395,15 @@ mono_class_layout_fields (MonoClass *class)
                break;
        }
 
-#if NO_UNALIGNED_ACCESS
        if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
                /*
-                * For small structs, set min_align to at least the struct size, since the
-                * JIT memset/memcpy code assumes this and generates unaligned accesses
-                * otherwise. See #78990 for a testcase.
-                * FIXME: Fix the memset/memcpy code instead.
+                * For small structs, set min_align to at least the struct size to improve
+                * performance, and since the JIT memset/memcpy code assumes this and generates 
+                * unaligned accesses otherwise. See #78990 for a testcase.
                 */
                if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
                        class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject));
        }
-#endif
 
        class->size_inited = 1;
 
@@ -1276,6 +1429,27 @@ mono_class_layout_fields (MonoClass *class)
        }
 }
 
+static MonoMethod*
+create_array_method (MonoClass *class, const char *name, MonoMethodSignature *sig)
+{
+       MonoMethod *method;
+
+       method = (MonoMethod *) mono_image_alloc0 (class->image, sizeof (MonoMethodPInvoke));
+       method->klass = class;
+       method->flags = METHOD_ATTRIBUTE_PUBLIC;
+       method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
+       method->signature = sig;
+       method->name = name;
+       method->slot = -1;
+       /* .ctor */
+       if (name [0] == '.') {
+               method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
+       } else {
+               method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
+       }
+       return method;
+}
+
 /*
  * mono_class_setup_methods:
  * @class: a class
@@ -1316,13 +1490,78 @@ mono_class_setup_methods (MonoClass *class)
                        methods [i] = mono_class_inflate_generic_method_full (
                                gklass->methods [i], class, mono_class_get_context (class));
                }
+       } else if (class->rank) {
+               MonoMethod *amethod;
+               MonoMethodSignature *sig;
+               int count_generic = 0, first_generic = 0;
+               int method_num = 0;
+
+               class->method.count = 3 + (class->rank > 1? 2: 1);
+
+               if (class->interface_count) {
+                       count_generic = generic_array_methods (class);
+                       first_generic = class->method.count;
+                       class->method.count += class->interface_count * count_generic;
+               }
+
+               methods = mono_image_alloc0 (class->image, sizeof (MonoMethod*) * class->method.count);
+
+               sig = mono_metadata_signature_alloc (class->image, class->rank);
+               sig->ret = &mono_defaults.void_class->byval_arg;
+               sig->pinvoke = TRUE;
+               sig->hasthis = TRUE;
+               for (i = 0; i < class->rank; ++i)
+                       sig->params [i] = &mono_defaults.int32_class->byval_arg;
+
+               amethod = create_array_method (class, ".ctor", sig);
+               methods [method_num++] = amethod;
+               if (class->rank > 1) {
+                       sig = mono_metadata_signature_alloc (class->image, class->rank * 2);
+                       sig->ret = &mono_defaults.void_class->byval_arg;
+                       sig->pinvoke = TRUE;
+                       sig->hasthis = TRUE;
+                       for (i = 0; i < class->rank * 2; ++i)
+                               sig->params [i] = &mono_defaults.int32_class->byval_arg;
+
+                       amethod = create_array_method (class, ".ctor", sig);
+                       methods [method_num++] = amethod;
+               }
+               /* element Get (idx11, [idx2, ...]) */
+               sig = mono_metadata_signature_alloc (class->image, class->rank);
+               sig->ret = &class->element_class->byval_arg;
+               sig->pinvoke = TRUE;
+               sig->hasthis = TRUE;
+               for (i = 0; i < class->rank; ++i)
+                       sig->params [i] = &mono_defaults.int32_class->byval_arg;
+               amethod = create_array_method (class, "Get", sig);
+               methods [method_num++] = amethod;
+               /* element& Address (idx11, [idx2, ...]) */
+               sig = mono_metadata_signature_alloc (class->image, class->rank);
+               sig->ret = &class->element_class->this_arg;
+               sig->pinvoke = TRUE;
+               sig->hasthis = TRUE;
+               for (i = 0; i < class->rank; ++i)
+                       sig->params [i] = &mono_defaults.int32_class->byval_arg;
+               amethod = create_array_method (class, "Address", sig);
+               methods [method_num++] = amethod;
+               /* void Set (idx11, [idx2, ...], element) */
+               sig = mono_metadata_signature_alloc (class->image, class->rank + 1);
+               sig->ret = &mono_defaults.void_class->byval_arg;
+               sig->pinvoke = TRUE;
+               sig->hasthis = TRUE;
+               for (i = 0; i < class->rank; ++i)
+                       sig->params [i] = &mono_defaults.int32_class->byval_arg;
+               sig->params [i] = &class->element_class->byval_arg;
+               amethod = create_array_method (class, "Set", sig);
+               methods [method_num++] = amethod;
+
+               for (i = 0; i < class->interface_count; i++)
+                       setup_generic_array_ifaces (class, class->interfaces [i], methods, first_generic + i * count_generic);
        } else {
-               methods = mono_mempool_alloc (class->image->mempool, sizeof (MonoMethod*) * class->method.count);
+               methods = mono_image_alloc (class->image, sizeof (MonoMethod*) * class->method.count);
                for (i = 0; i < class->method.count; ++i) {
                        int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1);
                        methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class);
-                       if (class->valuetype && methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !(methods [i]->flags & MONO_METHOD_ATTR_STATIC))
-                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
                }
        }
 
@@ -1330,7 +1569,9 @@ mono_class_setup_methods (MonoClass *class)
                for (i = 0; i < class->method.count; ++i)
                        methods [i]->slot = i;
 
-       /* Leave this assignment as the last op in this function */
+       /* Needed because of the double-checking locking pattern */
+       mono_memory_barrier ();
+
        class->methods = methods;
 
        if (mono_debugger_class_loaded_methods_func)
@@ -1339,6 +1580,39 @@ mono_class_setup_methods (MonoClass *class)
        mono_loader_unlock ();
 }
 
+/*
+ * mono_class_get_method_by_index:
+ *
+ *   Returns class->methods [index], initializing class->methods if neccesary.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
+MonoMethod*
+mono_class_get_method_by_index (MonoClass *class, int index)
+{
+       /* Avoid calling setup_methods () if possible */
+       if (class->generic_class && !class->methods) {
+               MonoClass *gklass = class->generic_class->container_class;
+               MonoMethod *m;
+
+               m = mono_class_inflate_generic_method_full (
+                               gklass->methods [index], class, mono_class_get_context (class));
+               /*
+                * If setup_methods () is called later for this class, no duplicates are created,
+                * since inflate_generic_method guarantees that only one instance of a method
+                * is created for each context.
+                */
+               /*
+               mono_class_setup_methods (class);
+               g_assert (m == class->methods [index]);
+               */
+               return m;
+       } else {
+               mono_class_setup_methods (class);
+               g_assert (index >= 0 && index < class->method.count);
+               return class->methods [index];
+       }
+}      
 
 static void
 mono_class_setup_properties (MonoClass *class)
@@ -1390,7 +1664,7 @@ mono_class_setup_properties (MonoClass *class)
                if (class->property.count)
                        mono_class_setup_methods (class);
 
-               properties = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoProperty) * class->property.count);
+               properties = mono_image_alloc0 (class->image, sizeof (MonoProperty) * class->property.count);
                for (i = class->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;
@@ -1422,6 +1696,8 @@ mono_class_setup_properties (MonoClass *class)
                        }
                }
        }
+       /*Flush any pending writes as we do double checked locking on class->properties */
+       mono_memory_barrier ();
 
        /* Leave this assignment as the last op in the function */
        class->properties = properties;
@@ -1500,7 +1776,7 @@ mono_class_setup_events (MonoClass *class)
        if (class->event.count)
                mono_class_setup_methods (class);
 
-       events = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoEvent) * class->event.count);
+       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];
 
@@ -1551,6 +1827,9 @@ mono_class_setup_events (MonoClass *class)
                        }
                }
        }
+       /*Flush any pending writes as we do double checked locking on class->properties */
+       mono_memory_barrier ();
+
        /* Leave this assignment as the last op in the function */
        class->events = events;
 
@@ -1664,73 +1943,6 @@ mono_class_get_implemented_interfaces (MonoClass *klass)
        return res;
 }
 
-typedef struct _IOffsetInfo IOffsetInfo;
-struct _IOffsetInfo {
-       IOffsetInfo *next;
-       int size;
-       int next_free;
-       int data [MONO_ZERO_LEN_ARRAY];
-};
-
-static IOffsetInfo *cached_offset_info = NULL;
-static int next_offset_info_size = 128;
-
-static int*
-cache_interface_offsets (int max_iid, int *data)
-{
-       IOffsetInfo *cached_info;
-       int *cached;
-       int new_size;
-       for (cached_info = cached_offset_info; cached_info; cached_info = cached_info->next) {
-               cached = cached_info->data;
-               while (cached < cached_info->data + cached_info->size && *cached) {
-                       if (*cached == max_iid) {
-                               int i, matched = TRUE;
-                               cached++;
-                               for (i = 0; i < max_iid; ++i) {
-                                       if (cached [i] != data [i]) {
-                                               matched = FALSE;
-                                               break;
-                                       }
-                               }
-                               if (matched)
-                                       return cached;
-                               cached += max_iid;
-                       } else {
-                               cached += *cached + 1;
-                       }
-               }
-       }
-       /* find a free slot */
-       for (cached_info = cached_offset_info; cached_info; cached_info = cached_info->next) {
-               if (cached_info->size - cached_info->next_free >= max_iid + 1) {
-                       cached = &cached_info->data [cached_info->next_free];
-                       *cached++ = max_iid;
-                       memcpy (cached, data, max_iid * sizeof (int));
-                       cached_info->next_free += max_iid + 1;
-                       return cached;
-               }
-       }
-       /* allocate a new chunk */
-       if (max_iid + 1 < next_offset_info_size) {
-               new_size = next_offset_info_size;
-               if (next_offset_info_size < 4096)
-                       next_offset_info_size += next_offset_info_size >> 2;
-       } else {
-               new_size = max_iid + 1;
-       }
-       cached_info = g_malloc0 (sizeof (IOffsetInfo) + sizeof (int) * new_size);
-       cached_info->size = new_size;
-       /*g_print ("allocated %d offset entries at %p (total: %d)\n", new_size, cached_info->data, offset_info_total_size);*/
-       cached = &cached_info->data [0];
-       *cached++ = max_iid;
-       memcpy (cached, data, max_iid * sizeof (int));
-       cached_info->next_free += max_iid + 1;
-       cached_info->next = cached_offset_info;
-       cached_offset_info = cached_info;
-       return cached;
-}
-
 static int
 compare_interface_ids (const void *p_key, const void *p_element) {
        const MonoClass *key = p_key;
@@ -1854,6 +2066,8 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume
                        "System.Collections.Generic", "IEnumerator`1");
        }
 
+       mono_class_init (eclass);
+
        /*
         * Arrays in 2.0 need to implement a number of generic interfaces
         * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
@@ -2007,8 +2221,8 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
 
        /* 
         * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
-        * implicit innterfaces have the property that they are assigned the same slot in the vtables
-        * for compatible interfaces
+        * implicit interfaces have the property that they are assigned the same slot in the
+        * vtables for compatible interfaces
         */
        array_interfaces = get_implicit_generic_array_interfaces (class, &num_array_interfaces, &is_enumerator);
 
@@ -2134,18 +2348,27 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
                        interface_offsets_count ++;
                }
        }
-       class->interface_offsets_count = interface_offsets_count;
-       class->interfaces_packed = mono_mempool_alloc (class->image->mempool, sizeof (MonoClass*) * interface_offsets_count);
-       class->interface_offsets_packed = mono_mempool_alloc (class->image->mempool, sizeof (int) * interface_offsets_count);
-       class->interface_bitmap = mono_mempool_alloc0 (class->image->mempool, (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0));
-       for (interface_offsets_count = 0, i = 0; i <= max_iid; i++) {
-               if (interface_offsets_full [i] != -1) {
-                       class->interface_bitmap [i >> 3] |= (1 << (i & 7));
-                       class->interfaces_packed [interface_offsets_count] = interfaces_full [i];
-                       class->interface_offsets_packed [interface_offsets_count] = interface_offsets_full [i];
-                       /*if (num_array_interfaces)
-                               g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&class->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/
-                       interface_offsets_count ++;
+
+       /*
+        * We might get called twice: once from mono_class_init () then once from 
+        * mono_class_setup_vtable ().
+        */
+       if (class->interfaces_packed) {
+               g_assert (class->interface_offsets_count == interface_offsets_count);
+       } else {
+               class->interface_offsets_count = interface_offsets_count;
+               class->interfaces_packed = mono_image_alloc (class->image, sizeof (MonoClass*) * interface_offsets_count);
+               class->interface_offsets_packed = mono_image_alloc (class->image, sizeof (guint16) * interface_offsets_count);
+               class->interface_bitmap = mono_image_alloc0 (class->image, (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0));
+               for (interface_offsets_count = 0, i = 0; i <= max_iid; i++) {
+                       if (interface_offsets_full [i] != -1) {
+                               class->interface_bitmap [i >> 3] |= (1 << (i & 7));
+                               class->interfaces_packed [interface_offsets_count] = interfaces_full [i];
+                               class->interface_offsets_packed [interface_offsets_count] = interface_offsets_full [i];
+                               /*if (num_array_interfaces)
+                                 g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&class->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/
+                               interface_offsets_count ++;
+                       }
                }
        }
        
@@ -2171,7 +2394,19 @@ mono_class_setup_interface_offsets (MonoClass *class)
 
        mono_loader_unlock ();
 }
-
+/*
+ * mono_class_setup_vtable:
+ *
+ *   Creates the generic vtable of CLASS.
+ * Initializes the following fields in MonoClass:
+ * - vtable
+ * - vtable_size
+ * Plus all the fields initialized by setup_interface_offsets ().
+ * If there is an error during vtable construction, class->exception_type is set.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
 void
 mono_class_setup_vtable (MonoClass *class)
 {
@@ -2185,6 +2420,7 @@ 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_CLASS_IS_INTERFACE (class))
@@ -2251,10 +2487,8 @@ check_core_clr_override_method (MonoClass *class, MonoMethod *override, MonoMeth
        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) {
-               class->exception_type = MONO_EXCEPTION_TYPE_LOAD;
-               class->exception_data = NULL;
-       }
+       if (override_level != base_level && base_level == MONO_SECURITY_CORE_CLR_CRITICAL)
+               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
 }
 
 
@@ -2657,6 +2891,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                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 there is an explicit implementation, just use it right away,
                                // otherwise look for a matching method
                                if (override_im == NULL) {
@@ -2721,6 +2958,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                        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) {
@@ -3075,15 +3315,22 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                mono_class_init (gklass);
 
                class->vtable_size = MAX (gklass->vtable_size, cur_slot);
-       } else
+       } else {
+               /* Check that the vtable_size value computed in mono_class_init () is correct */
+               if (class->vtable_size)
+                       g_assert (cur_slot == class->vtable_size);
                class->vtable_size = cur_slot;
+       }
 
        /* 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 ();
                class->vtable = class->parent->vtable;
        } else {
-               class->vtable = mono_mempool_alloc0 (class->image->mempool, sizeof (gpointer) * class->vtable_size);
-               memcpy (class->vtable, vtable,  sizeof (gpointer) * class->vtable_size);
+               MonoMethod **tmp = mono_image_alloc0 (class->image, sizeof (gpointer) * class->vtable_size);
+               memcpy (tmp, vtable,  sizeof (gpointer) * class->vtable_size);
+               mono_memory_barrier ();
+               class->vtable = tmp;
        }
 
        DEBUG_INTERFACE_VTABLE (print_vtable_full (class, class->vtable, class->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
@@ -3217,7 +3464,7 @@ generic_array_methods (MonoClass *class)
                        g_assert_not_reached ();
                }
 
-               name = mono_mempool_alloc (mono_defaults.corlib->mempool, strlen (iname) + strlen (mname) + 1);
+               name = mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
                strcpy (name, iname);
                strcpy (name + strlen (iname), mname);
                generic_array_method_info [i].name = name;
@@ -3230,7 +3477,7 @@ generic_array_methods (MonoClass *class)
 }
 
 static void
-setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos)
+setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos)
 {
        MonoGenericContext tmp_context;
        int i;
@@ -3244,36 +3491,15 @@ setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos)
                MonoMethod *inflated;
 
                inflated = mono_class_inflate_generic_method (m, &tmp_context);
-               class->methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated);
-       }
-}
-
-static MonoMethod*
-create_array_method (MonoClass *class, const char *name, MonoMethodSignature *sig)
-{
-       MonoMethod *method;
-
-       method = (MonoMethod *) mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethodPInvoke));
-       method->klass = class;
-       method->flags = METHOD_ATTRIBUTE_PUBLIC;
-       method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
-       method->signature = sig;
-       method->name = name;
-       method->slot = -1;
-       /* .ctor */
-       if (name [0] == '.') {
-               method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
-       } else {
-               method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
+               methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated);
        }
-       return method;
 }
 
 static char*
-concat_two_strings_with_zero (MonoMemPool *pool, const char *s1, const char *s2)
+concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
 {
        int len = strlen (s1) + strlen (s2) + 2;
-       char *s = mono_mempool_alloc (pool, len);
+       char *s = mono_image_alloc (image, len);
        int result;
 
        result = g_snprintf (s, len, "%s%c%s", s1, '\0', s2);
@@ -3285,15 +3511,15 @@ concat_two_strings_with_zero (MonoMemPool *pool, const char *s1, const char *s2)
 static void
 set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
 {
-       class->exception_type = error->exception_type;
+       gpointer exception_data = NULL;
 
        switch (error->exception_type) {
        case MONO_EXCEPTION_TYPE_LOAD:
-               class->exception_data = concat_two_strings_with_zero (class->image->mempool, error->class_name, error->assembly_name);
+               exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->assembly_name);
                break;
 
        case MONO_EXCEPTION_MISSING_METHOD:
-               class->exception_data = concat_two_strings_with_zero (class->image->mempool, error->class_name, error->member_name);
+               exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->member_name);
                break;
 
        case MONO_EXCEPTION_MISSING_FIELD: {
@@ -3305,7 +3531,7 @@ set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
                else
                        class_name = error->klass->name;
 
-               class->exception_data = concat_two_strings_with_zero (class->image->mempool, class_name, error->member_name);
+               exception_data = concat_two_strings_with_zero (class->image, class_name, error->member_name);
                
                if (name_space)
                        g_free ((void*)class_name);
@@ -3320,17 +3546,19 @@ set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
                else
                        msg = "Could not load file or assembly '%s' or one of its dependencies.";
 
-               class->exception_data = concat_two_strings_with_zero (class->image->mempool, msg, error->assembly_name);
+               exception_data = concat_two_strings_with_zero (class->image, msg, error->assembly_name);
                break;
        }
 
        case MONO_EXCEPTION_BAD_IMAGE:
-               class->exception_data = error->msg;
+               exception_data = error->msg;
                break;
 
        default :
                g_assert_not_reached ();
        }
+
+       mono_class_set_failure (class, error->exception_type, exception_data);
 }
 
 static void
@@ -3345,23 +3573,20 @@ check_core_clr_inheritance (MonoClass *class)
        class_level = mono_security_core_clr_class_level (class);
        parent_level = mono_security_core_clr_class_level (parent);
 
-       if (class_level < parent_level) {
-               class->exception_type = MONO_EXCEPTION_TYPE_LOAD;
-               class->exception_data = NULL;
-       }
+       if (class_level < parent_level)
+               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
 }
 
 /**
  * mono_class_init:
  * @class: the class to initialize
  *
- * compute the instance_size, class_size and other infos that cannot be 
- * computed at mono_class_get() time. Also compute a generic vtable and 
- * the method slot numbers. We use this infos later to create a domain
- * specific vtable.
- *
+ *   Compute the instance_size, class_size and other infos that cannot be 
+ * computed at mono_class_get() time. Also compute vtable_size if possible. 
  * Returns TRUE on success or FALSE if there was a problem in loading
  * the type (incorrect assemblies, missing assemblies, methods, etc). 
+ *
+ * LOCKING: Acquires the loader lock.
  */
 gboolean
 mono_class_init (MonoClass *class)
@@ -3373,6 +3598,7 @@ mono_class_init (MonoClass *class)
        
        g_assert (class);
 
+       /* Double-checking locking pattern */
        if (class->inited)
                return class->exception_type == MONO_EXCEPTION_NONE;
 
@@ -3428,18 +3654,8 @@ mono_class_init (MonoClass *class)
 
        has_cached_info = mono_class_get_cached_class_info (class, &cached_info);
 
-       if (!class->generic_class && !class->image->dynamic && (!has_cached_info || (has_cached_info && cached_info.has_nested_classes))) {
-               i = mono_metadata_nesting_typedef (class->image, class->type_token, 1);
-               while (i) {
-                       MonoClass* nclass;
-                       guint32 cols [MONO_NESTED_CLASS_SIZE];
-                       mono_metadata_decode_row (&class->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
-                       nclass = mono_class_create_from_typedef (class->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
-                       class->nested_classes = g_list_prepend_mempool (class->nested_classes, class->image->mempool, nclass);
-
-                       i = mono_metadata_nesting_typedef (class->image, class->type_token, i + 1);
-               }
-       }
+       if (class->generic_class || class->image->dynamic || !class->type_token || (has_cached_info && !cached_info.has_nested_classes))
+               class->nested_classes_inited = TRUE;
 
        /*
         * Computes the size used by the fields, and their locations
@@ -3463,108 +3679,59 @@ mono_class_init (MonoClass *class)
                        }
                }
                                
-
-       /* initialize method pointers */
+       /* Initialize arrays */
        if (class->rank) {
-               MonoMethod *amethod;
-               MonoMethodSignature *sig;
-               int count_generic = 0, first_generic = 0;
-               int method_num = 0;
-
                class->method.count = 3 + (class->rank > 1? 2: 1);
 
                if (class->interface_count) {
-                       count_generic = generic_array_methods (class);
-                       first_generic = class->method.count;
+                       int count_generic = generic_array_methods (class);
                        class->method.count += class->interface_count * count_generic;
                }
+       }
 
-               sig = mono_metadata_signature_alloc (class->image, class->rank);
-               sig->ret = &mono_defaults.void_class->byval_arg;
-               sig->pinvoke = TRUE;
-               sig->hasthis = TRUE;
-               for (i = 0; i < class->rank; ++i)
-                       sig->params [i] = &mono_defaults.int32_class->byval_arg;
-
-               amethod = create_array_method (class, ".ctor", sig);
-               class->methods = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethod*) * class->method.count);
-               class->methods [method_num++] = amethod;
-               if (class->rank > 1) {
-                       sig = mono_metadata_signature_alloc (class->image, class->rank * 2);
-                       sig->ret = &mono_defaults.void_class->byval_arg;
-                       sig->pinvoke = TRUE;
-                       sig->hasthis = TRUE;
-                       for (i = 0; i < class->rank * 2; ++i)
-                               sig->params [i] = &mono_defaults.int32_class->byval_arg;
-
-                       amethod = create_array_method (class, ".ctor", sig);
-                       class->methods [method_num++] = amethod;
-               }
-               /* element Get (idx11, [idx2, ...]) */
-               sig = mono_metadata_signature_alloc (class->image, class->rank);
-               sig->ret = &class->element_class->byval_arg;
-               sig->pinvoke = TRUE;
-               sig->hasthis = TRUE;
-               for (i = 0; i < class->rank; ++i)
-                       sig->params [i] = &mono_defaults.int32_class->byval_arg;
-               amethod = create_array_method (class, "Get", sig);
-               class->methods [method_num++] = amethod;
-               /* element& Address (idx11, [idx2, ...]) */
-               sig = mono_metadata_signature_alloc (class->image, class->rank);
-               sig->ret = &class->element_class->this_arg;
-               sig->pinvoke = TRUE;
-               sig->hasthis = TRUE;
-               for (i = 0; i < class->rank; ++i)
-                       sig->params [i] = &mono_defaults.int32_class->byval_arg;
-               amethod = create_array_method (class, "Address", sig);
-               class->methods [method_num++] = amethod;
-               /* void Set (idx11, [idx2, ...], element) */
-               sig = mono_metadata_signature_alloc (class->image, class->rank + 1);
-               sig->ret = &mono_defaults.void_class->byval_arg;
-               sig->pinvoke = TRUE;
-               sig->hasthis = TRUE;
-               for (i = 0; i < class->rank; ++i)
-                       sig->params [i] = &mono_defaults.int32_class->byval_arg;
-               sig->params [i] = &class->element_class->byval_arg;
-               amethod = create_array_method (class, "Set", sig);
-               class->methods [method_num++] = amethod;
-
-               for (i = 0; i < class->interface_count; i++)
-                       setup_generic_array_ifaces (class, class->interfaces [i], first_generic + i * count_generic);
-       }
-
-       mono_class_setup_supertypes (class);
+       mono_class_setup_supertypes (class);
 
        if (!default_ghc)
                initialize_object_slots (class);
 
-       /*
-        * If possible, avoid the creation of the generic vtable by requesting
-        * cached info from the runtime.
+       /* 
+        * Initialize the rest of the data without creating a generic vtable if possible.
+        * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
+        * also avoid computing a generic vtable.
         */
        if (has_cached_info) {
-               guint32 cur_slot = 0;
-
+               /* AOT case */
                class->vtable_size = cached_info.vtable_size;
                class->has_finalize = cached_info.has_finalize;
                class->ghcimpl = cached_info.ghcimpl;
                class->has_cctor = cached_info.has_cctor;
+       } else if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) {
+               static int szarray_vtable_size = 0;
 
-               if (class->parent) {
-                       mono_class_init (class->parent);
-                       cur_slot = class->parent->vtable_size;
+               /* SZARRAY case */
+               if (!szarray_vtable_size) {
+                       mono_class_setup_vtable (class);
+                       szarray_vtable_size = class->vtable_size;
+               } else {
+                       class->vtable_size = szarray_vtable_size;
                }
+       } else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) {
+               MonoClass *gklass = class->generic_class->container_class;
 
-               setup_interface_offsets (class, cur_slot);
-       }
-       else {
-               mono_class_setup_vtable (class);
+               /* Generic instance case */
+               class->ghcimpl = gklass->ghcimpl;
+               class->has_finalize = gklass->has_finalize;
+               class->has_cctor = gklass->has_cctor;
 
-               if (class->exception_type || mono_loader_get_last_error ()){
-                       class_init_ok = FALSE;
-                       goto leave;
-               }
+               mono_class_setup_vtable (gklass);
+               if (gklass->exception_type)
+                       goto fail;
+
+               class->vtable_size = gklass->vtable_size;
+       } else {
+               /* General case */
 
+               /* ghcimpl is not currently used
                class->ghcimpl = 1;
                if (class->parent) { 
                        MonoMethod *cmethod = class->vtable [ghc_slot];
@@ -3574,37 +3741,106 @@ mono_class_init (MonoClass *class)
                                class->ghcimpl = 0;
                        }
                }
+               */
+
+               /* Interfaces and valuetypes are not supposed to have finalizers */
+               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];
+                       }
 
-               /* Object::Finalize should have empty implemenatation */
-               class->has_finalize = 0;
-               if (class->parent) { 
-                       MonoMethod *cmethod = class->vtable [finalize_slot];
-                       if (cmethod->is_inflated)
-                               cmethod = ((MonoMethodInflated*)cmethod)->declaring;
-                       if (cmethod != default_finalize) {
-                               class->has_finalize = 1;
+                       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;
+                                       }
+                               }
                        }
                }
 
-               for (i = 0; i < class->method.count; ++i) {
-                       MonoMethod *method = class->methods [i];
-                       if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
-                               (strcmp (".cctor", method->name) == 0)) {
-                               class->has_cctor = 1;
-                               break;
+               /* C# doesn't allow interfaces to have cctors */
+               if (!MONO_CLASS_IS_INTERFACE (class) || class->image != mono_defaults.corlib) {
+                       MonoMethod *cmethod = NULL;
+
+                       if (class->type_token) {
+                               cmethod = find_method_in_metadata (class, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
+                               /* The find_method function ignores the 'flags' argument */
+                               if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
+                                       class->has_cctor = 1;
+                       } else {
+                               mono_class_setup_methods (class);
+
+                               for (i = 0; i < class->method.count; ++i) {
+                                       MonoMethod *method = class->methods [i];
+                                       if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
+                                               (strcmp (".cctor", method->name) == 0)) {
+                                               class->has_cctor = 1;
+                                               break;
+                                       }
+                               }
                        }
                }
        }
 
-       if (MONO_CLASS_IS_INTERFACE (class)) {
-               /* 
-                * knowledge of interface offsets is needed for the castclass/isinst code, so
-                * we have to setup them for interfaces, too.
+       if (!mono_setup_vtable_in_class_init) {
+               /*
+                * This is an embedding API break, since the caller might assume that 
+                * mono_class_init () constructs a generic vtable, so vtable construction errors
+                * are visible right after the mono_class_init (), and not after 
+                * mono_class_vtable ().
                 */
-               setup_interface_offsets (class, 0);
+               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 ())
+                               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 ())
+                                       goto fail;
+                       }
+                       setup_interface_offsets (class, class->parent->vtable_size);
+               } else {
+                       setup_interface_offsets (class, 0);
+               }
+       } else {
+               mono_class_setup_vtable (class);
+
+               if (MONO_CLASS_IS_INTERFACE (class))
+                       setup_interface_offsets (class, 0);
+       }
+
+       if (mono_verifier_is_enabled_for_class (class) && !mono_verifier_verify_class (class)) {
+               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (class->image, class->name, class->image->assembly_name));
+               class_init_ok = FALSE;
        }
 
+       goto leave;
+
+ fail:
+       class_init_ok = FALSE;
+
  leave:
+       /* Because of the double-checking locking pattern */
+       mono_memory_barrier ();
        class->inited = 1;
        class->init_pending = 0;
 
@@ -3623,6 +3859,16 @@ mono_class_init (MonoClass *class)
        return class_init_ok;
 }
 
+static gboolean
+is_corlib_image (MonoImage *image)
+{
+       /* FIXME: allow the dynamic case for our compilers and with full trust */
+       if (image->dynamic)
+               return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib");
+       else
+               return image == mono_defaults.corlib;
+}
+
 /*
  * LOCKING: this assumes the loader lock is held
  */
@@ -3631,6 +3877,7 @@ mono_class_setup_mono_type (MonoClass *class)
 {
        const char *name = class->name;
        const char *nspace = class->name_space;
+       gboolean is_corlib = is_corlib_image (class->image);
 
        class->this_arg.byref = 1;
        class->this_arg.data.klass = class;
@@ -3638,7 +3885,7 @@ mono_class_setup_mono_type (MonoClass *class)
        class->byval_arg.data.klass = class;
        class->byval_arg.type = MONO_TYPE_CLASS;
 
-       if (!strcmp (nspace, "System")) {
+       if (is_corlib && !strcmp (nspace, "System")) {
                if (!strcmp (name, "ValueType")) {
                        /*
                         * do not set the valuetype bit for System.ValueType.
@@ -3660,10 +3907,11 @@ mono_class_setup_mono_type (MonoClass *class)
                        class->this_arg.type = class->byval_arg.type = MONO_TYPE_TYPEDBYREF;
                }
        }
-       
+
        if (class->valuetype) {
                int t = MONO_TYPE_VALUETYPE;
-               if (!strcmp (nspace, "System")) {
+
+               if (is_corlib && !strcmp (nspace, "System")) {
                        switch (*name) {
                        case 'B':
                                if (!strcmp (name, "Boolean")) {
@@ -3753,8 +4001,9 @@ void
 mono_class_setup_parent (MonoClass *class, MonoClass *parent)
 {
        gboolean system_namespace;
+       gboolean is_corlib = is_corlib_image (class->image);
 
-       system_namespace = !strcmp (class->name_space, "System");
+       system_namespace = !strcmp (class->name_space, "System") && is_corlib;
 
        /* if root of the hierarchy */
        if (system_namespace && !strcmp (class->name, "Object")) {
@@ -3775,11 +4024,13 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
                        if (parent == mono_defaults.object_class)
                                parent = mono_defaults.com_object_class;
                }
-               class->parent = parent;
-
+               if (!parent) {
+                       /* set the parent to something useful and safe, but mark the type as broken */
+                       parent = mono_defaults.object_class;
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+               }
 
-               if (!parent)
-                       g_assert_not_reached (); /* FIXME */
+               class->parent = parent;
 
                if (parent->generic_class && !parent->name) {
                        /*
@@ -3809,10 +4060,10 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
                                class->delegate  = 1;
                }
 
-               if (class->parent->enumtype || ((strcmp (class->parent->name, "ValueType") == 0) && 
+               if (class->parent->enumtype || (is_corlib_image (class->parent->image) && (strcmp (class->parent->name, "ValueType") == 0) && 
                                                (strcmp (class->parent->name_space, "System") == 0)))
                        class->valuetype = 1;
-               if (((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) {
+               if (is_corlib_image (class->parent->image) && ((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) {
                        class->valuetype = class->enumtype = 1;
                }
                /*class->enumtype = class->parent->enumtype; */
@@ -3855,7 +4106,7 @@ mono_class_setup_supertypes (MonoClass *class)
                class->idepth = 1;
 
        ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth);
-       class->supertypes = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClass *) * ms);
+       class->supertypes = mono_image_alloc0 (class->image, sizeof (MonoClass *) * ms);
 
        if (class->parent) {
                class->supertypes [class->idepth - 1] = class;
@@ -3902,7 +4153,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
        nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
 
-       class = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+       class = mono_image_alloc0 (image, sizeof (MonoClass));
 
        class->name = name;
        class->name_space = nspace;
@@ -4148,9 +4399,6 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
                }
        }
 
-       if (MONO_CLASS_IS_INTERFACE (klass))
-               setup_interface_offsets (klass, 0);
-
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
        
        mono_loader_unlock ();
@@ -4186,12 +4434,12 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb
                /* FIXME: */
                image = mono_defaults.corlib;
 
-       klass = param->pklass = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+       klass = param->pklass = mono_image_alloc0 (image, sizeof (MonoClass));
 
        if (param->name)
                klass->name = param->name;
        else {
-               klass->name = mono_mempool_alloc0 (image->mempool, 16);
+               klass->name = mono_image_alloc0 (image, 16);
                sprintf ((char*)klass->name, is_mvar ? "!!%d" : "!%d", param->num);
        }
        klass->name_space = "";
@@ -4211,7 +4459,7 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb
 
        if (count - pos > 0) {
                klass->interface_count = count - pos;
-               klass->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass *) * (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];
        }
@@ -4230,6 +4478,31 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb
        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);
+               }
+       }
+
        mono_class_setup_supertypes (klass);
 
        mono_loader_unlock ();
@@ -4259,12 +4532,12 @@ mono_ptr_class_get (MonoType *type)
                mono_loader_unlock ();
                return result;
        }
-       result = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+       result = mono_image_alloc0 (image, 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);
-       result->name = mono_mempool_strdup (image->mempool, name);
+       result->name = mono_image_strdup (image, name);
        g_free (name);
 
        mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
@@ -4415,15 +4688,17 @@ mono_class_from_mono_type (MonoType *type)
  * @context: the generic context used to evaluate generic instantiations in
  */
 static MonoType *
-mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
+mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate)
 {
        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 (t, context);
-               if (inflated)
+               MonoType *inflated = inflate_generic_type (NULL, t, context);
+               if (inflated) {
                        t = inflated;
+                       *did_inflate = TRUE;
+               }
        }
        return t;
 }
@@ -4437,10 +4712,15 @@ mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGener
 static MonoClass *
 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
 {
-       MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context);
+       MonoClass *ret;
+       gboolean inflated = FALSE;
+       MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated);
        if (!t)
                return NULL;
-       return mono_class_from_mono_type (t);
+       ret = mono_class_from_mono_type (t);
+       if (inflated)
+               mono_metadata_free_type (t);
+       return ret;
 }
 
 /**
@@ -4496,19 +4776,21 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
                        mono_class_init (parent);
        }
 
-       class = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+       class = mono_image_alloc0 (image, sizeof (MonoClass));
 
        class->image = image;
        class->name_space = eclass->name_space;
        nsize = strlen (eclass->name);
-       name = g_malloc (nsize + 2 + rank);
+       name = g_malloc (nsize + 2 + rank + 1);
        memcpy (name, eclass->name, nsize);
        name [nsize] = '[';
        if (rank > 1)
                memset (name + nsize + 1, ',', rank - 1);
-       name [nsize + rank] = ']';
-       name [nsize + rank + 1] = 0;
-       class->name = mono_mempool_strdup (image->mempool, name);
+       if (bounded)
+               name [nsize + rank] = '*';
+       name [nsize + rank + bounded] = ']';
+       name [nsize + rank + bounded + 1] = 0;
+       class->name = mono_image_strdup (image, name);
        g_free (name);
 
        mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
@@ -4537,7 +4819,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
                /* generic IList, ICollection, IEnumerable */
                class->interface_count = 1;
-               class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
+               class->interfaces = mono_image_alloc0 (image, sizeof (MonoClass*) * class->interface_count);
 
                args [0] = &eclass->byval_arg;
                class->interfaces [0] = mono_class_bind_generic_parameters (
@@ -4560,7 +4842,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
        class->element_class = eclass;
 
        if ((rank > 1) || bounded) {
-               MonoArrayType *at = mono_mempool_alloc0 (image->mempool, sizeof (MonoArrayType));
+               MonoArrayType *at = mono_image_alloc0 (image, sizeof (MonoArrayType));
                class->byval_arg.type = MONO_TYPE_ARRAY;
                class->byval_arg.data.array = at;
                at->eklass = eclass;
@@ -4805,7 +5087,7 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ
        g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
 
        if (!field->data) {
-               cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), cindex + 1);
+               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));
 
@@ -5025,6 +5307,7 @@ MonoType *
 mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
 {
        MonoType *type = NULL;
+       gboolean inflated = FALSE;
 
        //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
        if (image->dynamic)
@@ -5035,14 +5318,30 @@ mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *co
                return class ? mono_class_get_type (class) : NULL;
        }
 
-       type = mono_type_retrieve_from_typespec (image, type_token, context);
+       type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated);
 
        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);
        }
 
+       if (inflated) {
+               MonoType *tmp = type;
+               type = mono_class_get_type (mono_class_from_mono_type (type));
+               /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
+                * A MonoClass::byval_arg of a generic type definion has type CLASS.
+                * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg.
+                *
+                * The long term solution is to chaise this places and make then set MonoType::type correctly.
+                * */
+               if (type->type != tmp->type)
+                       type = tmp;
+               else
+                       mono_metadata_free_type (tmp);
+       }
        return type;
 }
 
@@ -5242,17 +5541,18 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
 }
 
 static MonoClass*
-return_nested_in (MonoClass *class, char *nested) {
+return_nested_in (MonoClass *class, char *nested)
+{
        MonoClass *found;
        char *s = strchr (nested, '/');
-       GList *tmp;
+       gpointer iter = NULL;
 
        if (s) {
                *s = 0;
                s++;
        }
-       for (tmp = class->nested_classes; tmp; tmp = tmp->next) {
-               found = tmp->data;
+
+       while ((found = mono_class_get_nested_types (class, &iter))) {
                if (strcmp (found->name, nested) == 0) {
                        if (s)
                                return return_nested_in (found, s);
@@ -5262,6 +5562,36 @@ return_nested_in (MonoClass *class, char *nested) {
        return NULL;
 }
 
+static MonoClass*
+search_modules (MonoImage *image, const char *name_space, const char *name)
+{
+       MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
+       MonoImage *file_image;
+       MonoClass *class;
+       int i;
+
+       /* 
+        * The EXPORTEDTYPES table only contains public types, so have to search the
+        * modules as well.
+        * Note: image->modules contains the contents of the MODULEREF table, while
+        * the real module list is in the FILE table.
+        */
+       for (i = 0; i < file_table->rows; i++) {
+               guint32 cols [MONO_FILE_SIZE];
+               mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
+               if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
+                       continue;
+
+               file_image = mono_image_load_file_for_image (image, i + 1);
+               if (file_image) {
+                       class = mono_class_from_name (file_image, name_space, name);
+                       if (class)
+                               return class;
+               }
+       }
+
+       return NULL;
+}
 
 /**
  * mono_class_from_name:
@@ -5297,6 +5627,8 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
        if (get_class_from_name) {
                gboolean res = get_class_from_name (image, name_space, name, &class);
                if (res) {
+                       if (!class)
+                               class = search_modules (image, name_space, name);
                        if (nested)
                                return class ? return_nested_in (class, nested) : NULL;
                        else
@@ -5327,6 +5659,12 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
                }
        }
 
+       if (!token) {
+               class = search_modules (image, name_space, name);
+               if (class)
+                       return class;
+       }
+
        if (!token)
                return NULL;
 
@@ -5350,15 +5688,19 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name
                        return class;
                } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
                        MonoAssembly **references = image->references;
-                       if (!references [idx - 1])
-                               mono_assembly_load_reference (image, idx - 1);
+                       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 [idx - 1]);
-                       if (references [idx - 1] == (gpointer)-1)
+                       g_assert (references [assembly_idx - 1]);
+                       if (references [assembly_idx - 1] == (gpointer)-1)
                                return NULL;                    
                        else
                                /* FIXME: Cycle detection */
-                               return mono_class_from_name (references [idx - 1]->image, name_space, name);
+                               return mono_class_from_name (references [assembly_idx - 1]->image, name_space, name);
                } else {
                        g_error ("not yet implemented");
                }
@@ -5452,7 +5794,9 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                         * interface_offsets set.
                         */
                        return mono_reflection_call_is_assignable_to (oklass, klass);
-
+               if (!oklass->interface_bitmap)
+                       /* Happens with generic instances of not-yet created dynamic types */
+                       return FALSE;
                if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
                        return TRUE;
 
@@ -5482,6 +5826,10 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                                                MonoClass *param1_class = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [i]);
                                                MonoClass *param2_class = mono_class_from_mono_type (oklass->generic_class->context.class_inst->type_argv [i]);
 
+                                               if (param1_class->valuetype != param2_class->valuetype) {
+                                                       match = FALSE;
+                                                       break;
+                                               }
                                                /*
                                                 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
                                                 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
@@ -5491,8 +5839,10 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                                                                ;
                                                        else if (((container->type_params [i].flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
                                                                ;
-                                                       else
+                                                       else {
                                                                match = FALSE;
+                                                               break;
+                                                       }
                                                }
                                        }
 
@@ -5527,9 +5877,12 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                }
 
                return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
-       } else if (mono_class_is_nullable (klass))
-               return (mono_class_is_assignable_from (klass->cast_class, oklass));
-       else if (klass == mono_defaults.object_class)
+       } else if (mono_class_is_nullable (klass)) {
+               if (mono_class_is_nullable (oklass))
+                       return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
+               else
+                       return mono_class_is_assignable_from (klass->cast_class, oklass);
+       } else if (klass == mono_defaults.object_class)
                return TRUE;
 
        return mono_class_has_parent (oklass, klass);
@@ -6037,8 +6390,8 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter)
        MonoClassField* field;
        if (!iter)
                return NULL;
-       mono_class_setup_fields_locking (klass);
        if (!*iter) {
+               mono_class_setup_fields_locking (klass);
                /* start from the first */
                if (klass->field.count) {
                        return *iter = &klass->fields [0];
@@ -6227,10 +6580,33 @@ MonoClass*
 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
 {
        GList *item;
+       int i;
+
        if (!iter)
                return NULL;
        if (!klass->inited)
                mono_class_init (klass);
+       if (!klass->nested_classes_inited) {
+               if (!klass->type_token)
+                       klass->nested_classes_inited = TRUE;
+               mono_loader_lock ();
+               if (!klass->nested_classes_inited) {
+                       i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
+                       while (i) {
+                               MonoClass* nclass;
+                               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);
+
+                               i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
+                       }
+               }
+               mono_memory_barrier ();
+               klass->nested_classes_inited = TRUE;
+               mono_loader_unlock ();
+       }
+
        if (!*iter) {
                /* start from the first */
                if (klass->nested_classes) {
@@ -6479,6 +6855,32 @@ mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_c
        return mono_class_get_method_from_name_flags (klass, name, param_count, 0);
 }
 
+static MonoMethod*
+find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
+{
+       MonoMethod *res = NULL;
+       int i;
+
+       /* Search directly in the metadata to avoid calling setup_methods () */
+       for (i = 0; i < klass->method.count; ++i) {
+               guint32 cols [MONO_METHOD_SIZE];
+               MonoMethod *method;
+
+               /* 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 (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
+                       method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
+                       if ((param_count == -1) || mono_method_signature (method)->param_count == param_count) {
+                               res = method;
+                               break;
+                       }
+               }
+       }
+
+       return res;
+}
+
 /**
  * mono_class_get_method_from_name_flags:
  * @klass: where to look for the method
@@ -6497,7 +6899,7 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p
 
        mono_class_init (klass);
 
-       if (klass->methods) {
+       if (klass->methods || klass->generic_class) {
                mono_class_setup_methods (klass);
                for (i = 0; i < klass->method.count; ++i) {
                        MonoMethod *method = klass->methods [i];
@@ -6512,22 +6914,7 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p
                }
        }
        else {
-               /* Search directly in the metadata to avoid calling setup_methods () */
-               for (i = 0; i < klass->method.count; ++i) {
-                       guint32 cols [MONO_METHOD_SIZE];
-                       MonoMethod *method;
-
-                       /* 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 (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
-                               method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
-                               if ((param_count == -1) || mono_method_signature (method)->param_count == param_count) {
-                                       res = method;
-                                       break;
-                               }
-                       }
-               }
+           res = find_method_in_metadata (klass, name, param_count, flags);
        }
 
        return res;
@@ -6541,17 +6928,42 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p
  *
  * Keep a detected failure informations in the class for later processing.
  * Note that only the first failure is kept.
+ *
+ * LOCKING: Acquires the loader lock.
  */
 gboolean
 mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
 {
        if (klass->exception_type)
                return FALSE;
+
+       mono_loader_lock ();
        klass->exception_type = ex_type;
-       klass->exception_data = ex_data;
+       if (ex_data)
+               mono_property_hash_insert (klass->image->property_hash, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
+       mono_loader_unlock ();
+
        return TRUE;
 }
 
+/*
+ * mono_class_get_exception_data:
+ *
+ *   Return the exception_data property of KLASS.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
+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;
+}
+
 /**
  * mono_classes_init:
  *
@@ -6570,17 +6982,8 @@ mono_classes_init (void)
 void
 mono_classes_cleanup (void)
 {
-       IOffsetInfo *cached_info, *next;
-
        if (global_interface_bitset)
                mono_bitset_free (global_interface_bitset);
-
-       for (cached_info = cached_offset_info; cached_info;) {
-               next = cached_info->next;
-
-               g_free (cached_info);
-               cached_info = next;
-       }
 }
 
 /**
@@ -6594,11 +6997,13 @@ mono_classes_cleanup (void)
 MonoException*
 mono_class_get_exception_for_failure (MonoClass *klass)
 {
+       gpointer exception_data = mono_class_get_exception_data (klass);
+
        switch (klass->exception_type) {
        case MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND: {
                MonoDomain *domain = mono_domain_get ();
                MonoSecurityManager* secman = mono_security_manager_get_methods ();
-               MonoMethod *method = klass->exception_data;
+               MonoMethod *method = exception_data;
                guint32 error = (method) ? MONO_METADATA_INHERITANCEDEMAND_METHOD : MONO_METADATA_INHERITANCEDEMAND_CLASS;
                MonoObject *exc = NULL;
                gpointer args [4];
@@ -6623,19 +7028,19 @@ mono_class_get_exception_for_failure (MonoClass *klass)
                return ex;
        }
        case MONO_EXCEPTION_MISSING_METHOD: {
-               char *class_name = klass->exception_data;
+               char *class_name = exception_data;
                char *assembly_name = class_name + strlen (class_name) + 1;
 
                return mono_get_exception_missing_method (class_name, assembly_name);
        }
        case MONO_EXCEPTION_MISSING_FIELD: {
-               char *class_name = klass->exception_data;
+               char *class_name = exception_data;
                char *member_name = class_name + strlen (class_name) + 1;
 
                return mono_get_exception_missing_field (class_name, member_name);
        }
        case MONO_EXCEPTION_FILE_NOT_FOUND: {
-               char *msg_format = klass->exception_data;
+               char *msg_format = exception_data;
                char *assembly_name = msg_format + strlen (msg_format) + 1;
                char *msg = g_strdup_printf (msg_format, assembly_name);
                MonoException *ex;
@@ -6647,7 +7052,7 @@ mono_class_get_exception_for_failure (MonoClass *klass)
                return ex;
        }
        case MONO_EXCEPTION_BAD_IMAGE: {
-               return mono_get_exception_bad_image_format (klass->exception_data);
+               return mono_get_exception_bad_image_format (exception_data);
        }
        default: {
                MonoLoaderError *error;
@@ -6665,6 +7070,74 @@ mono_class_get_exception_for_failure (MonoClass *klass)
        }
 }
 
+static gboolean
+is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
+ {
+       outer_klass = mono_class_get_generic_type_definition (outer_klass);
+       inner_klass = mono_class_get_generic_type_definition (inner_klass);
+       do {
+               if (outer_klass == inner_klass)
+                       return TRUE;
+               inner_klass = inner_klass->nested_in;
+       } while (inner_klass);
+       return FALSE;
+}
+
+MonoClass *
+mono_class_get_generic_type_definition (MonoClass *klass)
+{
+       return klass->generic_class ? klass->generic_class->container_class : klass;
+}
+
+/*
+ * Check if @klass is a subtype of @parent ignoring generic instantiations.
+ * 
+ * Generic instantiations are ignored for all super types of @klass.
+ * 
+ * Visibility checks ignoring generic instantiations.  
+ */
+static gboolean
+mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
+{
+       int i;
+       klass = mono_class_get_generic_type_definition (klass);
+       parent = mono_class_get_generic_type_definition (parent);
+       
+       for (i = 0; i < klass->idepth; ++i) {
+               if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
+                       return TRUE;
+       }
+       return FALSE;
+}
+/*
+ * Subtype can only access parent members with family protection if the site object
+ * is subclass of Subtype. For example:
+ * class A { protected int x; }
+ * class B : A {
+ *     void valid_access () {
+ *             B b;
+ *             b.x = 0;
+ *  }
+ *  void invalid_access () {
+ *             A a;
+ *             a.x = 0;
+ *  }
+ * }
+ * */
+static gboolean
+is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
+{
+       if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
+               return FALSE;
+
+       if (context_klass == NULL)
+               return TRUE;
+       /*if access_klass is not member_klass context_klass must be type compat*/
+       if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
+               return FALSE;
+       return TRUE;
+}
+
 static gboolean
 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
 {
@@ -6673,6 +7146,7 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
                return TRUE;
        if (!accessed || !accessing)
                return FALSE;
+       mono_assembly_load_friends (accessed);
        for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
                MonoAssemblyName *friend = tmp->data;
                /* Be conservative with checks */
@@ -6683,7 +7157,7 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
                if (friend->public_key_token [0]) {
                        if (!accessing->aname.public_key_token [0])
                                continue;
-                       if (strcmp ((char*)friend->public_key_token, (char*)accessing->aname.public_key_token))
+                       if (!mono_public_tokens_are_equal (friend->public_key_token, accessing->aname.public_key_token))
                                continue;
                }
                return TRUE;
@@ -6707,9 +7181,67 @@ get_generic_definition_class (MonoClass *klass)
        return NULL;
 }
 
+static gboolean
+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;
+       }
+       return TRUE;
+}
+
+static gboolean
+can_access_type (MonoClass *access_klass, MonoClass *member_klass)
+{
+       int access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+
+       if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
+               return FALSE;
+
+       if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
+               return TRUE;
+
+       if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
+               return FALSE;
+
+       switch (access_level) {
+       case TYPE_ATTRIBUTE_NOT_PUBLIC:
+               return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+
+       case TYPE_ATTRIBUTE_PUBLIC:
+               return TRUE;
+
+       case TYPE_ATTRIBUTE_NESTED_PUBLIC:
+               return TRUE;
+
+       case TYPE_ATTRIBUTE_NESTED_PRIVATE:
+               return is_nesting_type (member_klass, access_klass);
+
+       case TYPE_ATTRIBUTE_NESTED_FAMILY:
+               return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in); 
+
+       case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
+               return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+
+       case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
+               return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
+                       mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
+
+       case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
+               return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
+                       mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
+       }
+       return FALSE;
+}
+
 /* FIXME: check visibility of type, too */
 static gboolean
-can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
+can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
 {
        MonoClass *member_generic_def;
        if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
@@ -6722,7 +7254,7 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_
                else
                        access_container = access_klass->generic_class->container_class;
 
-               if (can_access_member (access_container, member_generic_def, access_level))
+               if (can_access_member (access_container, member_generic_def, context_klass, access_level))
                        return TRUE;
        }
 
@@ -6735,18 +7267,18 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_
        case FIELD_ATTRIBUTE_PRIVATE:
                return access_klass == member_klass;
        case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
-               if (mono_class_has_parent (access_klass, member_klass) &&
+               if (is_valid_family_access (access_klass, member_klass, context_klass) &&
                    can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
                        return TRUE;
                return FALSE;
        case FIELD_ATTRIBUTE_ASSEMBLY:
                return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
        case FIELD_ATTRIBUTE_FAMILY:
-               if (mono_class_has_parent (access_klass, member_klass))
+               if (is_valid_family_access (access_klass, member_klass, context_klass))
                        return TRUE;
                return FALSE;
        case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
-               if (mono_class_has_parent (access_klass, member_klass))
+               if (is_valid_family_access (access_klass, member_klass, context_klass))
                        return TRUE;
                return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
        case FIELD_ATTRIBUTE_PUBLIC:
@@ -6759,11 +7291,11 @@ gboolean
 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
 {
        /* FIXME: check all overlapping fields */
-       int can = can_access_member (method->klass, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+       int can = can_access_member (method->klass, field->parent, NULL, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
        if (!can) {
                MonoClass *nested = method->klass->nested_in;
                while (nested) {
-                       can = can_access_member (nested, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+                       can = can_access_member (nested, field->parent, NULL, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
                        if (can)
                                return TRUE;
                        nested = nested->nested_in;
@@ -6775,11 +7307,11 @@ mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
 gboolean
 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
 {
-       int can = can_access_member (method->klass, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+       int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
        if (!can) {
                MonoClass *nested = method->klass->nested_in;
                while (nested) {
-                       can = can_access_member (nested, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+                       can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
                        if (can)
                                return TRUE;
                        nested = nested->nested_in;
@@ -6797,6 +7329,85 @@ mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
        return can;
 }
 
+/*
+ * mono_method_can_access_method_with_context:
+ * @method: The caller method 
+ * @called: The called method 
+ * @context_klass:TThe 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.
+ * 
+ * Returns: TRUE if caller have proper visibility and acessibility to @called
+ */
+gboolean
+mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
+{
+       MonoClass *access_class = method->klass;
+       MonoClass *member_class = called->klass;
+       int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+       if (!can) {
+               MonoClass *nested = access_class->nested_in;
+               while (nested) {
+                       can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+                       if (can)
+                               break;
+                       nested = nested->nested_in;
+               }
+       }
+
+       if (!can)
+               return FALSE;
+
+       if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class)))
+               return FALSE;
+
+       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 TRUE;
+}
+
+
+/*
+ * mono_method_can_access_method_with_context:
+ * @method: The caller method 
+ * @field: The accessed field
+ * @context_klass: The static type on stack of the owner @field object used
+ * 
+ * This function must be used with instance fields, as they have more strict family accessibility.
+ * It can be used with static fields, but context_klass should be NULL.
+ * 
+ * Returns: TRUE if caller have proper visibility and acessibility to @field
+ */
+gboolean
+mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
+{
+       MonoClass *access_class = method->klass;
+       MonoClass *member_class = field->parent;
+       /* FIXME: check all overlapping fields */
+       int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+       if (!can) {
+               MonoClass *nested = access_class->nested_in;
+               while (nested) {
+                       can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+                       if (can)
+                               break;
+                       nested = nested->nested_in;
+               }
+       }
+
+       if (!can)
+               return FALSE;
+
+       if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class)))
+               return FALSE;
+       return TRUE;
+}
+
 /**
  * mono_type_is_valid_enum_basetype:
  * @type: The MonoType to check
@@ -6886,15 +7497,28 @@ mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
 gboolean
 mono_class_generic_sharing_enabled (MonoClass *class)
 {
-       static int generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+       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)
+                       generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+               else
+                       generic_sharing = MONO_GENERIC_SHARING_NONE;
+
                if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
                        if (strcmp (option, "corlib") == 0)
                                generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+                       else if (strcmp (option, "collections") == 0)
+                               generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
                        else if (strcmp (option, "all") == 0)
                                generic_sharing = MONO_GENERIC_SHARING_ALL;
                        else if (strcmp (option, "none") == 0)
@@ -6903,6 +7527,9 @@ mono_class_generic_sharing_enabled (MonoClass *class)
                                g_warning ("Unknown generic sharing option `%s'.", option);
                }
 
+               if (!supported)
+                       generic_sharing = MONO_GENERIC_SHARING_NONE;
+
                inited = TRUE;
        }
 
@@ -6913,6 +7540,12 @@ mono_class_generic_sharing_enabled (MonoClass *class)
                return TRUE;
        case MONO_GENERIC_SHARING_CORLIB :
                return class->image == mono_defaults.corlib;
+       case MONO_GENERIC_SHARING_COLLECTIONS:
+               if (class->image != mono_defaults.corlib)
+                       return FALSE;
+               while (class->nested_in)
+                       class = class->nested_in;
+               return g_str_has_prefix (class->name_space, "System.Collections.Generic");
        default:
                g_assert_not_reached ();
        }