[reflection] Use coop handles for MonoMethod icalls (#4272)
[mono.git] / mono / metadata / class.c
index a332083ca1a6250ae7dded897b07f945c0395d5b..4cf5fcf45754804080565adb1ab40e4b2f8c377e 100644 (file)
@@ -48,8 +48,6 @@
 #include <mono/utils/bsearch.h>
 #include <mono/utils/checked-build.h>
 
-#define ENABLE_LAZY_ARRAY_IFACES TRUE
-
 MonoStats mono_stats;
 
 gboolean mono_print_vtable = FALSE;
@@ -1653,6 +1651,7 @@ static void
 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
 {
        if (cached_info) {
+               mono_loader_lock ();
                klass->instance_size = cached_info->instance_size;
                klass->sizes.class_size = cached_info->class_size;
                klass->packing_size = cached_info->packing_size;
@@ -1661,6 +1660,7 @@ init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
                klass->has_references = cached_info->has_references;
                klass->has_static_refs = cached_info->has_static_refs;
                klass->no_special_static_fields = cached_info->no_special_static_fields;
+               mono_loader_unlock ();
        }
        else {
                if (!klass->size_inited)
@@ -3079,282 +3079,6 @@ print_implemented_interfaces (MonoClass *klass)
        }
 }
 
-static MonoClass*
-inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
-{
-       MonoType *args [1];
-       args [0] = &arg0->byval_arg;
-
-       return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
-}
-
-static MonoClass*
-array_class_get_if_rank (MonoClass *klass, guint rank)
-{
-       return rank ? mono_array_class_get (klass, rank) : klass;
-}
-
-static void
-fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *eclass, int rank)
-{
-       valuetype_types [0] = eclass;
-       if (eclass == mono_defaults.int16_class)
-               valuetype_types [1] = mono_defaults.uint16_class;
-       else if (eclass == mono_defaults.uint16_class)
-               valuetype_types [1] = mono_defaults.int16_class;
-       else if (eclass == mono_defaults.int32_class)
-               valuetype_types [1] = mono_defaults.uint32_class;
-       else if (eclass == mono_defaults.uint32_class)
-               valuetype_types [1] = mono_defaults.int32_class;
-       else if (eclass == mono_defaults.int64_class)
-               valuetype_types [1] = mono_defaults.uint64_class;
-       else if (eclass == mono_defaults.uint64_class)
-               valuetype_types [1] = mono_defaults.int64_class;
-       else if (eclass == mono_defaults.byte_class)
-               valuetype_types [1] = mono_defaults.sbyte_class;
-       else if (eclass == mono_defaults.sbyte_class)
-               valuetype_types [1] = mono_defaults.byte_class;
-       else if (eclass->enumtype && mono_class_enum_basetype (eclass))
-               valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
-}
-
-static GENERATE_GET_CLASS_WITH_CACHE (generic_icollection, System.Collections.Generic, ICollection`1)
-static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerable, System.Collections.Generic, IEnumerable`1)
-static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerator, System.Collections.Generic, IEnumerator`1)
-static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlylist, System.Collections.Generic, IReadOnlyList`1)
-static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlycollection, System.Collections.Generic, IReadOnlyCollection`1)
-
-/* this won't be needed once bug #325495 is completely fixed
- * though we'll need something similar to know which interfaces to allow
- * in arrays when they'll be lazyly created
- * 
- * FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
- * MS returns diferrent types based on which instance is called. For example:
- *     object obj = new byte[10][];
- *     Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
- *     Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
- *     a != b ==> true
- * 
- * Fixing this should kill quite some code, save some bits and improve compatibility.
- */
-static MonoClass**
-get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator)
-{
-       MonoClass *eclass = klass->element_class;
-       MonoClass* generic_icollection_class;
-       MonoClass* generic_ienumerable_class;
-       MonoClass* generic_ienumerator_class;
-       MonoClass* generic_ireadonlylist_class;
-       MonoClass* generic_ireadonlycollection_class;
-       MonoClass *valuetype_types[2] = { NULL, NULL };
-       MonoClass **interfaces = NULL;
-       int i, nifaces, interface_count, real_count, original_rank;
-       int all_interfaces;
-       gboolean internal_enumerator;
-       gboolean eclass_is_valuetype;
-
-       if (!mono_defaults.generic_ilist_class || ENABLE_LAZY_ARRAY_IFACES) {
-               *num = 0;
-               return NULL;
-       }
-       internal_enumerator = FALSE;
-       eclass_is_valuetype = FALSE;
-       original_rank = eclass->rank;
-       if (klass->byval_arg.type != MONO_TYPE_SZARRAY) {
-               MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
-               if (gklass && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0)        {
-                       /*
-                        * For a Enumerator<T[]> we need to get the list of interfaces for T.
-                        */
-                       eclass = mono_class_from_mono_type (gklass->context.class_inst->type_argv [0]);
-                       original_rank = eclass->rank;
-                       if (!eclass->rank)
-                               eclass = eclass->element_class;
-                       internal_enumerator = TRUE;
-                       *is_enumerator = TRUE;
-               } else {
-                       *num = 0;
-                       return NULL;
-               }
-       }
-
-       /* 
-        * with this non-lazy impl we can't implement all the interfaces so we do just the minimal stuff
-        * for deep levels of arrays of arrays (string[][] has all the interfaces, string[][][] doesn't)
-        */
-       all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
-
-       generic_icollection_class = mono_class_get_generic_icollection_class ();
-       generic_ienumerable_class = mono_class_get_generic_ienumerable_class ();
-       generic_ienumerator_class = mono_class_get_generic_ienumerator_class ();
-       generic_ireadonlylist_class = mono_class_get_generic_ireadonlylist_class ();
-       generic_ireadonlycollection_class = mono_class_get_generic_ireadonlycollection_class ();
-
-       mono_class_init (eclass);
-
-       /*
-        * Arrays in 2.0 need to implement a number of generic interfaces
-        * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
-        * on the element class). For net 4.5, we also need to implement IReadOnlyList`1/IReadOnlyCollection`1.
-        * We collect the types needed to build the
-        * instantiations in interfaces at intervals of 3/5, because 3/5 are
-        * the generic interfaces needed to implement.
-        *
-        * On 4.5, as an optimization, we don't expand ref classes for the variant generic interfaces
-        * (IEnumerator, IReadOnlyList and IReadOnlyColleciton). The regular dispatch code can handle those cases.
-        */
-       if (eclass->valuetype) {
-               nifaces = generic_ireadonlylist_class ? 5 : 3;
-               fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank);
-
-               /* IList, ICollection, IEnumerable, IReadOnlyList`1 */
-               real_count = interface_count = valuetype_types [1] ? (nifaces * 2) : nifaces;
-               if (internal_enumerator) {
-                       ++real_count;
-                       if (valuetype_types [1])
-                               ++real_count;
-               }
-
-               interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count);
-               interfaces [0] = valuetype_types [0];
-               if (valuetype_types [1])
-                       interfaces [nifaces] = valuetype_types [1];
-
-               eclass_is_valuetype = TRUE;
-       } else {
-               int j;
-               int idepth = eclass->idepth;
-               if (!internal_enumerator)
-                       idepth--;
-               nifaces = generic_ireadonlylist_class ? 2 : 3;
-
-               // FIXME: This doesn't seem to work/required for generic params
-               if (!(eclass->this_arg.type == MONO_TYPE_VAR || eclass->this_arg.type == MONO_TYPE_MVAR || (image_is_dynamic (eclass->image) && !eclass->wastypebuilder)))
-                       mono_class_setup_interface_offsets (eclass);
-
-               interface_count = all_interfaces? eclass->interface_offsets_count: eclass->interface_count;
-               /* we add object for interfaces and the supertypes for the other
-                * types. The last of the supertypes is the element class itself which we
-                * already created the explicit interfaces for (so we include it for IEnumerator
-                * and exclude it for arrays).
-                */
-               if (MONO_CLASS_IS_INTERFACE (eclass))
-                       interface_count++;
-               else
-                       interface_count += idepth;
-               if (eclass->rank && eclass->element_class->valuetype) {
-                       fill_valuetype_array_derived_types (valuetype_types, eclass->element_class, original_rank);
-                       if (valuetype_types [1])
-                               ++interface_count;
-               }
-               /* IList, ICollection, IEnumerable, IReadOnlyList */
-               interface_count *= nifaces;
-               real_count = interface_count;
-               if (internal_enumerator) {
-                       real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count;
-                       if (valuetype_types [1])
-                               ++real_count;
-               }
-               interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count);
-               if (MONO_CLASS_IS_INTERFACE (eclass)) {
-                       interfaces [0] = mono_defaults.object_class;
-                       j = nifaces;
-               } else {
-                       j = 0;
-                       for (i = 0; i < idepth; i++) {
-                               mono_class_init (eclass->supertypes [i]);
-                               interfaces [j] = eclass->supertypes [i];
-                               j += nifaces;
-                       }
-               }
-               if (all_interfaces) {
-                       for (i = 0; i < eclass->interface_offsets_count; i++) {
-                               interfaces [j] = eclass->interfaces_packed [i];
-                               j += nifaces;
-                       }
-               } else {
-                       for (i = 0; i < eclass->interface_count; i++) {
-                               interfaces [j] = eclass->interfaces [i];
-                               j += nifaces;
-                       }
-               }
-               if (valuetype_types [1]) {
-                       interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank);
-                       j += nifaces;
-               }
-       }
-
-       /* instantiate the generic interfaces */
-       for (i = 0; i < interface_count; i += nifaces) {
-               MonoClass *iface = interfaces [i];
-
-               interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface);
-               interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface);
-
-               if (eclass->valuetype) {
-                       interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
-                       if (generic_ireadonlylist_class) {
-                               interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface);
-                               interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface);
-                       }
-               } else {
-                       if (!generic_ireadonlylist_class)
-                               interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
-               }
-       }
-       if (internal_enumerator) {
-               int j;
-               /* instantiate IEnumerator<iface> */
-               for (i = 0; i < interface_count; i++) {
-                       interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]);
-               }
-               j = interface_count;
-               if (!eclass_is_valuetype) {
-                       if (MONO_CLASS_IS_INTERFACE (eclass)) {
-                               interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, mono_defaults.object_class);
-                               j ++;
-                       } else {
-                               for (i = 0; i < eclass->idepth; i++) {
-                                       interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->supertypes [i]);
-                                       j ++;
-                               }
-                       }
-                       for (i = 0; i < eclass->interface_offsets_count; i++) {
-                               interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->interfaces_packed [i]);
-                               j ++;
-                       }
-               } else {
-                       interfaces [j++] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [0], original_rank));
-               }
-               if (valuetype_types [1])
-                       interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [1], original_rank));
-       }
-#if 0
-       {
-       char *type_name = mono_type_get_name_full (&klass->byval_arg, 0);
-       for (i = 0; i  < real_count; ++i) {
-               char *name = mono_type_get_name_full (&interfaces [i]->byval_arg, 0);
-               g_print ("%s implements %s\n", type_name, name);
-               g_free (name);
-       }
-       g_free (type_name);
-       }
-#endif
-       *num = real_count;
-       return interfaces;
-}
-
-static int
-find_array_interface (MonoClass *klass, const char *name)
-{
-       int i;
-       for (i = 0; i < klass->interface_count; ++i) {
-               if (strcmp (klass->interfaces [i]->name, name) == 0)
-                       return i;
-       }
-       return -1;
-}
-
 /*
  * Return the number of virtual methods.
  * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
@@ -3414,15 +3138,6 @@ find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
        }
 }
 
-static int
-find_interface_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic)
-{
-       int i = find_interface (num_ifaces, interfaces_full, ic);
-       if (i >= 0)
-               return interface_offsets_full [i];
-       return -1;
-}
-
 static mono_bool
 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
 {
@@ -3572,23 +3287,14 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
        GPtrArray *ifaces;
        GPtrArray **ifaces_array = NULL;
        int interface_offsets_count;
-       MonoClass **array_interfaces = NULL;
-       int num_array_interfaces;
-       int is_enumerator = FALSE;
 
        mono_loader_lock ();
 
        mono_class_setup_supertypes (klass);
-       /* 
-        * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
-        * implicit interfaces have the property that they are assigned the same slot in the
-        * vtables for compatible interfaces
-        */
-       array_interfaces = get_implicit_generic_array_interfaces (klass, &num_array_interfaces, &is_enumerator);
 
        /* compute maximum number of slots and maximum interface id */
        max_iid = 0;
-       num_ifaces = num_array_interfaces; /* this can include duplicated ones */
+       num_ifaces = 0; /* this can include duplicated ones */
        ifaces_array = g_new0 (GPtrArray *, klass->idepth);
        for (j = 0; j < klass->idepth; j++) {
                k = klass->supertypes [j];
@@ -3622,13 +3328,6 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                }
        }
 
-       for (i = 0; i < num_array_interfaces; ++i) {
-               ic = array_interfaces [i];
-               mono_class_init (ic);
-               if (max_iid < ic->interface_id)
-                       max_iid = ic->interface_id;
-       }
-
        if (MONO_CLASS_IS_INTERFACE (klass)) {
                num_ifaces++;
                if (max_iid < klass->interface_id)
@@ -3683,55 +3382,6 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
        if (MONO_CLASS_IS_INTERFACE (klass))
                set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
 
-       if (num_array_interfaces) {
-               if (is_enumerator) {
-                       int ienumerator_idx = find_array_interface (klass, "IEnumerator`1");
-                       int ienumerator_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ienumerator_idx]);
-                       g_assert (ienumerator_offset >= 0);
-                       for (i = 0; i < num_array_interfaces; ++i) {
-                               ic = array_interfaces [i];
-                               if (strcmp (ic->name, "IEnumerator`1") == 0)
-                                       set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, ienumerator_offset, TRUE);
-                               else
-                                       g_assert_not_reached ();
-                               /*g_print ("type %s has %s offset at %d (%s)\n", klass->name, ic->name, interface_offsets_full [ic->interface_id], klass->interfaces [0]->name);*/
-                       }
-               } else {
-                       int ilist_offset, icollection_offset, ienumerable_offset, ireadonlylist_offset, ireadonlycollection_offset;
-                       int ilist_iface_idx = find_array_interface (klass, "IList`1");
-                       MonoClass* ilist_class = klass->interfaces [ilist_iface_idx];
-                       int ireadonlylist_iface_idx = find_array_interface (klass, "IReadOnlyList`1");
-                       MonoClass* ireadonlylist_class = ireadonlylist_iface_idx != -1 ? klass->interfaces [ireadonlylist_iface_idx] : NULL;
-                       int icollection_iface_idx = find_array_interface (ilist_class, "ICollection`1");
-                       int ienumerable_iface_idx = find_array_interface (ilist_class, "IEnumerable`1");
-                       int ireadonlycollection_iface_idx = ireadonlylist_iface_idx != -1 ? find_array_interface (ireadonlylist_class, "IReadOnlyCollection`1") : -1;
-                       ilist_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ilist_iface_idx]);
-                       icollection_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [icollection_iface_idx]);
-                       ienumerable_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [ienumerable_iface_idx]);
-                       ireadonlylist_offset = ireadonlylist_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ireadonlylist_iface_idx]) : -1;
-                       ireadonlycollection_offset = ireadonlycollection_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ireadonlylist_class->interfaces [ireadonlycollection_iface_idx]) : -1;
-                       g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
-                       for (i = 0; i < num_array_interfaces; ++i) {
-                               int offset;
-                               ic = array_interfaces [i];
-                               if (mono_class_get_generic_class (ic)->container_class == mono_defaults.generic_ilist_class)
-                                       offset = ilist_offset;
-                               else if (strcmp (ic->name, "ICollection`1") == 0)
-                                       offset = icollection_offset;
-                               else if (strcmp (ic->name, "IEnumerable`1") == 0)
-                                       offset = ienumerable_offset;
-                               else if (strcmp (ic->name, "IReadOnlyList`1") == 0)
-                                       offset = ireadonlylist_offset;
-                               else if (strcmp (ic->name, "IReadOnlyCollection`1") == 0)
-                                       offset = ireadonlycollection_offset;
-                               else
-                                       g_assert_not_reached ();
-                               set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, offset, TRUE);
-                               /*g_print ("type %s has %s offset at %d (%s)\n", klass->name, ic->name, offset, klass->interfaces [0]->name);*/
-                       }
-               }
-       }
-
        for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
                if (interface_offsets_full [i] != -1)
                        interface_offsets_count ++;
@@ -3767,8 +3417,6 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                        bitmap [id >> 3] |= (1 << (id & 7));
                        klass->interfaces_packed [i] = interfaces_full [i];
                        klass->interface_offsets_packed [i] = interface_offsets_full [i];
-                       /*if (num_array_interfaces)
-                         g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&klass->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/
                }
 #ifdef COMPRESSED_INTERFACE_BITMAP
                i = mono_compress_bitmap (NULL, bitmap, bsize);
@@ -3784,7 +3432,6 @@ end:
 
        g_free (interfaces_full);
        g_free (interface_offsets_full);
-       g_free (array_interfaces);
        for (i = 0; i < klass->idepth; i++) {
                ifaces = ifaces_array [i];
                if (ifaces)
@@ -4827,6 +4474,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
        g_slist_free (virt_methods);
        virt_methods = NULL;
 
+       g_assert (cur_slot <= max_vtsize);
+
        /* Ensure that all vtable slots are filled with concrete instance methods */
        if (!mono_class_is_abstract (klass)) {
                for (i = 0; i < cur_slot; ++i) {
@@ -5371,13 +5020,14 @@ mono_class_init (MonoClass *klass)
        init_list = g_slist_remove (init_list, klass);
        mono_native_tls_set_value (init_pending_tls_id, init_list);
 
-       /* Because of the double-checking locking pattern */
-       mono_memory_barrier ();
-       klass->inited = 1;
-
        if (locked)
                mono_loader_unlock ();
 
+       /* Leave this for last */
+       mono_loader_lock ();
+       klass->inited = 1;
+       mono_loader_unlock ();
+
        return !mono_class_has_failure (klass);
 }
 
@@ -5432,16 +5082,14 @@ mono_class_has_finalizer (MonoClass *klass)
                }
        }
 
-       mono_image_lock (klass->image);
-
+       mono_loader_lock ();
        if (!klass->has_finalize_inited) {
                klass->has_finalize = has_finalize ? 1 : 0;
 
                mono_memory_barrier ();
                klass->has_finalize_inited = TRUE;
        }
-
-       mono_image_unlock (klass->image);
+       mono_loader_unlock ();
 
        return klass->has_finalize;
 }
@@ -5576,8 +5224,22 @@ mono_class_setup_mono_type (MonoClass *klass)
                klass->this_arg.type = (MonoTypeEnum)t;
        }
 
-       if (MONO_CLASS_IS_INTERFACE (klass))
+       if (MONO_CLASS_IS_INTERFACE (klass)) {
                klass->interface_id = mono_get_unique_iid (klass);
+
+               if (is_corlib && !strcmp (nspace, "System.Collections.Generic")) {
+                       //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
+                   /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
+                   * MS returns diferrent types based on which instance is called. For example:
+                   *   object obj = new byte[10][];
+                   *   Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
+                   *   Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
+                   *   a != b ==> true
+                       */
+                       if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
+                               klass->is_array_special_interface = 1;
+               }
+       }
 }
 
 #ifndef DISABLE_COM
@@ -5916,6 +5578,42 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 #endif
 
        klass->cast_class = klass->element_class = klass;
+       if (mono_is_corlib_image (klass->image)) {
+               switch (klass->byval_arg.type) {
+                       case MONO_TYPE_I1:
+                               if (mono_defaults.byte_class)
+                                       klass->cast_class = mono_defaults.byte_class;
+                               break;
+                       case MONO_TYPE_U1:
+                               if (mono_defaults.sbyte_class)
+                                       mono_defaults.sbyte_class = klass;
+                               break;
+                       case MONO_TYPE_I2:
+                               if (mono_defaults.uint16_class)
+                                       mono_defaults.uint16_class = klass;
+                               break;
+                       case MONO_TYPE_U2:
+                               if (mono_defaults.int16_class)
+                                       klass->cast_class = mono_defaults.int16_class;
+                               break;
+                       case MONO_TYPE_I4:
+                               if (mono_defaults.uint32_class)
+                                       mono_defaults.uint32_class = klass;
+                               break;
+                       case MONO_TYPE_U4:
+                               if (mono_defaults.int32_class)
+                                       klass->cast_class = mono_defaults.int32_class;
+                               break;
+                       case MONO_TYPE_I8:
+                               if (mono_defaults.uint64_class)
+                                       mono_defaults.uint64_class = klass;
+                               break;
+                       case MONO_TYPE_U8:
+                               if (mono_defaults.int64_class)
+                                       klass->cast_class = mono_defaults.int64_class;
+                               break;
+               }
+       }
 
        if (!klass->enumtype) {
                if (!mono_metadata_interfaces_from_typedef_full (
@@ -6044,6 +5742,7 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
                        mono_error_cleanup (&error);
                }
        }
+       mono_loader_lock ();
        if (klass->parent)
                mono_class_setup_parent (klass, klass->parent);
 
@@ -6051,6 +5750,7 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
                klass->cast_class = gtd->cast_class;
                klass->element_class = gtd->element_class;
        }
+       mono_loader_unlock ();
 }
 
 gboolean
@@ -8586,7 +8286,7 @@ mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
 
                /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
                if (image_is_dynamic (candidate->image) && !candidate->wastypebuilder) {
-                       MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info (candidate);
+                       MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info_raw (candidate); /* FIXME use handles */
                        int j;
                        if (tb && tb->interfaces) {
                                for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
@@ -8707,9 +8407,14 @@ mono_class_get_cctor (MonoClass *klass)
                return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
        }
 
+       mono_class_init (klass);
+
        if (!klass->has_cctor)
                return NULL;
 
+       if (mono_class_is_ginst (klass) && !klass->methods)
+               return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class));
+
        if (mono_class_get_cached_class_info (klass, &cached_info)) {
                MonoError error;
                MonoMethod *result = mono_get_method_checked (klass->image, cached_info.cctor_token, klass, NULL, &error);
@@ -8718,9 +8423,6 @@ mono_class_get_cctor (MonoClass *klass)
                return result;
        }
 
-       if (mono_class_is_ginst (klass) && !klass->methods)
-               return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class));
-
        return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
 }
 
@@ -9515,8 +9217,12 @@ setup_nested_types (MonoClass *klass)
        if (klass->nested_classes_inited)
                return;
 
-       if (!klass->type_token)
+       if (!klass->type_token) {
+               mono_loader_lock ();
                klass->nested_classes_inited = TRUE;
+               mono_loader_unlock ();
+               return;
+       }
 
        i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
        classes = NULL;
@@ -10735,8 +10441,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
                interfaces = NULL;
        }
 
-       mono_image_lock (klass->image);
-
+       mono_loader_lock ();
        if (!klass->interfaces_inited) {
                klass->interface_count = interface_count;
                klass->interfaces = interfaces;
@@ -10745,8 +10450,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
 
                klass->interfaces_inited = TRUE;
        }
-
-       mono_image_unlock (klass->image);
+       mono_loader_unlock ();
 }
 
 static void
@@ -10827,7 +10531,6 @@ mono_field_resolve_flags (MonoClassField *field)
        MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
        int field_idx = field - klass->fields;
 
-
        if (gtd) {
                MonoClassField *gfield = &gtd->fields [field_idx];
                return mono_field_get_flags (gfield);
@@ -10891,3 +10594,156 @@ mono_class_full_name (MonoClass *klass)
 
 /* Declare all shared lazy type lookup functions */
 GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)
+
+/**
+ * mono_method_get_base_method:
+ * @method: a method
+ * @definition: if true, get the definition
+ * @error: set on failure
+ *
+ * Given a virtual method associated with a subclass, return the corresponding
+ * method from an ancestor.  If @definition is FALSE, returns the method in the
+ * superclass of the given method.  If @definition is TRUE, return the method
+ * in the ancestor class where it was first declared.  The type arguments will
+ * be inflated in the ancestor classes.  If the method is not associated with a
+ * class, or isn't virtual, returns the method itself.  On failure returns NULL
+ * and sets @error.
+ */
+MonoMethod*
+mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error)
+{
+       MonoClass *klass, *parent;
+       MonoGenericContext *generic_inst = NULL;
+       MonoMethod *result = NULL;
+       int slot;
+
+       if (method->klass == NULL)
+               return method;
+
+       if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
+           MONO_CLASS_IS_INTERFACE (method->klass) ||
+           method->flags & METHOD_ATTRIBUTE_NEW_SLOT)
+               return method;
+
+       slot = mono_method_get_vtable_slot (method);
+       if (slot == -1)
+               return method;
+
+       klass = method->klass;
+       if (mono_class_is_ginst (klass)) {
+               generic_inst = mono_class_get_context (klass);
+               klass = mono_class_get_generic_class (klass)->container_class;
+       }
+
+retry:
+       if (definition) {
+               /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */
+               for (parent = klass->parent; parent != NULL; parent = parent->parent) {
+                       /* on entry, klass is either a plain old non-generic class and generic_inst == NULL
+                          or klass is the generic container class and generic_inst is the instantiation.
+
+                          when we go to the parent, if the parent is an open constructed type, we need to
+                          replace the type parameters by the definitions from the generic_inst, and then take it
+                          apart again into the klass and the generic_inst.
+
+                          For cases like this:
+                          class C<T> : B<T, int> {
+                              public override void Foo () { ... }
+                          }
+                          class B<U,V> : A<HashMap<U,V>> {
+                              public override void Foo () { ... }
+                          }
+                          class A<X> {
+                              public virtual void Foo () { ... }
+                          }
+
+                          if at each iteration the parent isn't open, we can skip inflating it.  if at some
+                          iteration the parent isn't generic (after possible inflation), we set generic_inst to
+                          NULL;
+                       */
+                       MonoGenericContext *parent_inst = NULL;
+                       if (mono_class_is_open_constructed_type (mono_class_get_type (parent))) {
+                               parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error);
+                               return_val_if_nok  (error, NULL);
+                       }
+                       if (mono_class_is_ginst (parent)) {
+                               parent_inst = mono_class_get_context (parent);
+                               parent = mono_class_get_generic_class (parent)->container_class;
+                       }
+
+                       mono_class_setup_vtable (parent);
+                       if (parent->vtable_size <= slot)
+                               break;
+                       klass = parent;
+                       generic_inst = parent_inst;
+               }
+       } else {
+               klass = klass->parent;
+               if (!klass)
+                       return method;
+               if (mono_class_is_open_constructed_type (mono_class_get_type (klass))) {
+                       klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
+                       return_val_if_nok (error, NULL);
+
+                       generic_inst = NULL;
+               }
+               if (mono_class_is_ginst (klass)) {
+                       generic_inst = mono_class_get_context (klass);
+                       klass = mono_class_get_generic_class (klass)->container_class;
+               }
+
+       }
+
+       if (generic_inst) {
+               klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
+               return_val_if_nok (error, NULL);
+       }
+
+       if (klass == method->klass)
+               return method;
+
+       /*This is possible if definition == FALSE.
+        * Do it here to be really sure we don't read invalid memory.
+        */
+       if (slot >= klass->vtable_size)
+               return method;
+
+       mono_class_setup_vtable (klass);
+
+       result = klass->vtable [slot];
+       if (result == NULL) {
+               /* It is an abstract method */
+               gboolean found = FALSE;
+               gpointer iter = NULL;
+               while ((result = mono_class_get_methods (klass, &iter))) {
+                       if (result->slot == slot) {
+                               found = TRUE;
+                               break;
+                       }
+               }
+               /* found might be FALSE if we looked in an abstract class
+                * that doesn't override an abstract method of its
+                * parent: 
+                *   abstract class Base {
+                *     public abstract void Foo ();
+                *   }
+                *   abstract class Derived : Base { }
+                *   class Child : Derived {
+                *     public override void Foo () { }
+                *  }
+                *
+                *  if m was Child.Foo and we ask for the base method,
+                *  then we get here with klass == Derived and found == FALSE
+                */
+               /* but it shouldn't be the case that if we're looking
+                * for the definition and didn't find a result; the
+                * loop above should've taken us as far as we could
+                * go! */
+               g_assert (!(definition && !found));
+               if (!found)
+                       goto retry;
+       }
+
+       g_assert (result != NULL);
+       return result;
+}