Merge pull request #4418 from kumpera/fix_gclass_recording_on_failure
[mono.git] / mono / metadata / class.c
index 9cb77315a50c10eab8275e1ba75251bf1c13aae6..0d0952b0c9ff467bb054e8eec296a6571915db12 100644 (file)
@@ -69,7 +69,7 @@ static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedCl
 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
 static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
 static int generic_array_methods (MonoClass *klass);
-static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos);
+static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
 
 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
@@ -204,7 +204,7 @@ mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError
        MonoClass *res = NULL;
        MonoImage *module;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
                return NULL;
@@ -693,7 +693,7 @@ is_valid_generic_argument (MonoType *type)
 static MonoType*
 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
 {
-       mono_error_init (error);
+       error_init (error);
 
        switch (type->type) {
        case MONO_TYPE_MVAR: {
@@ -849,7 +849,7 @@ MonoType*
 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
 {
        MonoType *inflated = NULL;
-       mono_error_init (error);
+       error_init (error);
 
        if (context)
                inflated = inflate_generic_type (image, type, context, error);
@@ -921,7 +921,7 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG
 {
        MonoType *inflated = NULL; 
 
-       mono_error_init (error);
+       error_init (error);
        if (context) {
                inflated = inflate_generic_type (image, type, context, error);
                return_val_if_nok (error, NULL);
@@ -961,7 +961,7 @@ inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflat
        MonoGenericInst *method_inst = NULL;
        MonoGenericContext res = { NULL, NULL };
 
-       mono_error_init (error);
+       error_init (error);
 
        if (context->class_inst) {
                class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
@@ -1033,7 +1033,7 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
        MonoMethodSignature *sig;
        MonoGenericContext tmp_context;
 
-       mono_error_init (error);
+       error_init (error);
 
        /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
        while (method->is_inflated) {
@@ -1285,7 +1285,7 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
 
        g_assert (klass->enumtype);
 
-       mono_error_init (error);
+       error_init (error);
 
        container = mono_class_try_get_generic_container (klass);
        if (mono_class_is_ginst (klass)) {
@@ -1494,7 +1494,7 @@ mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoCla
 {
        if (mono_class_has_failure (caused_by)) {
                MonoError cause_error;
-               mono_error_init (&cause_error);
+               error_init (&cause_error);
                mono_error_set_for_class_failure (&cause_error, caused_by);
                mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (&cause_error));
                mono_error_cleanup (&cause_error);
@@ -1651,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;
@@ -1659,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)
@@ -1858,7 +1860,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
                                        mono_class_setup_fields (field_class);
                                        if (mono_class_has_failure (field_class)) {
                                                MonoError field_error;
-                                               mono_error_init (&field_error);
+                                               error_init (&field_error);
                                                mono_error_set_for_class_failure (&field_error, field_class);
                                                mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
                                                mono_error_cleanup (&field_error);
@@ -2361,8 +2363,10 @@ mono_class_setup_methods (MonoClass *klass)
                amethod = create_array_method (klass, "Set", sig);
                methods [method_num++] = amethod;
 
+               GHashTable *cache = g_hash_table_new (NULL, NULL);
                for (i = 0; i < klass->interface_count; i++)
-                       setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
+                       setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
+               g_hash_table_destroy (cache);
        } else if (mono_class_has_static_metadata (klass)) {
                MonoError error;
                int first_idx = mono_class_get_first_method_idx (klass);
@@ -2696,7 +2700,7 @@ mono_class_setup_events (MonoClass *klass)
                        MonoEvent *event = &events [i];
                        MonoEvent *gevent = &ginfo->events [i];
 
-                       mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok
+                       error_init (&error); //since we do conditional calls, we must ensure the default value is ok
 
                        event->parent = klass;
                        event->name = gevent->name;
@@ -3077,62 +3081,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)
-
-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.
@@ -3192,15 +3140,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)
 {
@@ -4805,7 +4744,7 @@ generic_array_methods (MonoClass *klass)
 }
 
 static void
-setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos)
+setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
 {
        MonoGenericContext tmp_context;
        int i;
@@ -4817,11 +4756,16 @@ setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **met
        for (i = 0; i < generic_array_method_num; i++) {
                MonoError error;
                MonoMethod *m = generic_array_method_info [i].array_method;
-               MonoMethod *inflated;
+               MonoMethod *inflated, *helper;
 
                inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, &error);
-               g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
-               methods [pos++] = mono_marshal_get_generic_array_helper (klass, iface, generic_array_method_info [i].name, inflated);
+               mono_error_assert_ok (&error);
+               helper = g_hash_table_lookup (cache, inflated);
+               if (!helper) {
+                       helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
+                       g_hash_table_insert (cache, inflated, helper);
+               }
+               methods [pos ++] = helper;
        }
 }
 
@@ -5145,16 +5089,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;
 }
@@ -5476,6 +5418,12 @@ mono_class_setup_supertypes (MonoClass *klass)
        mono_loader_unlock ();
 }
 
+static gboolean
+discard_gclass_due_to_failure (MonoClass *gclass, void *user_data)
+{
+       return mono_class_get_generic_class (gclass)->container_class == user_data;
+}
+
 static gboolean
 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
 {
@@ -5524,7 +5472,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        guint32 field_last, method_last;
        guint32 nesting_tokeen;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
                mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
@@ -5769,6 +5717,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        return klass;
 
 parent_failure:
+       if (mono_class_is_gtd (klass))
+               disable_gclass_recording (discard_gclass_due_to_failure, klass);
+
        mono_class_setup_mono_type (klass);
        mono_loader_unlock ();
        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
@@ -5807,6 +5758,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);
 
@@ -5814,6 +5766,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
@@ -6570,7 +6523,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
        if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
                /*Arrays of those two types are invalid.*/
                MonoError prepared_error;
-               mono_error_init (&prepared_error);
+               error_init (&prepared_error);
                mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
                mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
                mono_error_cleanup (&prepared_error);
@@ -7256,7 +7209,7 @@ mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_toke
 {
        MonoClass *klass;
 
-       mono_error_init (error);
+       error_init (error);
        klass = mono_class_get_checked (image, type_token, error);
 
        if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
@@ -7277,7 +7230,7 @@ mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
 {
        MonoClass *klass = NULL;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (image_is_dynamic (image)) {
                int table = mono_metadata_token_table (type_token);
@@ -7333,7 +7286,7 @@ mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext
        MonoType *type = NULL;
        gboolean inflated = FALSE;
 
-       mono_error_init (error);
+       error_init (error);
 
        //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
        if (image_is_dynamic (image)) {
@@ -7576,7 +7529,7 @@ mono_class_from_name_case_checked (MonoImage *image, const char *name_space, con
        const char *nspace;
        guint32 i, visib;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (image_is_dynamic (image)) {
                guint32 token = 0;
@@ -7658,7 +7611,7 @@ search_modules (MonoImage *image, const char *name_space, const char *name, Mono
        MonoClass *klass;
        int i;
 
-       mono_error_init (error);
+       error_init (error);
 
        /* 
         * The EXPORTEDTYPES table only contains public types, so have to search the
@@ -7694,7 +7647,7 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons
        char *nested;
        char buf [1024];
 
-       mono_error_init (error);
+       error_init (error);
 
        // Checking visited images avoids stack overflows when cyclic references exist.
        if (g_hash_table_lookup (visited_images, image))
@@ -8349,7 +8302,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) {
@@ -8628,7 +8581,7 @@ gpointer
 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
              MonoGenericContext *context, MonoError *error)
 {
-       mono_error_init (error);
+       error_init (error);
 
        if (image_is_dynamic (image)) {
                MonoClass *tmp_handle_class;
@@ -8718,7 +8671,7 @@ gpointer
 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
 {
        MonoClass *handle_class;
-       mono_error_init (error);
+       error_init (error);
        return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
 }
 
@@ -9280,8 +9233,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;
@@ -9427,7 +9384,7 @@ mono_field_get_type (MonoClassField *field)
 MonoType*
 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
 {
-       mono_error_init (error);
+       error_init (error);
        if (!field->type)
                mono_field_resolve_type (field, error);
        return field->type;
@@ -9836,7 +9793,7 @@ mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
        if (mono_class_has_failure (klass))
                return FALSE;
        
-       mono_error_init (&prepare_error);
+       error_init (&prepare_error);
        
        va_start (args, fmt);
        mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
@@ -9911,7 +9868,7 @@ mono_class_get_exception_for_failure (MonoClass *klass)
        if (!mono_class_has_failure (klass))
                return NULL;
        MonoError unboxed_error;
-       mono_error_init (&unboxed_error);
+       error_init (&unboxed_error);
        mono_error_set_for_class_failure (&unboxed_error, klass);
        return mono_error_convert_to_exception (&unboxed_error);
 }
@@ -10459,7 +10416,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
        int i, interface_count;
        MonoClass **interfaces;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (klass->interfaces_inited)
                return;
@@ -10468,14 +10425,13 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
                MonoType *args [1];
 
                /* generic IList, ICollection, IEnumerable */
-               interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
+               interface_count = 2;
                interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
 
                args [0] = &klass->element_class->byval_arg;
                interfaces [0] = mono_class_bind_generic_parameters (
                        mono_defaults.generic_ilist_class, 1, args, FALSE);
-               if (interface_count > 1)
-                       interfaces [1] = mono_class_bind_generic_parameters (
+               interfaces [1] = mono_class_bind_generic_parameters (
                           mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
        } else if (mono_class_is_ginst (klass)) {
                MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
@@ -10500,8 +10456,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;
@@ -10510,8 +10465,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
 
                klass->interfaces_inited = TRUE;
        }
-
-       mono_image_unlock (klass->image);
+       mono_loader_unlock ();
 }
 
 static void
@@ -10523,7 +10477,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error)
        MonoType *ftype;
        int field_idx = field - klass->fields;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (gtd) {
                MonoClassField *gfield = &gtd->fields [field_idx];
@@ -10592,7 +10546,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);
@@ -10655,4 +10608,157 @@ mono_class_full_name (MonoClass *klass)
 }
 
 /* Declare all shared lazy type lookup functions */
-GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)
+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;
+}