Fri Sep 14 14:04:31 CEST 2007 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / class.c
index 3485ff449793bc0e7f27b6c58141a74d38c719b2..c927d3fb8bc2147d8c83c4470e60249909342a6f 100644 (file)
@@ -18,7 +18,6 @@
 #endif
 #include <mono/metadata/image.h>
 #include <mono/metadata/assembly.h>
-#include <mono/metadata/cil-coff.h>
 #include <mono/metadata/metadata.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/tabledefs.h>
@@ -31,6 +30,8 @@
 #include <mono/metadata/reflection.h>
 #include <mono/metadata/exception.h>
 #include <mono/metadata/security-manager.h>
+#include <mono/metadata/security-core-clr.h>
+#include <mono/metadata/attrdefs.h>
 #include <mono/os/gc_wrapper.h>
 #include <mono/utils/mono-counters.h>
 
@@ -65,7 +66,7 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
        guint32 idx;
        const char *name, *nspace;
        MonoClass *res;
-       MonoAssembly **references;
+       MonoImage *module;
        
        mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
 
@@ -80,8 +81,9 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
                /* a typedef in disguise */
                return mono_class_from_name (image, nspace, name);
        case MONO_RESOLTION_SCOPE_MODULEREF:
-               if (image->modules [idx-1])
-                       return mono_class_from_name (image->modules [idx - 1], nspace, name);
+               module = mono_image_load_module (image, idx);
+               if (module)
+                       return mono_class_from_name (module, nspace, name);
                else {
                        char *msg = g_strdup_printf ("%s%s%s", nspace, nspace [0] ? "." : "", name);
                        char *human_name;
@@ -125,15 +127,12 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
                break;
        }
 
-       references = image->references;
-       if (!references [idx - 1])
+       if (!image->references || !image->references [idx - 1])
                mono_assembly_load_reference (image, idx - 1);
-       /* If this assert fails, it probably means that you haven't installed an assembly load/search hook */
-       g_assert (references == image->references);
-       g_assert (references [idx - 1]);
+       g_assert (image->references [idx - 1]);
 
        /* If the assembly did not load, register this as a type load exception */
-       if (references [idx - 1] == REFERENCE_MISSING){
+       if (image->references [idx - 1] == REFERENCE_MISSING){
                MonoAssemblyName aname;
                char *human_name;
                
@@ -145,24 +144,7 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
                return NULL;
        }
 
-       return mono_class_from_name (references [idx - 1]->image, nspace, name);
-}
-
-static inline MonoType*
-dup_type (MonoType* t, const MonoType *original)
-{
-       MonoType *r = g_new0 (MonoType, 1);
-       *r = *t;
-       r->attrs = original->attrs;
-       r->byref = original->byref;
-       if (t->type == MONO_TYPE_PTR)
-               t->data.type = dup_type (t->data.type, original->data.type);
-       else if (t->type == MONO_TYPE_ARRAY)
-               t->data.array = mono_dup_array_type (t->data.array);
-       else if (t->type == MONO_TYPE_FNPTR)
-               t->data.method = mono_metadata_signature_deep_dup (t->data.method);
-       mono_stats.generics_metadata_size += sizeof (MonoType);
-       return r;
+       return mono_class_from_name (image->references [idx - 1]->image, nspace, name);
 }
 
 /* Copy everything mono_metadata_free_array free. */
@@ -185,9 +167,9 @@ mono_metadata_signature_deep_dup (MonoMethodSignature *sig)
        
        sig = mono_metadata_signature_dup (sig);
        
-       sig->ret = dup_type (sig->ret, sig->ret);
+       sig->ret = mono_metadata_type_dup (NULL, sig->ret);
        for (i = 0; i < sig->param_count; ++i)
-               sig->params [i] = dup_type (sig->params [i], sig->params [i]);
+               sig->params [i] = mono_metadata_type_dup (NULL, sig->params [i]);
        
        return sig;
 }
@@ -205,6 +187,13 @@ _mono_type_get_assembly_name (MonoClass *klass, GString *str)
                ta->aname.public_key_token [0] ? (char *)ta->aname.public_key_token : "null");
 }
 
+static inline void
+mono_type_name_check_byref (MonoType *type, GString *str)
+{
+       if (type->byref)
+               g_string_append_c (str, '&');
+}
+
 static void
 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                            MonoTypeNameFormat format)
@@ -227,6 +216,9 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                for (i = 1; i < rank; i++)
                        g_string_append_c (str, ',');
                g_string_append_c (str, ']');
+               
+               mono_type_name_check_byref (type, str);
+
                if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
                        _mono_type_get_assembly_name (type->data.array->eklass, str);
                break;
@@ -240,6 +232,9 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                mono_type_get_name_recurse (
                        &type->data.klass->byval_arg, str, FALSE, nested_format);
                g_string_append (str, "[]");
+               
+               mono_type_name_check_byref (type, str);
+
                if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
                        _mono_type_get_assembly_name (type->data.klass, str);
                break;
@@ -252,15 +247,21 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
 
                mono_type_get_name_recurse (
                        type->data.type, str, FALSE, nested_format);
-               g_string_append (str, "*");
+               g_string_append_c (str, '*');
+
+               mono_type_name_check_byref (type, str);
+
                if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
-                       _mono_type_get_assembly_name (type->data.klass, str);
+                       _mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
                break;
        }
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
                g_assert (type->data.generic_param->name);
                g_string_append (str, type->data.generic_param->name);
+       
+               mono_type_name_check_byref (type, str);
+
                break;
        default:
                klass = mono_class_from_mono_type (type);
@@ -286,6 +287,7 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                        break;
                if (klass->generic_class) {
                        MonoGenericClass *gclass = klass->generic_class;
+                       MonoGenericInst *inst = gclass->context.class_inst;
                        MonoTypeNameFormat nested_format;
                        int i;
 
@@ -296,16 +298,15 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                                g_string_append_c (str, '<');
                        else
                                g_string_append_c (str, '[');
-                       for (i = 0; i < gclass->inst->type_argc; i++) {
-                               MonoType *t = gclass->inst->type_argv [i];
+                       for (i = 0; i < inst->type_argc; i++) {
+                               MonoType *t = inst->type_argv [i];
 
                                if (i)
                                        g_string_append_c (str, ',');
                                if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
                                    (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
                                        g_string_append_c (str, '[');
-                               mono_type_get_name_recurse (
-                                       gclass->inst->type_argv [i], str, FALSE, nested_format);
+                               mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
                                if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
                                    (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
                                        g_string_append_c (str, ']');
@@ -333,6 +334,9 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                        else
                                g_string_append_c (str, ']');
                }
+
+               mono_type_name_check_byref (type, str);
+
                if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
                    (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
                        _mono_type_get_assembly_name (klass, str);
@@ -368,9 +372,6 @@ mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
 
        mono_type_get_name_recurse (type, result, FALSE, format);
 
-       if (type->byref)
-               g_string_append_c (result, '&');
-
        return g_string_free (result, FALSE);
 }
 
@@ -403,7 +404,7 @@ mono_type_get_name (MonoType *type)
  * mono_type_get_underlying_type:
  * @type: a type
  *
- * Returns: the MonoType for the underlying interger type if @type
+ * Returns: the MonoType for the underlying integer type if @type
  * is an enum and byref is false, otherwise the type itself.
  */
 MonoType*
@@ -437,82 +438,55 @@ mono_class_is_open_constructed_type (MonoType *t)
                return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg);
        case MONO_TYPE_PTR:
                return mono_class_is_open_constructed_type (t->data.type);
-       case MONO_TYPE_GENERICINST: {
-               MonoGenericClass *gclass = t->data.generic_class;
-               int i;
-
-               if (mono_class_is_open_constructed_type (&gclass->container_class->byval_arg))
-                       return TRUE;
-               for (i = 0; i < gclass->inst->type_argc; i++)
-                       if (mono_class_is_open_constructed_type (gclass->inst->type_argv [i]))
-                               return TRUE;
-               return FALSE;
-       }
+       case MONO_TYPE_GENERICINST:
+               return t->data.generic_class->context.class_inst->is_open;
        default:
                return FALSE;
        }
 }
 
-static MonoGenericClass *
-inflate_generic_class (MonoGenericClass *ogclass, MonoGenericContext *context)
-{
-       MonoGenericClass *ngclass, *cached;
-       MonoGenericInst *ninst;
-
-       ninst = mono_metadata_inflate_generic_inst (ogclass->inst, context);
-       if (ninst == ogclass->inst)
-               return ogclass;
-
-       if (ogclass->is_dynamic) {
-               MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
-               ngclass = &dgclass->generic_class;
-               ngclass->is_dynamic = 1;
-       } else {
-               ngclass = g_new0 (MonoGenericClass, 1);
-       }
-
-       ngclass->container_class = ogclass->container_class;
-       ngclass->inst = ninst;
-
-       mono_loader_lock ();
-       cached = mono_metadata_lookup_generic_class (ngclass);
-       mono_loader_unlock ();
-       if (cached) {
-               g_free (ngclass);
-               return cached;
-       }
-
-       return ngclass;
-}
-
 static MonoType*
 inflate_generic_type (MonoType *type, MonoGenericContext *context)
 {
        switch (type->type) {
        case MONO_TYPE_MVAR: {
+               MonoType *nt;
                int num = type->data.generic_param->num;
-               MonoGenericInst *inst = context->gmethod ? context->gmethod->inst : NULL;
+               MonoGenericInst *inst = context->method_inst;
                if (!inst || !inst->type_argv)
                        return NULL;
                if (num >= inst->type_argc)
                        g_error ("MVAR %d (%s) cannot be expanded in this context with %d instantiations", num, type->data.generic_param->name, inst->type_argc);
-               return dup_type (inst->type_argv [num], type);
+
+               /*
+                * Note that the VAR/MVAR cases are different from the rest.  The other cases duplicate @type,
+                * while the VAR/MVAR duplicates a type from the context.  So, we need to ensure that the
+                * ->byref and ->attrs from @type are propagated to the returned type.
+                */
+               nt = mono_metadata_type_dup (NULL, inst->type_argv [num]);
+               nt->byref = type->byref;
+               nt->attrs = type->attrs;
+               return nt;
        }
        case MONO_TYPE_VAR: {
+               MonoType *nt;
                int num = type->data.generic_param->num;
                MonoGenericInst *inst = context->class_inst;
                if (!inst)
                        return NULL;
                if (num >= inst->type_argc)
                        g_error ("VAR %d (%s) cannot be expanded in this context with %d instantiations", num, type->data.generic_param->name, inst->type_argc);
-               return dup_type (inst->type_argv [num], type);
+               nt = mono_metadata_type_dup (NULL, 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);
                if (!inflated)
                        return NULL;
-               nt = dup_type (type, type);
+               nt = mono_metadata_type_dup (NULL, type);
                nt->data.klass = mono_class_from_mono_type (inflated);
                return nt;
        }
@@ -521,35 +495,45 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context)
                MonoType *nt, *inflated = inflate_generic_type (&eclass->byval_arg, context);
                if (!inflated)
                        return NULL;
-               nt = dup_type (type, type);
+               nt = mono_metadata_type_dup (NULL, type);
                nt->data.array = g_memdup (nt->data.array, sizeof (MonoArrayType));
                nt->data.array->eklass = mono_class_from_mono_type (inflated);
                return nt;
        }
        case MONO_TYPE_GENERICINST: {
                MonoGenericClass *gclass = type->data.generic_class;
+               MonoGenericInst *inst;
                MonoType *nt;
-               if (!gclass->inst->is_open)
+               if (!gclass->context.class_inst->is_open)
                        return NULL;
-               gclass = inflate_generic_class (gclass, context);
+
+               inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context);
+               if (inst != gclass->context.class_inst)
+                       gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
+
                if (gclass == type->data.generic_class)
                        return NULL;
-               nt = dup_type (type, type);
+
+               nt = mono_metadata_type_dup (NULL, type);
                nt->data.generic_class = gclass;
                return nt;
        }
        case MONO_TYPE_CLASS:
        case MONO_TYPE_VALUETYPE: {
                MonoClass *klass = type->data.klass;
-               MonoGenericClass *gclass;
+               MonoGenericContainer *container = klass->generic_container;
+               MonoGenericInst *inst;
+               MonoGenericClass *gclass = NULL;
                MonoType *nt;
 
-               if (!klass->generic_container)
-                       return NULL;
-               gclass = inflate_generic_class (mono_get_shared_generic_class (klass->generic_container, klass->image->dynamic), context);
-               if (gclass->inst == klass->generic_container->context.class_inst)
+               if (!container)
                        return NULL;
-               nt = dup_type (type, type);
+
+               /* We can't use context->class_inst directly, since it can have more elements */
+               inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context);
+               gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
+
+               nt = mono_metadata_type_dup (NULL, type);
                nt->type = MONO_TYPE_GENERICINST;
                nt->data.generic_class = gclass;
                return nt;
@@ -563,20 +547,7 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context)
 MonoGenericContext *
 mono_generic_class_get_context (MonoGenericClass *gclass)
 {
-       MonoGenericContext *context = gclass->cached_context;
-       if (context) {
-              g_assert (context->class_inst == gclass->inst);
-              g_assert (!context->gmethod);
-              return context;
-       }
-       
-       context = g_new0 (MonoGenericContext, 1);
-       context->class_inst = gclass->inst;
-
-       if (InterlockedCompareExchangePointer ((gpointer *)&gclass->cached_context, context, NULL))
-              g_free (context);
-
-       return gclass->cached_context;
+       return &gclass->context;
 }
 
 MonoGenericContext *
@@ -600,40 +571,27 @@ mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
        MonoType *inflated = inflate_generic_type (type, context);
 
        if (!inflated)
-               return dup_type (type, type);
+               return mono_metadata_type_dup (NULL, type);
 
        mono_stats.inflated_type_count++;
        return inflated;
 }
 
-static MonoGenericContext *
+static MonoGenericContext
 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with)
 {
        MonoGenericInst *class_inst = NULL;
-       MonoGenericMethod *gmethod = NULL;
-       MonoGenericContext *res;
+       MonoGenericInst *method_inst = NULL;
+       MonoGenericContext res;
 
        if (context->class_inst)
                class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with);
 
-       if (context->gmethod) {
-               MonoGenericInst *ninst = mono_metadata_inflate_generic_inst (context->gmethod->inst, inflate_with);
-               if (class_inst == context->class_inst && ninst == context->gmethod->inst) {
-                       gmethod = context->gmethod;
-               } else {
-                       gmethod = g_new0 (MonoGenericMethod, 1);
-                       gmethod->class_inst = class_inst;
-                       gmethod->container = context->gmethod->container;
-                       gmethod->inst = ninst;
-               }
-       }
-
-       if (class_inst == context->class_inst && gmethod == context->gmethod)
-               return context;
+       if (context->method_inst)
+               method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with);
 
-       res = g_new0 (MonoGenericContext, 1);
-       res->class_inst = class_inst;
-       res->gmethod = gmethod;
+       res.class_inst = class_inst;
+       res.method_inst = method_inst;
 
        return res;
 }
@@ -658,22 +616,27 @@ mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *conte
  *
  * Instantiate method @method with the generic context @context.
  * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
- *         Use mono_get_inflated_method (), mono_method_signature () and mono_method_get_header () to get the correct values.
+ *         Use mono_method_signature () and mono_method_get_header () to get the correct values.
  */
 MonoMethod*
 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
 {
        MonoMethod *result;
-       MonoMethodInflated *iresult;
+       MonoMethodInflated *iresult, *cached;
        MonoMethodSignature *sig;
+       MonoGenericContext tmp_context;
 
-       /* The `method' has already been instantiated before -> we need to create a new context. */
+       /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
        while (method->is_inflated) {
                MonoGenericContext *method_context = mono_method_get_context (method);
                MonoMethodInflated *imethod = (MonoMethodInflated *) method;
-               context = inflate_generic_context (method_context, context);
-               if (context == method_context)
+
+               tmp_context = inflate_generic_context (method_context, context);
+               context = &tmp_context;
+
+               if (mono_metadata_generic_context_equal (method_context, context))
                        return method;
+
                method = imethod->declaring;
        }
 
@@ -682,6 +645,16 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
 
        mono_stats.inflated_method_count++;
        iresult = g_new0 (MonoMethodInflated, 1);
+       iresult->context = *context;
+       iresult->declaring = method;
+
+       mono_loader_lock ();
+       cached = mono_method_inflated_lookup (iresult, FALSE);
+       if (cached) {
+               mono_loader_unlock ();
+               g_free (iresult);
+               return (MonoMethod*)cached;
+       }
 
        sig = mono_method_signature (method);
        if (sig->pinvoke) {
@@ -693,13 +666,12 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
 
        result = (MonoMethod *) iresult;
        result->is_inflated = 1;
+       /* result->generic_container = NULL; */
        result->signature = NULL;
-       iresult->context = context;
-       iresult->declaring = method;
 
        if (!klass_hint || !klass_hint->generic_class ||
            klass_hint->generic_class->container_class != method->klass ||
-           klass_hint->generic_class->inst != context->class_inst)
+           klass_hint->generic_class->context.class_inst != context->class_inst)
                klass_hint = NULL;
 
        if (method->klass->generic_container)
@@ -710,17 +682,13 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin
                result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
        }
 
-       if (method->generic_container && !context->gmethod) {
-               MonoGenericMethod *gmethod = g_memdup (method->generic_container->context.gmethod, sizeof (*gmethod));
-               if (result->klass->generic_class)
-                       gmethod->class_inst = result->klass->generic_class->inst;
-
-               context = g_new0 (MonoGenericContext, 1);
-               context->gmethod = gmethod;
-               context->class_inst = gmethod->class_inst;
-               iresult->context = context;
-       }
+       if (context->method_inst)
+               result->generic_container = NULL;
+       else if (method->generic_container)
+               iresult->context.method_inst = method->generic_container->context.method_inst;
 
+       mono_method_inflated_lookup (iresult, TRUE);
+       mono_loader_unlock ();
        return result;
 }
 
@@ -742,7 +710,7 @@ mono_method_get_context (MonoMethod *method)
        if (!method->is_inflated)
                return NULL;
        imethod = (MonoMethodInflated *) method;
-       return imethod->context;
+       return &imethod->context;
 }
 
 /** 
@@ -1048,7 +1016,7 @@ mono_class_layout_fields (MonoClass *class)
        MonoClassField *field;
 
        if (class->generic_container ||
-           (class->generic_class && class->generic_class->inst->is_open))
+           (class->generic_class && class->generic_class->context.class_inst->is_open))
                return;
 
        /*
@@ -1233,15 +1201,18 @@ 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.
                 */
                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;
 
@@ -1571,8 +1542,8 @@ mono_get_unique_iid (MonoClass *class)
        if (mono_print_vtable) {
                int generic_id;
                char *type_name = mono_type_full_name (&class->byval_arg);
-               if (class->generic_class && !class->generic_class->inst->is_open) {
-                       generic_id = class->generic_class->inst->id;
+               if (class->generic_class && !class->generic_class->context.class_inst->is_open) {
+                       generic_id = class->generic_class->context.class_inst->id;
                        g_assert (generic_id != 0);
                } else {
                        generic_id = 0;
@@ -1679,6 +1650,67 @@ cache_interface_offsets (int max_iid, int *data)
        return cached;
 }
 
+static int
+compare_interface_ids (const void *p_key, const void *p_element) {
+       const MonoClass *key = p_key;
+       const MonoClass *element = *(MonoClass**) p_element;
+       
+       return (key->interface_id - element->interface_id);
+}
+
+int
+mono_class_interface_offset (MonoClass *klass, MonoClass *itf) {
+       MonoClass **result = bsearch (
+                       itf,
+                       klass->interfaces_packed,
+                       klass->interface_offsets_count,
+                       sizeof (MonoClass *),
+                       compare_interface_ids);
+       if (result) {
+               return klass->interface_offsets_packed [result - (klass->interfaces_packed)];
+       } else {
+               return -1;
+       }
+}
+
+static void
+print_implemented_interfaces (MonoClass *klass) {
+       GPtrArray *ifaces = NULL;
+       int i;
+       int ancestor_level = 0;
+       
+       printf ("Packed interface table for class %s has size %d\n", klass->name, klass->interface_offsets_count);
+       for (i = 0; i < klass->interface_offsets_count; i++)
+               printf ("  [%d][UUID %d][SLOT %d] interface %s\n", i,
+                               klass->interfaces_packed [i]->interface_id,
+                               klass->interface_offsets_packed [i],
+                               klass->interfaces_packed [i]->name );
+       printf ("Interface flags: ");
+       for (i = 0; i <= klass->max_interface_id; i++)
+               if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
+                       printf ("(%d,T)", i);
+               else
+                       printf ("(%d,F)", i);
+       printf ("\n");
+       printf ("Dump interface flags:");
+       for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
+               printf (" %02X", klass->interface_bitmap [i]);
+       printf ("\n");
+       while (klass != NULL) {
+               printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
+               ifaces = mono_class_get_implemented_interfaces (klass);
+               if (ifaces) {
+                       for (i = 0; i < ifaces->len; i++) {
+                               MonoClass *ic = g_ptr_array_index (ifaces, i);
+                               printf ("  [UIID %d] interface %s\n", ic->interface_id, ic->name);
+                       }
+                       g_ptr_array_free (ifaces, TRUE);
+               }
+               ancestor_level ++;
+               klass = klass->parent;
+       }
+}
+
 /*
  * LOCKING: this is supposed to be called with the loader lock held.
  */
@@ -1687,8 +1719,10 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
 {
        MonoClass *k, *ic;
        int i, max_iid;
-       int *cached_data;
+       MonoClass **interfaces_full;
+       int *interface_offsets_full;
        GPtrArray *ifaces;
+       int interface_offsets_count;
 
        /* compute maximum number of slots and maximum interface id */
        max_iid = 0;
@@ -1719,16 +1753,20 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
        }
        class->max_interface_id = max_iid;
        /* compute vtable offset for interfaces */
-       class->interface_offsets = g_malloc (sizeof (int) * (max_iid + 1));
+       interfaces_full = g_malloc (sizeof (MonoClass*) * (max_iid + 1));
+       interface_offsets_full = g_malloc (sizeof (int) * (max_iid + 1));
 
-       for (i = 0; i <= max_iid; i++)
-               class->interface_offsets [i] = -1;
+       for (i = 0; i <= max_iid; i++) {
+               interfaces_full [i] = NULL;
+               interface_offsets_full [i] = -1;
+       }
 
        ifaces = mono_class_get_implemented_interfaces (class);
        if (ifaces) {
                for (i = 0; i < ifaces->len; ++i) {
                        ic = g_ptr_array_index (ifaces, i);
-                       class->interface_offsets [ic->interface_id] = cur_slot;
+                       interfaces_full [ic->interface_id] = ic;
+                       interface_offsets_full [ic->interface_id] = cur_slot;
                        cur_slot += ic->method.count;
                }
                g_ptr_array_free (ifaces, TRUE);
@@ -1740,26 +1778,49 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
                        for (i = 0; i < ifaces->len; ++i) {
                                ic = g_ptr_array_index (ifaces, i);
 
-                               if (class->interface_offsets [ic->interface_id] == -1) {
-                                       int io = k->interface_offsets [ic->interface_id];
+                               if (interface_offsets_full [ic->interface_id] == -1) {
+                                       int io = mono_class_interface_offset (k, ic);
 
                                        g_assert (io >= 0);
 
-                                       class->interface_offsets [ic->interface_id] = io;
+                                       interfaces_full [ic->interface_id] = ic;
+                                       interface_offsets_full [ic->interface_id] = io;
                                }
                        }
                        g_ptr_array_free (ifaces, TRUE);
                }
        }
 
-       if (MONO_CLASS_IS_INTERFACE (class))
-               class->interface_offsets [class->interface_id] = cur_slot;
-
-       cached_data = cache_interface_offsets (max_iid + 1, class->interface_offsets);
-       g_free (class->interface_offsets);
-       class->interface_offsets = cached_data;
+       if (MONO_CLASS_IS_INTERFACE (class)) {
+               interfaces_full [class->interface_id] = class;
+               interface_offsets_full [class->interface_id] = cur_slot;
+       }
 
-       return cur_slot;
+       for (interface_offsets_count = 0, i = 0; i <= max_iid; i++) {
+               if (interface_offsets_full [i] != -1) {
+                       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];
+                       interface_offsets_count ++;
+               }
+       }
+       
+       g_free (interfaces_full);
+       g_free (interface_offsets_full);
+       
+       //printf ("JUST DONE: ");
+       //print_implemented_interfaces (class);
+       return cur_slot;
 }
 
 /*
@@ -1826,6 +1887,18 @@ mono_class_setup_vtable (MonoClass *class)
        return;
 }
 
+static void
+check_core_clr_override_method (MonoClass *class, MonoMethod *override, MonoMethod *base)
+{
+       MonoSecurityCoreCLRLevel override_level = mono_security_core_clr_method_level (override, FALSE);
+       MonoSecurityCoreCLRLevel base_level = mono_security_core_clr_method_level (base, FALSE);
+
+       if (override_level != base_level && base_level == MONO_SECURITY_CORE_CLR_CRITICAL) {
+               class->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+               class->exception_data = NULL;
+       }
+}
+
 /*
  * LOCKING: this is supposed to be called with the loader lock held.
  */
@@ -1878,13 +1951,16 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                        int dslot;
                        mono_class_setup_methods (decl->klass);
                        g_assert (decl->slot != -1);
-                       dslot = decl->slot + class->interface_offsets [decl->klass->interface_id];
+                       dslot = decl->slot + mono_class_interface_offset (class, decl->klass);
                        vtable [dslot] = overrides [i*2 + 1];
                        vtable [dslot]->slot = dslot;
                        if (!override_map)
                                override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
                        g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
+
+                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                               check_core_clr_override_method (class, vtable [dslot], decl);
                }
        }
 
@@ -1908,7 +1984,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                        if (pifaces)
                                pic = g_ptr_array_index (pifaces, i);
                        g_assert (ic->interface_id <= k->max_interface_id);
-                       io = k->interface_offsets [ic->interface_id];
+                       io = mono_class_interface_offset (k, ic);
 
                        g_assert (io >= 0);
                        g_assert (io <= max_vtsize);
@@ -1935,6 +2011,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                                mono_secman_inheritancedemand_method (cm, im);
                                                        }
 
+                                                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                                                               check_core_clr_override_method (class, cm, im);
+
                                                        g_assert (io + l <= max_vtsize);
                                                        vtable [io + l] = cm;
                                                }
@@ -1977,13 +2056,17 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                        continue;
 
                                                if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
-                                                   mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+                                                               mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im)) &&
+                                                               ((vtable [io + l] == NULL) || mono_class_is_subclass_of (cm->klass, vtable [io + l]->klass, FALSE))) {
 
                                                        /* CAS - SecurityAction.InheritanceDemand on interface */
                                                        if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
                                                                mono_secman_inheritancedemand_method (cm, im);
                                                        }
 
+                                                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                                                               check_core_clr_override_method (class, cm, im);
+
                                                        g_assert (io + l <= max_vtsize);
                                                        vtable [io + l] = cm;
                                                        break;
@@ -2021,6 +2104,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                                mono_secman_inheritancedemand_method (cm, im);
                                                        }
 
+                                                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                                                               check_core_clr_override_method (class, cm, im);
+
                                                        g_assert (io + l <= max_vtsize);
                                                        vtable [io + l] = cm;
                                                        break;
@@ -2049,10 +2135,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                MonoClass *parent = class->parent;
                                                
                                                for (; parent; parent = parent->parent) {
-                                                       if ((ic->interface_id <= parent->max_interface_id) && 
-                                                                       (parent->interface_offsets [ic->interface_id] != -1) &&
+                                                       if (MONO_CLASS_IMPLEMENTS_INTERFACE (parent, ic->interface_id) &&
                                                                        parent->vtable) {
-                                                               vtable [io + l] = parent->vtable [parent->interface_offsets [ic->interface_id] + l];
+                                                               vtable [io + l] = parent->vtable [mono_class_interface_offset (parent, ic) + l];
                                                        }
                                                }
                                        }
@@ -2073,7 +2158,15 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                        printf ("METHOD %s(%s)\n", cm->name, msig);
                                                        g_free (msig);
                                                }
-                                               g_assert_not_reached ();
+
+                                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+
+                                               if (ifaces)
+                                                       g_ptr_array_free (ifaces, TRUE);
+                                               if (override_map)
+                                                       g_hash_table_destroy (override_map);
+
+                                               return;
                                        }
                                }
                        }
@@ -2138,6 +2231,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                        mono_secman_inheritancedemand_method (cm, m1);
                                                }
 
+                                               if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                                                       check_core_clr_override_method (class, cm, m1);
+
                                                slot = k->methods [j]->slot;
                                                g_assert (cm->slot < max_vtsize);
                                                if (!override_map)
@@ -2170,6 +2266,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                        if (!override_map)
                                override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
                        g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
+
+                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                               check_core_clr_override_method (class, vtable [decl->slot], decl);
                }
        }
 
@@ -2208,8 +2307,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
        if (mono_print_vtable) {
                int icount = 0;
 
+               print_implemented_interfaces (class);
+               
                for (i = 0; i <= max_iid; i++)
-                       if (class->interface_offsets [i] != -1)
+                       if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, i))
                                icount++;
 
                printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&class->byval_arg), 
@@ -2233,7 +2334,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                        for (i = 0; i < class->interface_count; i++) {
                                ic = class->interfaces [i];
                                printf ("  slot offset: %03d, method count: %03d, iid: %03d %s\n",  
-                                       class->interface_offsets [ic->interface_id],
+                                       mono_class_interface_offset (class, ic),
                                        ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg));
                        }
 
@@ -2241,7 +2342,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                for (i = 0; i < k->interface_count; i++) {
                                        ic = k->interfaces [i]; 
                                        printf ("  slot offset: %03d, method count: %03d, iid: %03d %s\n",  
-                                               class->interface_offsets [ic->interface_id],
+                                               mono_class_interface_offset (class, ic),
                                                ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg));
                                }
                        }
@@ -2292,12 +2393,11 @@ g_list_prepend_mempool (GList* l, MonoMemPool* mp, gpointer datum)
 static void
 setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos)
 {
-       MonoGenericContext *context;
+       MonoGenericContext tmp_context;
        int i;
 
-       context = g_new0 (MonoGenericContext, 1);
-       context->gmethod = g_new0 (MonoGenericMethod, 1);
-       context->gmethod->inst = iface->generic_class->inst;
+       tmp_context.class_inst = NULL;
+       tmp_context.method_inst = iface->generic_class->context.class_inst;
 
        for (i = 0; i < class->parent->method.count; i++) {
                MonoMethod *m = class->parent->methods [i];
@@ -2322,7 +2422,7 @@ setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos)
                strcpy (name, iname);
                strcpy (name + strlen (iname), mname);
 
-               inflated = mono_class_inflate_generic_method (m, context);
+               inflated = mono_class_inflate_generic_method (m, &tmp_context);
                class->methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, name, inflated);
        }
 }
@@ -2348,6 +2448,84 @@ create_array_method (MonoClass *class, const char *name, MonoMethodSignature *si
        return method;
 }
 
+static char*
+concat_two_strings_with_zero (MonoMemPool *pool, const char *s1, const char *s2)
+{
+       int len = strlen (s1) + strlen (s2) + 2;
+       char *s = mono_mempool_alloc (pool, len);
+       int result;
+
+       result = g_snprintf (s, len, "%s%c%s", s1, '\0', s2);
+       g_assert (result == len - 1);
+
+       return s;
+}
+
+static void
+set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
+{
+       class->exception_type = error->exception_type;
+
+       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);
+               break;
+
+       case MONO_EXCEPTION_MISSING_METHOD:
+               class->exception_data = concat_two_strings_with_zero (class->image->mempool, error->class_name, error->member_name);
+               break;
+
+       case MONO_EXCEPTION_MISSING_FIELD: {
+               const char *name_space = error->klass->name_space ? error->klass->name_space : NULL;
+               const char *class_name;
+
+               if (name_space)
+                       class_name = g_strdup_printf ("%s.%s", name_space, error->klass->name);
+               else
+                       class_name = error->klass->name;
+
+               class->exception_data = concat_two_strings_with_zero (class->image->mempool, class_name, error->member_name);
+               
+               if (name_space)
+                       g_free ((void*)class_name);
+               break;
+       }
+
+       case MONO_EXCEPTION_FILE_NOT_FOUND: {
+               const char *msg;
+
+               if (error->ref_only)
+                       msg = "Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.";
+               else
+                       msg = "Could not load file or assembly '%s' or one of its dependencies.";
+
+               class->exception_data = concat_two_strings_with_zero (class->image->mempool, msg, error->assembly_name);
+               break;
+       }
+
+       default :
+               g_assert_not_reached ();
+       }
+}
+
+static void
+check_core_clr_inheritance (MonoClass *class)
+{
+       MonoSecurityCoreCLRLevel class_level, parent_level;
+       MonoClass *parent = class->parent;
+
+       if (!parent)
+               return;
+
+       class_level = mono_security_core_clr_class_level (class);
+       parent_level = mono_security_core_clr_class_level (parent);
+
+       if (class_level < parent_level) {
+               class->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+               class->exception_data = NULL;
+       }
+}
+
 /**
  * mono_class_init:
  * @class: the class to initialize
@@ -2371,7 +2549,7 @@ mono_class_init (MonoClass *class)
        g_assert (class);
 
        if (class->inited)
-               return TRUE;
+               return class->exception_type == MONO_EXCEPTION_NONE;
 
        /*g_print ("Init class %s\n", class->name);*/
 
@@ -2381,7 +2559,7 @@ mono_class_init (MonoClass *class)
        if (class->inited) {
                mono_loader_unlock ();
                /* Somebody might have gotten in before us */
-               return TRUE;
+               return class->exception_type == MONO_EXCEPTION_NONE;
        }
 
        if (class->init_pending) {
@@ -2397,6 +2575,9 @@ mono_class_init (MonoClass *class)
                mono_secman_inheritancedemand_class (class, class->parent);
        }
 
+       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+               check_core_clr_inheritance (class);
+
        if (mono_debugger_start_class_init_func)
                mono_debugger_start_class_init_func (class);
 
@@ -2421,10 +2602,8 @@ mono_class_init (MonoClass *class)
                class->methods = g_new0 (MonoMethod *, class->method.count);
 
                for (i = 0; i < class->method.count; i++) {
-                       MonoMethod *inflated = mono_class_inflate_generic_method_full (
+                       class->methods [i] = mono_class_inflate_generic_method_full (
                                gklass->methods [i], class, mono_class_get_context (class));
-
-                       class->methods [i] = mono_get_inflated_method (inflated);
                }
 
                class->property = gklass->property;
@@ -2453,7 +2632,7 @@ mono_class_init (MonoClass *class)
 
        has_cached_info = mono_class_get_cached_class_info (class, &cached_info);
 
-       if (!class->generic_class && (!has_cached_info || (has_cached_info && cached_info.has_nested_classes))) {
+       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;
@@ -2627,7 +2806,7 @@ mono_class_init (MonoClass *class)
 
        if (MONO_CLASS_IS_INTERFACE (class)) {
                /* 
-                * class->interface_offsets is needed for the castclass/isinst code, so
+                * knowledge of interface offsets is needed for the castclass/isinst code, so
                 * we have to setup them for interfaces, too.
                 */
                setup_interface_offsets (class, 0);
@@ -2637,6 +2816,13 @@ mono_class_init (MonoClass *class)
        class->inited = 1;
        class->init_pending = 0;
 
+       if (mono_loader_get_last_error ()) {
+               if (class->exception_type == MONO_EXCEPTION_NONE)
+                       set_failure_from_loader_error (class, mono_loader_get_last_error ());
+
+               mono_loader_clear_error ();
+       }
+
        mono_loader_unlock ();
 
        if (mono_debugger_class_init_func)
@@ -2882,66 +3068,6 @@ mono_class_setup_supertypes (MonoClass *class)
        } else {
                class->supertypes [0] = class;
        }
-}      
-
-MonoGenericInst *
-mono_get_shared_generic_inst (MonoGenericContainer *container)
-{
-       MonoGenericInst *nginst;
-       int i;
-
-       nginst = g_new0 (MonoGenericInst, 1);
-       nginst->type_argc = container->type_argc;
-       nginst->type_argv = g_new0 (MonoType *, nginst->type_argc);
-       nginst->is_reference = 1;
-       nginst->is_open = 1;
-
-       for (i = 0; i < nginst->type_argc; i++) {
-               MonoType *t = g_new0 (MonoType, 1);
-
-               t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
-               t->data.generic_param = &container->type_params [i];
-
-               nginst->type_argv [i] = t;
-       }
-
-       return mono_metadata_lookup_generic_inst (nginst);
-}
-
-/*
- * In preparation for implementing shared code.
- */
-MonoGenericClass *
-mono_get_shared_generic_class (MonoGenericContainer *container, gboolean is_dynamic)
-{
-       MonoGenericClass *gclass;
-
-       g_assert (!container->is_method);
-
-       if (is_dynamic) {
-               MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
-               gclass = &dgclass->generic_class;
-               gclass->is_dynamic = 1;
-       } else {
-               gclass = g_new0 (MonoGenericClass, 1);
-       }
-
-       gclass->cached_context = &container->context;
-       gclass->container_class = container->owner.klass;
-       gclass->inst = mono_get_shared_generic_inst (container);
-
-       if (!is_dynamic) {
-               MonoGenericClass *cached = mono_metadata_lookup_generic_class (gclass);
-
-               if (cached) {
-                       g_free (gclass);
-                       return cached;
-               }
-       }
-
-       gclass->cached_class = container->owner.klass;
-
-       return gclass;
 }
 
 /**
@@ -2969,7 +3095,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
 
        mono_loader_lock ();
 
-       if ((class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token)))) {
+       if ((class = mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
                mono_loader_unlock ();
                return class;
        }
@@ -2990,7 +3116,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        class->type_token = type_token;
        class->flags = cols [MONO_TYPEDEF_FLAGS];
 
-       g_hash_table_insert (image->class_cache, GUINT_TO_POINTER (type_token), class);
+       mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), class);
 
        /*
         * Check whether we're a generic type definition.
@@ -2999,15 +3125,13 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        if (class->generic_container) {
                class->generic_container->owner.klass = class;
                context = &class->generic_container->context;
-
-               context->class_inst = mono_get_shared_generic_inst (class->generic_container);
        }
 
        if (cols [MONO_TYPEDEF_EXTENDS]) {
                parent = mono_class_get_full (
                        image, mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]), context);
                if (parent == NULL){
-                       g_hash_table_remove (image->class_cache, GUINT_TO_POINTER (type_token));
+                       mono_internal_hash_table_remove (&image->class_cache, GUINT_TO_POINTER (type_token));
                        mono_loader_unlock ();
                        return NULL;
                }
@@ -3079,6 +3203,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
 
        if (class->enumtype) {
                class->enum_basetype = mono_class_find_enum_basetype (class);
+               if (!class->enum_basetype) {
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_loader_unlock ();
+                       return NULL;
+               }
                class->cast_class = class->element_class = mono_class_from_mono_type (class->enum_basetype);
        }
 
@@ -3110,14 +3239,14 @@ MonoClass*
 mono_class_get_nullable_param (MonoClass *klass)
 {
        g_assert (mono_class_is_nullable (klass));
-       return mono_class_from_mono_type (klass->generic_class->inst->type_argv [0]);
+       return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
 }
 
 /*
  * Create the `MonoClass' for an instantiation of a generic type.
  * We only do this if we actually need it.
  */
-static MonoClass*
+MonoClass*
 mono_generic_class_get_class (MonoGenericClass *gclass)
 {
        MonoClass *klass, *gklass;
@@ -3126,6 +3255,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        mono_loader_lock ();
        if (gclass->cached_class) {
                mono_loader_unlock ();
+               g_assert (!gclass->cached_class->generic_container);
                return gclass->cached_class;
        }
 
@@ -3250,10 +3380,12 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb
        if (!image && param->owner) {
                if (is_mvar) {
                        MonoMethod *method = param->owner->owner.method;
-                       image = method->klass ? method->klass->image : NULL;
+                       image = (method && method->klass) ? method->klass->image : NULL;
                } else {
                        MonoClass *klass = param->owner->owner.klass;
-                       image = klass->image;
+                       // FIXME: 'klass' should not be null
+                       //        But, monodis creates GenericContainers without associating a owner to it
+                       image = klass ? klass->image : NULL;
                }
        }
 
@@ -3428,7 +3560,7 @@ mono_class_from_mono_type (MonoType *type)
        case MONO_TYPE_MVAR:
                return mono_class_from_generic_parameter (type->data.generic_param, NULL, TRUE);
        default:
-               g_warning ("implement me 0x%02x\n", type->type);
+               g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
                g_assert_not_reached ();
        }
        
@@ -3436,21 +3568,37 @@ mono_class_from_mono_type (MonoType *type)
 }
 
 /**
+ * mono_type_retrieve_from_typespec
  * @image: context where the image is created
  * @type_spec:  typespec token
  * @context: the generic context used to evaluate generic instantiations in
  */
-static MonoClass *
-mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
+static MonoType *
+mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
 {
        MonoType *t = mono_type_create_from_typespec (image, type_spec);
        if (!t)
                return NULL;
-       if (context && (context->class_inst || context->gmethod)) {
+       if (context && (context->class_inst || context->method_inst)) {
                MonoType *inflated = inflate_generic_type (t, context);
                if (inflated)
                        t = inflated;
        }
+       return t;
+}
+
+/**
+ * mono_class_create_from_typespec
+ * @image: context where the image is created
+ * @type_spec:  typespec token
+ * @context: the generic context used to evaluate generic instantiations in
+ */
+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);
+       if (!t)
+               return NULL;
        return mono_class_from_mono_type (t);
 }
 
@@ -3527,7 +3675,17 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
                (eclass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
        class->parent = parent;
        class->instance_size = mono_class_instance_size (class->parent);
-       class->sizes.element_size = mono_class_array_element_size (eclass);
+
+       if (eclass->enumtype && !eclass->enum_basetype) {
+               if (!eclass->reflection_info || eclass->wastypebuilder) {
+                       g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
+                       g_assert (eclass->reflection_info && !eclass->wastypebuilder);
+               }
+               /* element_size -1 is ok as this is not an instantitable type*/
+               class->sizes.element_size = -1;
+       } else
+               class->sizes.element_size = mono_class_array_element_size (eclass);
+
        mono_class_setup_supertypes (class);
 
        if (mono_defaults.generic_ilist_class) {
@@ -3559,10 +3717,10 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
                        class->interface_count = eclass->idepth + eclass->interface_count;
                }
 
-               class->interfaces = g_new0 (MonoClass *, class->interface_count);
+               class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
 
                for (i = 0; i < class->interface_count; i++) {
-                       MonoType *inflated, **args;
+                       MonoType *args [1];
                        MonoClass *iface;
 
                        if (eclass->valuetype)
@@ -3581,13 +3739,10 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
                                        iface = eclass->interfaces [i - eclass->idepth];
                        }
 
-                       args = g_new0 (MonoType *, 1);
                        args [0] = &iface->byval_arg;
 
-                       inflated = mono_class_bind_generic_parameters (
-                               &mono_defaults.generic_ilist_class->byval_arg, 1, args);
-
-                       class->interfaces [i] = mono_class_from_mono_type (inflated);
+                       class->interfaces [i] = mono_class_bind_generic_parameters (
+                               mono_defaults.generic_ilist_class, 1, args, FALSE);
                }
        }
 
@@ -3995,7 +4150,7 @@ mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *c
        MonoClass *class = NULL;
 
        if (image->dynamic)
-               return mono_lookup_dynamic_token (image, type_token);
+               return mono_lookup_dynamic_token (image, type_token, context);
 
        switch (type_token & 0xff000000){
        case MONO_TOKEN_TYPE_DEF:
@@ -4021,6 +4176,43 @@ mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *c
        return class;
 }
 
+
+/**
+ * mono_type_get_full:
+ * @image: the image where the type resides
+ * @type_token: the token for the type
+ * @context: the generic context used to evaluate generic instantiations in
+ *
+ * This functions exists to fullfill the fact that sometimes it's desirable to have access to the 
+ * 
+ * Returns: the MonoType that represents @type_token in @image
+ */
+MonoType *
+mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
+{
+       MonoType *type = NULL;
+
+       //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
+       if (image->dynamic)
+               return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context));
+
+       if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
+               MonoClass *class = mono_class_get_full (image, type_token, context);
+               return class ? mono_class_get_type (class) : NULL;
+       }
+
+       type = mono_type_retrieve_from_typespec (image, type_token, context);
+
+       if (!type) {
+               char *name = mono_class_name_from_token (image, type_token);
+               char *assembly = mono_assembly_name_from_token (image, type_token);
+               mono_loader_set_error_type_load (name, assembly);
+       }
+
+       return type;
+}
+
+
 MonoClass *
 mono_class_get (MonoImage *image, guint32 type_token)
 {
@@ -4334,8 +4526,7 @@ mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
 {
        g_assert (klassc->idepth > 0);
        if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
-               if ((klassc->interface_id <= klass->max_interface_id) &&
-                       (klass->interface_offsets [klassc->interface_id] >= 0))
+               if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
                        return TRUE;
        } else if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && MONO_CLASS_IS_INTERFACE (klass)) {
                int i;
@@ -4360,6 +4551,24 @@ mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
        return FALSE;
 }
 
+static gboolean
+mono_class_has_variant_generic_params (MonoClass *klass)
+{
+       int i;
+       MonoGenericContainer *container;
+
+       if (!klass->generic_class)
+               return FALSE;
+
+       container = klass->generic_class->container_class->generic_container;
+
+       for (i = 0; i < container->type_argc; ++i)
+               if (container->type_params [i].flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
+                       return TRUE;
+
+       return FALSE;
+}
+
 gboolean
 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
 {
@@ -4369,21 +4578,69 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
        if (!oklass->inited)
                mono_class_init (oklass);
 
+       if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
+               return klass == oklass;
+
        if (MONO_CLASS_IS_INTERFACE (klass)) {
                if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR))
                        return FALSE;
 
                /* interface_offsets might not be set for dynamic classes */
-               if (oklass->reflection_info && !oklass->interface_offsets)
+               if (oklass->reflection_info && !oklass->interface_bitmap)
                        /* 
                         * oklass might be a generic type parameter but they have 
                         * interface_offsets set.
                         */
                        return mono_reflection_call_is_assignable_to (oklass, klass);
 
-               if ((klass->interface_id <= oklass->max_interface_id) &&
-                   (oklass->interface_offsets [klass->interface_id] != -1))
+               if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
                        return TRUE;
+
+               if (mono_class_has_variant_generic_params (klass)) {
+                       if (oklass->generic_class) {
+                               int i;
+                               gboolean match = FALSE;
+                               MonoClass *container_class1 = klass->generic_class->container_class;
+                               MonoClass *container_class2 = oklass->generic_class->container_class;
+
+                               /* 
+                                * Check whenever the generic definition of oklass implements the 
+                                * generic definition of klass. The IMPLEMENTS_INTERFACE stuff is not usable
+                                * here since the relevant tables are not set up.
+                                */
+                               for (i = 0; i < container_class2->interface_offsets_count; ++i)
+                                       if ((container_class2->interfaces_packed [i] == container_class1) || (container_class2->interfaces_packed [i]->generic_class && (container_class2->interfaces_packed [i]->generic_class->container_class == container_class1)))
+                                               match = TRUE;
+
+                               if (match) {
+                                       MonoGenericContainer *container;
+
+                                       container = klass->generic_class->container_class->generic_container;
+
+                                       match = TRUE;
+                                       for (i = 0; i < container->type_argc; ++i) {
+                                               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]);
+
+                                               /*
+                                                * The _VARIANT and _COVARIANT constants should read _COVARIANT and
+                                                * _CONTRAVARIANT, but they are in a public header so we can't fix it.
+                                                */
+                                               if (param1_class != param2_class) {
+                                                       if ((container->type_params [i].flags & MONO_GEN_PARAM_VARIANT) && mono_class_is_assignable_from (param1_class, param2_class))
+                                                               ;
+                                                       else if (((container->type_params [i].flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
+                                                               ;
+                                                       else
+                                                               match = FALSE;
+                                               }
+                                       }
+
+                                       if (match)
+                                               return TRUE;
+                               }
+                       }
+               }
        } else if (klass->rank) {
                MonoClass *eclass, *eoclass;
 
@@ -4554,7 +4811,7 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
 {
        if (image->dynamic) {
                MonoClass *tmp_handle_class;
-               gpointer obj = mono_lookup_dynamic_token_class (image, token, &tmp_handle_class);
+               gpointer obj = mono_lookup_dynamic_token_class (image, token, &tmp_handle_class, context);
 
                g_assert (tmp_handle_class);
                if (handle_class)
@@ -4570,15 +4827,15 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
        case MONO_TOKEN_TYPE_DEF:
        case MONO_TOKEN_TYPE_REF:
        case MONO_TOKEN_TYPE_SPEC: {
-               MonoClass *class;
+               MonoType *type;
                if (handle_class)
                        *handle_class = mono_defaults.typehandle_class;
-               class = mono_class_get_full (image, token, context);
-               if (!class)
+               type = mono_type_get_full (image, token, context);
+               if (!type)
                        return NULL;
-               mono_class_init (class);
+               mono_class_init (mono_class_from_mono_type (type));
                /* We return a MonoType* as handle */
-               return &class->byval_arg;
+               return type;
        }
        case MONO_TOKEN_FIELD_DEF: {
                MonoClass *class;
@@ -4639,17 +4896,17 @@ mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
 }
 
 gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token)
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
 {
        MonoClass *handle_class;
 
-       return lookup_dynamic (image, token, &handle_class);
+       return lookup_dynamic (image, token, &handle_class, context);
 }
 
 gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class, MonoGenericContext *context)
 {
-       return lookup_dynamic (image, token, handle_class);
+       return lookup_dynamic (image, token, handle_class, context);
 }
 
 static MonoGetCachedClassInfo get_cached_class_info = NULL;
@@ -5488,6 +5745,30 @@ mono_class_get_exception_for_failure (MonoClass *klass)
                g_free (astr);
                return ex;
        }
+       case MONO_EXCEPTION_MISSING_METHOD: {
+               char *class_name = klass->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 *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 *assembly_name = msg_format + strlen (msg_format) + 1;
+               char *msg = g_strdup_printf (msg_format, assembly_name);
+               MonoException *ex;
+
+               ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), assembly_name));
+
+               g_free (msg);
+
+               return ex;
+       }
        default: {
                MonoLoaderError *error;
                MonoException *ex;
@@ -5503,3 +5784,198 @@ mono_class_get_exception_for_failure (MonoClass *klass)
        }
        }
 }
+
+static gboolean
+can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
+{
+       GSList *tmp;
+       if (accessing == accessed)
+               return TRUE;
+       if (!accessed || !accessing)
+               return FALSE;
+       for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
+               MonoAssemblyName *friend = tmp->data;
+               /* Be conservative with checks */
+               if (!friend->name)
+                       continue;
+               if (strcmp (accessing->aname.name, friend->name))
+                       continue;
+               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))
+                               continue;
+               }
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/*
+ * If klass is a generic type or if it is derived from a generic type, return the
+ * MonoClass of the generic definition
+ * Returns NULL if not found
+ */
+static MonoClass*
+get_generic_definition_class (MonoClass *klass)
+{
+       while (klass) {
+               if (klass->generic_class && klass->generic_class->container_class)
+                       return klass->generic_class->container_class;
+               klass = klass->parent;
+       }
+       return NULL;
+}
+
+/* FIXME: check visibility of type, too */
+static gboolean
+can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
+{
+       MonoClass *member_generic_def;
+       if (access_klass->generic_class && access_klass->generic_class->container_class && 
+                       (member_generic_def = get_generic_definition_class (member_klass))) {
+               if (can_access_member (access_klass->generic_class->container_class,
+                                      member_generic_def, access_level))
+                       return TRUE;
+       }
+
+       /* Partition I 8.5.3.2 */
+       /* the access level values are the same for fields and methods */
+       switch (access_level) {
+       case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
+               /* same compilation unit */
+               return access_klass->image == member_klass->image;
+       case FIELD_ATTRIBUTE_PRIVATE:
+               return access_klass == member_klass;
+       case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
+               if (mono_class_has_parent (access_klass, member_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))
+                       return TRUE;
+               return FALSE;
+       case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
+               if (mono_class_has_parent (access_klass, member_klass))
+                       return TRUE;
+               return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+       case FIELD_ATTRIBUTE_PUBLIC:
+               return TRUE;
+       }
+       return FALSE;
+}
+
+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);
+       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);
+                       if (can)
+                               return TRUE;
+                       nested = nested->nested_in;
+               }
+       }
+       return can;
+}
+
+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);
+       if (!can) {
+               MonoClass *nested = method->klass->nested_in;
+               while (nested) {
+                       can = can_access_member (nested, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+                       if (can)
+                               return TRUE;
+                       nested = nested->nested_in;
+               }
+       }
+       /* 
+        * FIXME:
+        * with generics calls to explicit interface implementations can be expressed
+        * directly: the method is private, but we must allow it. This may be opening
+        * a hole or the generics code should handle this differently.
+        * Maybe just ensure the interface type is public.
+        */
+       if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
+               return TRUE;
+       return can;
+}
+
+/**
+ * mono_type_is_valid_enum_basetype:
+ * @type: The MonoType to check
+ *
+ * Returns: TRUE if the type can be used as the basetype of an enum
+ */
+gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
+       switch (type->type) {
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_BOOLEAN:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+       case MONO_TYPE_CHAR:
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * mono_class_is_valid_enum:
+ * @klass: An enum class to be validated
+ *
+ * This method verify the required properties an enum should have.
+ *  
+ * Returns: TRUE if the informed enum class is valid 
+ *
+ * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
+ * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
+ * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
+ */
+gboolean mono_class_is_valid_enum (MonoClass *klass) {
+       MonoClassField * field;
+       gpointer iter = NULL;
+       gboolean found_base_field = FALSE;
+
+       g_assert (klass->enumtype);
+       /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
+       if (!klass->parent || strcmp (klass->parent->name, "Enum") || strcmp (klass->parent->name_space, "System") ) {
+               return FALSE;
+       }
+
+       if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
+               return FALSE;
+
+       while ((field = mono_class_get_fields (klass, &iter))) {
+               if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+                       if (found_base_field)
+                               return FALSE;
+                       found_base_field = TRUE;
+                       if (!mono_type_is_valid_enum_basetype (field->type))
+                               return FALSE;
+               }
+       }
+
+       if (!found_base_field)
+               return FALSE;
+
+       if (klass->method.count > 0) 
+               return FALSE;
+
+       return TRUE;
+}