Merge pull request #495 from nicolas-raoul/fix-for-issue2907-with-no-formatting-changes
[mono.git] / mono / metadata / class.c
index 77b06b73025917807c7cc1d340a839a018364b27..6378847ba3a2e998f671ead8e91fd11819112c69 100644 (file)
@@ -6,6 +6,7 @@
  *
  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
  */
 #include <config.h>
 #ifdef HAVE_ALLOCA_H
@@ -42,6 +43,7 @@
 #include <mono/utils/mono-string.h>
 #include <mono/utils/mono-error-internals.h>
 #include <mono/utils/mono-logger-internal.h>
+#include <mono/utils/mono-memory-model.h>
 MonoStats mono_stats;
 
 gboolean mono_print_vtable = FALSE;
@@ -62,15 +64,80 @@ static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, Mono
 
 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
-static gboolean mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass);
 static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
 static guint32 mono_field_resolve_flags (MonoClassField *field);
 static void mono_class_setup_vtable_full (MonoClass *class, GList *in_setup);
+static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
 
 
 void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
 void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
 
+
+/*
+We use gclass recording to allow recursive system f types to be referenced by a parent.
+
+Given the following type hierarchy:
+
+class TextBox : TextBoxBase<TextBox> {}
+class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
+class TextInput<T> : Input<T> where T: TextInput<T> {}
+class Input<T> {}
+
+The runtime tries to load TextBoxBase<>.
+To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
+To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
+To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
+
+At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded 
+at this point, iow, both are registered in the type map and both and a NULL parent. This means
+that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
+
+To fix that what we do is to record all generic instantes created while resolving the parent of
+any generic type definition and, after resolved, correct the parent field if needed.
+
+*/
+static int record_gclass_instantiation;
+static GSList *gclass_recorded_list;
+typedef gboolean (*gclass_record_func) (MonoClass*, void*);
+
+/* 
+ * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
+*/
+static void
+enable_gclass_recording (void)
+{
+       ++record_gclass_instantiation;
+}
+
+/* 
+ * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
+*/
+static void
+disable_gclass_recording (gclass_record_func func, void *user_data)
+{
+       GSList **head = &gclass_recorded_list;
+
+       g_assert (record_gclass_instantiation > 0);
+       --record_gclass_instantiation;
+
+       while (*head) {
+               GSList *node = *head;
+               if (func ((MonoClass*)node->data, user_data)) {
+                       *head = node->next;
+                       g_slist_free_1 (node);
+               } else {
+                       head = &node->next;
+               }
+       }
+
+       /* We automatically discard all recorded gclasses when disabled. */
+       if (!record_gclass_instantiation && gclass_recorded_list) {
+               g_slist_free (gclass_recorded_list);
+               gclass_recorded_list = NULL;
+       }
+}
+
 /*
  * mono_class_from_typeref:
  * @image: a MonoImage
@@ -512,6 +579,21 @@ mono_class_is_open_constructed_type (MonoType *t)
        }
 }
 
+/*
+This is a simple function to catch the most common bad instances of generic types.
+Specially those that might lead to further failures in the runtime.
+*/
+static gboolean
+is_valid_generic_argument (MonoType *type)
+{
+       switch (type->type) {
+       case MONO_TYPE_VOID:
+       case MONO_TYPE_TYPEDBYREF:
+               return FALSE;
+       }
+       return TRUE;
+}
+
 static MonoType*
 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
 {
@@ -531,6 +613,12 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
                        return NULL;
                }
 
+               if (!is_valid_generic_argument (inst->type_argv [num])) {
+                       MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
+                       mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
+                               num, info ? info->name : "", inst->type_argv [num]->type);
+                       return NULL;                    
+               }
                /*
                 * Note that the VAR/MVAR cases are different from the rest.  The other cases duplicate @type,
                 * while the VAR/MVAR duplicates a type from the context.  So, we need to ensure that the
@@ -553,6 +641,12 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
                                num, info ? info->name : "", inst->type_argc);
                        return NULL;
                }
+               if (!is_valid_generic_argument (inst->type_argv [num])) {
+                       MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
+                       mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
+                               num, info ? info->name : "", inst->type_argv [num]->type);
+                       return NULL;                    
+               }
                nt = mono_metadata_type_dup (image, inst->type_argv [num]);
                nt->byref = type->byref;
                nt->attrs = type->attrs;
@@ -901,7 +995,16 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
                method = imethod->declaring;
        }
 
-       if (!method->is_generic && !method->klass->generic_container)
+       /*
+        * A method only needs to be inflated if the context has argument for which it is
+        * parametric. Eg:
+        * 
+        * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
+        * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
+        * 
+        */
+       if (!((method->is_generic && context->method_inst) || 
+               (method->klass->generic_container && context->class_inst)))
                return method;
 
        /*
@@ -1378,7 +1481,11 @@ mono_class_setup_fields (MonoClass *class)
        explicit_size = mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size);
 
        if (explicit_size) {
-               g_assert ((packing_size & 0xfffffff0) == 0);
+               if ((packing_size & 0xfffffff0) != 0) {
+                       char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 16", class->name, packing_size);
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+                       return;
+               }
                class->packing_size = packing_size;
                real_size += class->instance_size;
        }
@@ -1389,6 +1496,8 @@ mono_class_setup_fields (MonoClass *class)
                }
                class->size_inited = 1;
                class->blittable = blittable;
+               mono_memory_barrier ();
+               class->fields_inited = 1;
                return;
        }
 
@@ -1504,6 +1613,9 @@ mono_class_setup_fields (MonoClass *class)
        /*valuetypes can't be neither bigger than 1Mb or empty. */
        if (class->valuetype && (class->instance_size <= 0 || class->instance_size > (0x100000 + sizeof (MonoObject))))
                mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+
+       mono_memory_barrier ();
+       class->fields_inited = 1;
 }
 
 /** 
@@ -1513,9 +1625,12 @@ mono_class_setup_fields (MonoClass *class)
  * Initializes the class->fields array of fields.
  * Aquires the loader lock.
  */
-static void
+void
 mono_class_setup_fields_locking (MonoClass *class)
 {
+       /* This can be checked without locks */
+       if (class->fields_inited)
+               return;
        mono_loader_lock ();
        mono_class_setup_fields (class);
        mono_loader_unlock ();
@@ -1598,12 +1713,8 @@ mono_class_layout_fields (MonoClass *class)
         */
         /* corlib is missing [StructLayout] directives in many places */
        if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
-               if (class->image != mono_defaults.corlib &&
-                       class->byval_arg.type != MONO_TYPE_VALUETYPE)
+               if (!class->valuetype)
                        gc_aware_layout = TRUE;
-               /* from System.dll, used in metadata/process.h */
-               if (strcmp (class->name, "ProcessStartInfo") == 0)
-                       gc_aware_layout = FALSE;
        }
 
        /* Compute klass->has_references */
@@ -1668,10 +1779,16 @@ mono_class_layout_fields (MonoClass *class)
                if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
                        passes = 1;
 
-               if (class->parent)
+               if (class->parent) {
+                       mono_class_setup_fields (class->parent);
+                       if (class->parent->exception_type) {
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                               return;
+                       }
                        real_size = class->parent->instance_size;
-               else
+               } else {
                        real_size = sizeof (MonoObject);
+               }
 
                for (pass = 0; pass < passes; ++pass) {
                        for (i = 0; i < top; i++){
@@ -1753,6 +1870,7 @@ mono_class_layout_fields (MonoClass *class)
                                continue;
 
                        size = mono_type_size (field->type, &align);
+                       align = class->packing_size ? MIN (class->packing_size, align): align;
                        class->min_align = MAX (align, class->min_align);
 
                        /*
@@ -1776,6 +1894,10 @@ mono_class_layout_fields (MonoClass *class)
                        real_size = MAX (real_size, size + field->offset);
                }
                class->instance_size = MAX (real_size, class->instance_size);
+               if (class->instance_size & (class->min_align - 1)) {
+                       class->instance_size += class->min_align - 1;
+                       class->instance_size &= ~(class->min_align - 1);
+               }
                break;
        }
 
@@ -2392,6 +2514,16 @@ mono_unload_interface_ids (MonoBitSet *bitset)
        mono_loader_unlock ();
 }
 
+void
+mono_unload_interface_id (MonoClass *class)
+{
+       if (global_interface_bitset && class->interface_id) {
+               mono_loader_lock ();
+               mono_bitset_clear (global_interface_bitset, class->interface_id);
+               mono_loader_unlock ();
+       }
+}
+
 /*
  * mono_get_unique_iid:
  * @class: interface
@@ -2422,16 +2554,18 @@ mono_get_unique_iid (MonoClass *class)
        }
        mono_bitset_set (global_interface_bitset, iid);
        /* set the bit also in the per-image set */
-       if (class->image->interface_bitset) {
-               if (iid >= mono_bitset_size (class->image->interface_bitset)) {
-                       MonoBitSet *new_set = mono_bitset_clone (class->image->interface_bitset, iid + 1);
-                       mono_bitset_free (class->image->interface_bitset);
-                       class->image->interface_bitset = new_set;
+       if (!class->generic_class) {
+               if (class->image->interface_bitset) {
+                       if (iid >= mono_bitset_size (class->image->interface_bitset)) {
+                               MonoBitSet *new_set = mono_bitset_clone (class->image->interface_bitset, iid + 1);
+                               mono_bitset_free (class->image->interface_bitset);
+                               class->image->interface_bitset = new_set;
+                       }
+               } else {
+                       class->image->interface_bitset = mono_bitset_new (iid + 1, 0);
                }
-       } else {
-               class->image->interface_bitset = mono_bitset_new (iid + 1, 0);
+               mono_bitset_set (class->image->interface_bitset, iid);
        }
-       mono_bitset_set (class->image->interface_bitset, iid);
 
 #ifndef MONO_SMALL_CONFIG
        if (mono_print_vtable) {
@@ -2539,7 +2673,7 @@ mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gbo
                return -1;
 
        for (i = 0; i < klass->interface_offsets_count; i++) {
-               if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i])) {
+               if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i], FALSE)) {
                        *non_exact_match = TRUE;
                        return klass->interface_offsets_packed [i];
                }
@@ -2694,7 +2828,8 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume
                         */
                        eclass = mono_class_from_mono_type (class->generic_class->context.class_inst->type_argv [0]);
                        original_rank = eclass->rank;
-                       eclass = eclass->element_class;
+                       if (!eclass->rank)
+                               eclass = eclass->element_class;
                        internal_enumerator = TRUE;
                        *is_enumerator = TRUE;
                } else {
@@ -3070,7 +3205,7 @@ mono_class_interface_match (const uint8_t *bitmap, int id)
  * Return -1 on failure and set exception_type
  */
 static int
-setup_interface_offsets (MonoClass *class, int cur_slot)
+setup_interface_offsets (MonoClass *class, int cur_slot, gboolean overwrite)
 {
        MonoError error;
        MonoClass *k, *ic;
@@ -3237,10 +3372,14 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
        }
 
        /*
-        * We might get called twice: once from mono_class_init () then once from 
-        * mono_class_setup_vtable ().
+        * We might get called multiple times:
+        * - mono_class_init ()
+        * - mono_class_setup_vtable ().
+        * - mono_class_setup_interface_offsets ().
+        * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
+        * means we have to overwrite those when called from other places (#4440).
         */
-       if (class->interfaces_packed) {
+       if (class->interfaces_packed && !overwrite) {
                g_assert (class->interface_offsets_count == interface_offsets_count);
        } else {
                uint8_t *bitmap;
@@ -3305,7 +3444,7 @@ mono_class_setup_interface_offsets (MonoClass *class)
 {
        mono_loader_lock ();
 
-       setup_interface_offsets (class, 0);
+       setup_interface_offsets (class, 0, FALSE);
 
        mono_loader_unlock ();
 }
@@ -3525,6 +3664,18 @@ print_method_signatures (MonoMethod *im, MonoMethod *cm) {
 }
 
 #endif
+static gboolean
+is_wcf_hack_disabled (void)
+{
+       static gboolean disabled;
+       static gboolean inited = FALSE;
+       if (!inited) {
+               disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
+               inited = TRUE;
+       }
+       return disabled;
+}
+
 static gboolean
 check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty, gboolean security_enabled) {
        MonoMethodSignature *cmsig, *imsig;
@@ -3569,6 +3720,15 @@ check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *c
                if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
                        mono_security_core_clr_check_override (class, cm, im);
                TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
+               if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
+                       char *body_name = mono_method_full_name (cm, TRUE);
+                       char *decl_name = mono_method_full_name (im, TRUE);
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                       g_free (body_name);
+                       g_free (decl_name);
+                       return FALSE;
+               }
+
                return TRUE;
        } else {
                MonoClass *ic = im->klass;
@@ -3646,6 +3806,15 @@ check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *c
                        mono_security_core_clr_check_override (class, cm, im);
                
                TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
+               if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
+                       char *body_name = mono_method_full_name (cm, TRUE);
+                       char *decl_name = mono_method_full_name (im, TRUE);
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                       g_free (body_name);
+                       g_free (decl_name);
+                       return FALSE;
+               }
+               
                return TRUE;
        }
 }
@@ -3692,12 +3861,11 @@ print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_no
        }
        for (i = 0; i < size; ++i) {
                MonoMethod *cm = vtable [i];
-               if (cm) {
-                       char *cm_name = mono_method_full_name (cm, TRUE);
-                       char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
-                       printf ("  [%c][%03d][INDEX %03d] %s\n", newness, i, cm->slot, cm_name);
-                       g_free (cm_name);
-               }
+               char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
+               char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
+
+               printf ("  [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
+               g_free (cm_name);
        }
 
        g_free (full_name);
@@ -3790,6 +3958,14 @@ print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, Mono
        }
 }
 
+static MonoMethod*
+mono_method_get_method_definition (MonoMethod *method)
+{
+       while (method->is_inflated)
+               method = ((MonoMethodInflated*)method)->declaring;
+       return method;
+}
+
 static gboolean
 verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
 {
@@ -3824,6 +4000,18 @@ verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
                        mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type"));
                        return FALSE;
                }
+
+               body = mono_method_get_method_definition (body);
+               decl = mono_method_get_method_definition (decl);
+
+               if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
+                       char *body_name = mono_method_full_name (body, TRUE);
+                       char *decl_name = mono_method_full_name (decl, TRUE);
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                       g_free (body_name);
+                       g_free (decl_name);
+                       return FALSE;
+               }
        }
        return TRUE;
 }
@@ -3906,7 +4094,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
 
        /* printf ("METAINIT %s.%s\n", class->name_space, class->name); */
 
-       cur_slot = setup_interface_offsets (class, cur_slot);
+       cur_slot = setup_interface_offsets (class, cur_slot, TRUE);
        if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
                return;
 
@@ -4079,6 +4267,8 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                        if (im->flags & METHOD_ATTRIBUTE_STATIC)
                                continue;
 
+                       TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
+
                        // If there is an explicit implementation, just use it right away,
                        // otherwise look for a matching method
                        if (override_im == NULL) {
@@ -4203,9 +4393,21 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                if (slot == -1)
                                                        goto fail;
 
+                                               if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
+                                                       char *body_name = mono_method_full_name (cm, TRUE);
+                                                       char *decl_name = mono_method_full_name (m1, TRUE);
+                                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+                                                       g_free (body_name);
+                                                       g_free (decl_name);
+                                                       goto fail;
+                                               }
+
                                                g_assert (cm->slot < max_vtsize);
                                                if (!override_map)
                                                        override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
+                                               TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
+                                                       mono_method_full_name (m1, 1), m1,
+                                                       mono_method_full_name (cm, 1), cm));
                                                g_hash_table_insert (override_map, m1, cm);
                                                break;
                                        }
@@ -4240,6 +4442,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                        overrides [i * 2 + 1]->slot = decl->slot;
                        if (!override_map)
                                override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
+                       TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n", 
+                               mono_method_full_name (decl, 1), decl,
+                               mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
                        g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
 
                        if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
@@ -4252,9 +4457,13 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
         * overriden, then change the other occurances too.
         */
        if (override_map) {
+               MonoMethod *cm;
+
                for (i = 0; i < max_vtsize; ++i)
                        if (vtable [i]) {
-                               MonoMethod *cm = g_hash_table_lookup (override_map, vtable [i]);
+                               TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
+
+                               cm = g_hash_table_lookup (override_map, vtable [i]);
                                if (cm)
                                        vtable [i] = cm;
                        }
@@ -4817,9 +5026,9 @@ mono_class_init (MonoClass *class)
                first_iface_slot = class->parent->vtable_size;
                if (mono_class_need_stelemref_method (class))
                        ++first_iface_slot;
-               setup_interface_offsets (class, first_iface_slot);
+               setup_interface_offsets (class, first_iface_slot, TRUE);
        } else {
-               setup_interface_offsets (class, 0);
+               setup_interface_offsets (class, 0, TRUE);
        }
 
        if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
@@ -5046,6 +5255,7 @@ mono_class_setup_mono_type (MonoClass *class)
 
 }
 
+#ifndef DISABLE_COM
 /*
  * COM initialization (using mono_init_com_types) is delayed until needed. 
  * However when a [ComImport] attribute is present on a type it will trigger
@@ -5069,6 +5279,7 @@ init_com_from_comimport (MonoClass *class)
        /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
        mono_init_com_types ();
 }
+#endif /*DISABLE_COM*/
 
 /*
  * LOCKING: this assumes the loader lock is held
@@ -5095,11 +5306,13 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
 
        if (!MONO_CLASS_IS_INTERFACE (class)) {
                /* Imported COM Objects always derive from __ComObject. */
+#ifndef DISABLE_COM
                if (MONO_CLASS_IS_IMPORT (class)) {
                        init_com_from_comimport (class);
                        if (parent == mono_defaults.object_class)
                                parent = mono_defaults.com_object_class;
                }
+#endif
                if (!parent) {
                        /* set the parent to something useful and safe, but mark the type as broken */
                        parent = mono_defaults.object_class;
@@ -5143,11 +5356,12 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
                        class->valuetype = class->enumtype = 1;
                }
                /*class->enumtype = class->parent->enumtype; */
-               mono_class_setup_supertypes (class);
        } else {
                /* initialize com types if COM interfaces are present */
+#ifndef DISABLE_COM
                if (MONO_CLASS_IS_IMPORT (class))
                        init_com_from_comimport (class);
+#endif
                class->parent = NULL;
        }
 
@@ -5170,6 +5384,7 @@ void
 mono_class_setup_supertypes (MonoClass *class)
 {
        int ms;
+       MonoClass **supertypes;
 
        if (class->supertypes)
                return;
@@ -5182,14 +5397,31 @@ mono_class_setup_supertypes (MonoClass *class)
                class->idepth = 1;
 
        ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth);
-       class->supertypes = mono_class_alloc0 (class, sizeof (MonoClass *) * ms);
+       supertypes = mono_class_alloc0 (class, sizeof (MonoClass *) * ms);
 
        if (class->parent) {
-               class->supertypes [class->idepth - 1] = class;
-               memcpy (class->supertypes, class->parent->supertypes, class->parent->idepth * sizeof (gpointer));
+               supertypes [class->idepth - 1] = class;
+               memcpy (supertypes, class->parent->supertypes, class->parent->idepth * sizeof (gpointer));
        } else {
-               class->supertypes [0] = class;
+               supertypes [0] = class;
        }
+
+       mono_atomic_store_release (&class->supertypes, supertypes);
+}
+
+static gboolean
+fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
+{
+       MonoClass *gtd = (MonoClass*)user_data;
+       /* Only try to fix generic instances of @gtd */
+       if (gclass->generic_class->container_class != gtd)
+               return FALSE;
+
+       /* Check if the generic instance has no parent. */
+       if (gtd->parent && !gclass->parent)
+               mono_generic_class_setup_parent (gclass, gtd);
+
+       return TRUE;
 }
 
 /**
@@ -5257,6 +5489,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
                context = &class->generic_container->context;
        }
 
+       if (class->generic_container)
+               enable_gclass_recording ();
+
        if (cols [MONO_TYPEDEF_EXTENDS]) {
                MonoClass *tmp;
                guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
@@ -5294,6 +5529,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
        mono_class_setup_mono_type (class);
 
+       if (class->generic_container)
+               disable_gclass_recording (fix_gclass_incomplete_instantiation, class);
+
        /* 
         * This might access class->byval_arg for recursion generated by generic constraints,
         * so it has to come after setup_mono_type ().
@@ -5430,6 +5668,31 @@ mono_class_get_nullable_param (MonoClass *klass)
        return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
 }
 
+static void
+mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
+{
+       if (gtd->parent) {
+               MonoError error;
+               MonoGenericClass *gclass = klass->generic_class;
+
+               klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
+               if (!mono_error_ok (&error)) {
+                       /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
+                       klass->parent = mono_defaults.object_class;
+                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_error_cleanup (&error);
+               }
+       }
+       if (klass->parent)
+               mono_class_setup_parent (klass, klass->parent);
+
+       if (klass->enumtype) {
+               klass->cast_class = gtd->cast_class;
+               klass->element_class = gtd->element_class;
+       }
+}
+
+
 /*
  * Create the `MonoClass' for an instantiation of a generic type.
  * We only do this if we actually need it.
@@ -5439,17 +5702,22 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
 {
        MonoClass *klass, *gklass;
 
+       if (gclass->cached_class)
+               return gclass->cached_class;
+
        mono_loader_lock ();
        if (gclass->cached_class) {
                mono_loader_unlock ();
                return gclass->cached_class;
        }
 
-       gclass->cached_class = mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
-       klass = gclass->cached_class;
+       klass = mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
 
        gklass = gclass->container_class;
 
+       if (record_gclass_instantiation > 0)
+               gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
+
        if (gklass->nested_in) {
                /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
                klass->nested_in = gklass->nested_in;
@@ -5484,24 +5752,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
         * We use the generic type definition to look for nested classes.
         */
 
-       if (gklass->parent) {
-               MonoError error;
-               klass->parent = mono_class_inflate_generic_class_checked (gklass->parent, mono_generic_class_get_context (gclass), &error);
-               if (!mono_error_ok (&error)) {
-                       /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
-                       klass->parent = mono_defaults.object_class;
-                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-                       mono_error_cleanup (&error);
-               }
-       }
-
-       if (klass->parent)
-               mono_class_setup_parent (klass, klass->parent);
-
-       if (klass->enumtype) {
-               klass->cast_class = gklass->cast_class;
-               klass->element_class = gklass->element_class;
-       }
+       mono_generic_class_setup_parent (klass, gklass);
 
        if (gclass->is_dynamic) {
                klass->inited = 1;
@@ -5520,6 +5771,9 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
                }
        }
 
+       mono_memory_barrier ();
+       gclass->cached_class = klass;
+
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
 
        inflated_classes ++;
@@ -5614,47 +5868,72 @@ make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is
                if (klass->parent->exception_type)
                        mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
                else
-                       setup_interface_offsets (klass, klass->parent->vtable_size);
+                       setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
        }
 
        return klass;
 }
 
 #define FAST_CACHE_SIZE 16
-static MonoClass *var_cache_fast [FAST_CACHE_SIZE];
-static MonoClass *mvar_cache_fast [FAST_CACHE_SIZE];
-static GHashTable *var_cache_slow;
-static GHashTable *mvar_cache_slow;
 
 static MonoClass *
 get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
 {
-       int n = mono_generic_param_num (param);
+       int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
+       MonoImage *image = param->image;
        GHashTable *ht;
 
-       if (n < FAST_CACHE_SIZE)
-               return (is_mvar ? mvar_cache_fast : var_cache_fast) [n];
-       ht = is_mvar ? mvar_cache_slow : var_cache_slow;
-       return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
+       g_assert (image);
+
+       if (n < FAST_CACHE_SIZE) {
+               if (is_mvar)
+                       return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
+               else
+                       return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
+       } else {
+               ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
+               return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
+       }
 }
 
+/*
+ * LOCKING: Acquires the loader lock.
+ */
 static void
 set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
 {
-       int n = mono_generic_param_num (param);
+       int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
+       MonoImage *image = param->image;
        GHashTable *ht;
 
+       g_assert (image);
+
        if (n < FAST_CACHE_SIZE) {
-               (is_mvar ? mvar_cache_fast : var_cache_fast) [n] = klass;
+               if (is_mvar) {
+                       /* No locking needed */
+                       if (!image->mvar_cache_fast)
+                               image->mvar_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
+                       image->mvar_cache_fast [n] = klass;
+               } else {
+                       if (!image->var_cache_fast)
+                               image->var_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
+                       image->var_cache_fast [n] = klass;
+               }
                return;
        }
-       ht = is_mvar ? mvar_cache_slow : var_cache_slow;
+       ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
        if (!ht) {
-               ht = g_hash_table_new (NULL, NULL);
-               if (is_mvar)
-                       mvar_cache_slow = ht;
-               else
-                       var_cache_slow = ht;
+               mono_loader_lock ();
+               ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
+               if (!ht) {
+                       ht = g_hash_table_new (NULL, NULL);
+                       mono_memory_barrier ();
+                       if (is_mvar)
+                               image->mvar_cache_slow = ht;
+                       else
+                               image->var_cache_slow = ht;
+               }
+               mono_loader_unlock ();
        }
 
        g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
@@ -6357,10 +6636,10 @@ mono_class_get_field_token (MonoClassField *field)
        int i;
 
        mono_class_setup_fields_locking (klass);
-       if (klass->exception_type)
-               return 0;
 
        while (klass) {
+               if (!klass->fields)
+                       return 0;
                for (i = 0; i < klass->field.count; ++i) {
                        if (&klass->fields [i] == field) {
                                int idx = klass->field.first + i + 1;
@@ -6414,7 +6693,9 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ
                
        if (!klass->ext->field_def_values [field_index].data) {
                cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
-               g_assert (cindex);
+               if (!cindex)
+                       return NULL;
+
                g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
 
                mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
@@ -7137,7 +7418,6 @@ gboolean
 mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc, 
                           gboolean check_interfaces)
 {
-       g_assert (klassc->idepth > 0);
        if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
                if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
                        return TRUE;
@@ -7164,6 +7444,12 @@ mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
        return FALSE;
 }
 
+static gboolean
+mono_type_is_generic_argument (MonoType *type)
+{
+       return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
+}
+
 gboolean
 mono_class_has_variant_generic_params (MonoClass *klass)
 {
@@ -7182,6 +7468,26 @@ mono_class_has_variant_generic_params (MonoClass *klass)
        return FALSE;
 }
 
+static gboolean
+mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
+{
+       if (target == candidate)
+               return TRUE;
+
+       if (check_for_reference_conv &&
+               mono_type_is_generic_argument (&target->byval_arg) &&
+               mono_type_is_generic_argument (&candidate->byval_arg)) {
+               MonoGenericParam *gparam = candidate->byval_arg.data.generic_param;
+               MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
+
+               if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
+                       return FALSE;
+       }
+       if (!mono_class_is_assignable_from (target, candidate))
+               return FALSE;
+       return TRUE;
+}
+
 /**
  * @container the generic container from the GTD
  * @klass: the class to be assigned to
@@ -7190,16 +7496,19 @@ mono_class_has_variant_generic_params (MonoClass *klass)
  * Both klass and oklass must be instances of the same generic interface.
  * Return true if @klass can be assigned to a @klass variable
  */
-static gboolean
-mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass)
+gboolean
+mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
 {
        int j;
        MonoType **klass_argv, **oklass_argv;
        MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
        MonoGenericContainer *container = klass_gtd->generic_container;
 
+       if (klass == oklass)
+               return TRUE;
+
        /*Viable candidates are instances of the same generic interface*/
-       if (mono_class_get_generic_type_definition (oklass) != klass_gtd)
+       if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
                return FALSE;
 
        klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
@@ -7209,7 +7518,7 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass)
                MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
                MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
 
-               if (param1_class->valuetype != param2_class->valuetype)
+               if (param1_class->valuetype != param2_class->valuetype || (param1_class->valuetype && param1_class != param2_class))
                        return FALSE;
 
                /*
@@ -7218,10 +7527,10 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass)
                 */
                if (param1_class != param2_class) {
                        if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
-                               if (!mono_class_is_assignable_from (param1_class, param2_class))
+                               if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
                                        return FALSE;
                        } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
-                               if (!mono_class_is_assignable_from (param2_class, param1_class))
+                               if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
                                        return FALSE;
                        } else
                                return FALSE;
@@ -7230,6 +7539,107 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass)
        return TRUE;
 }
 
+static gboolean
+mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
+{
+       MonoGenericParam *gparam, *ogparam;
+       MonoGenericParamInfo *tinfo, *cinfo;
+       MonoClass **candidate_class;
+       gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
+       int tmask, cmask;
+
+       if (target == candidate)
+               return TRUE;
+       if (target->byval_arg.type != candidate->byval_arg.type)
+               return FALSE;
+
+       gparam = target->byval_arg.data.generic_param;
+       ogparam = candidate->byval_arg.data.generic_param;
+       tinfo = mono_generic_param_info (gparam);
+       cinfo = mono_generic_param_info (ogparam);
+
+       class_constraint_satisfied = FALSE;
+       valuetype_constraint_satisfied = FALSE;
+
+       /*candidate must have a super set of target's special constraints*/
+       tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
+       cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
+
+       if (cinfo->constraints) {
+               for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
+                       MonoClass *cc = *candidate_class;
+
+                       if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
+                               class_constraint_satisfied = TRUE;
+                       else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
+                               valuetype_constraint_satisfied = TRUE;
+               }
+       }
+       class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
+       valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
+
+       if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
+               return FALSE;
+       if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
+               return FALSE;
+       if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
+               valuetype_constraint_satisfied)) {
+               return FALSE;
+       }
+
+
+       /*candidate type constraints must be a superset of target's*/
+       if (tinfo->constraints) {
+               MonoClass **target_class;
+               for (target_class = tinfo->constraints; *target_class; ++target_class) {
+                       MonoClass *tc = *target_class;
+
+                       /*
+                        * A constraint from @target might inflate into @candidate itself and in that case we don't need
+                        * check it's constraints since it satisfy the constraint by itself.
+                        */
+                       if (mono_metadata_type_equal (&tc->byval_arg, &candidate->byval_arg))
+                               continue;
+
+                       if (!cinfo->constraints)
+                               return FALSE;
+
+                       for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
+                               MonoClass *cc = *candidate_class;
+
+                               if (mono_class_is_assignable_from (tc, cc))
+                                       break;
+
+                               /*
+                                * This happens when we have the following:
+                                *
+                                * Bar<K> where K : IFace
+                                * Foo<T, U> where T : U where U : IFace
+                                *      ...
+                                *      Bar<T> <- T here satisfy K constraint transitively through to U's constraint
+                                *
+                                */
+                               if (mono_type_is_generic_argument (&cc->byval_arg)) {
+                                       if (mono_gparam_is_assignable_from (target, cc))
+                                               break;
+                               }
+                       }
+                       if (!*candidate_class)
+                               return FALSE;
+               }
+       }
+
+       /*candidate itself must have a constraint that satisfy target*/
+       if (cinfo->constraints) {
+               for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
+                       MonoClass *cc = *candidate_class;
+                       if (mono_class_is_assignable_from (target, cc))
+                               return TRUE;
+               }
+       }
+       return FALSE;
+}
+
 /**
  * mono_class_is_assignable_from:
  * @klass: the class to be assigned to
@@ -7251,12 +7661,27 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
        if (klass->exception_type || oklass->exception_type)
                return FALSE;
 
-       if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
-               return klass == oklass;
+       if (mono_type_is_generic_argument (&klass->byval_arg)) {
+               if (!mono_type_is_generic_argument (&oklass->byval_arg))
+                       return FALSE;
+               return mono_gparam_is_assignable_from (klass, oklass);
+       }
 
        if (MONO_CLASS_IS_INTERFACE (klass)) {
-               if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR))
+               if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
+                       MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
+                       MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
+                       int i;
+
+                       if (constraints) {
+                               for (i = 0; constraints [i]; ++i) {
+                                       if (mono_class_is_assignable_from (klass, constraints [i]))
+                                               return TRUE;
+                               }
+                       }
+
                        return FALSE;
+               }
 
                /* interface_offsets might not be set for dynamic classes */
                if (oklass->ref_info_handle && !oklass->interface_bitmap)
@@ -7284,13 +7709,13 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                        for (i = 0; i < oklass->interface_offsets_count; ++i) {
                                MonoClass *iface = oklass->interfaces_packed [i];
 
-                               if (mono_class_is_variant_compatible (klass, iface))
+                               if (mono_class_is_variant_compatible (klass, iface, FALSE))
                                        return TRUE;
                        }
                }
                return FALSE;
        } else if (klass->delegate) {
-               if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass))
+               if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE))
                        return TRUE;
        }else if (klass->rank) {
                MonoClass *eclass, *eoclass;
@@ -7339,7 +7764,7 @@ mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
        MonoGenericContainer *container = klass_gtd->generic_container;
 
        /*Viable candidates are instances of the same generic interface*/
-       if (mono_class_get_generic_type_definition (oklass) != klass_gtd)
+       if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
                return FALSE;
 
        klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
@@ -7444,10 +7869,6 @@ mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
        if (target == mono_defaults.object_class)
                return TRUE;
 
-       /*setup_supertypes don't mono_class_init anything */
-       mono_class_setup_supertypes (candidate);
-       mono_class_setup_supertypes (target);
-
        if (mono_class_has_parent (candidate, target))
                return TRUE;
 
@@ -7456,10 +7877,10 @@ mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
                return mono_class_implement_interface_slow (target, candidate);
 
        if (target->delegate && mono_class_has_variant_generic_params (target))
-               return mono_class_is_variant_compatible (target, candidate);
+               return mono_class_is_variant_compatible (target, candidate, FALSE);
 
        /*FIXME properly handle nullables and arrays */
-
+       /*FIXME properly handle (M)VAR */
        return FALSE;
 }
 
@@ -8753,6 +9174,7 @@ mono_classes_cleanup (void)
 {
        if (global_interface_bitset)
                mono_bitset_free (global_interface_bitset);
+       global_interface_bitset = NULL;
 }
 
 /**
@@ -8871,7 +9293,8 @@ 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);
-       
+       mono_class_setup_supertypes (klass);
+
        for (i = 0; i < klass->idepth; ++i) {
                if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
                        return TRUE;
@@ -8992,6 +9415,9 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass)
 {
        int access_level;
 
+       if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
+               return TRUE;
+
        if (access_klass->element_class && !access_klass->enumtype)
                access_klass = access_klass->element_class;
 
@@ -9051,6 +9477,9 @@ static gboolean
 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
 {
        MonoClass *member_generic_def;
+       if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
+               return TRUE;
+
        if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
                                        access_klass->generic_container) && 
                        (member_generic_def = get_generic_definition_class (member_klass))) {