static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error);
-static gpointer mono_class_get_exception_data (const MonoClass *klass);
/*
enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
return_val_if_nok (error, NULL);
- MonoClassExt *ext = mono_class_get_ext (enclosing);
- if (enclosing->nested_classes_inited && ext) {
+ GList *nested_classes = mono_class_get_nested_classes_property (enclosing);
+ if (enclosing->nested_classes_inited && nested_classes) {
/* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
- for (tmp = ext->nested_classes; tmp; tmp = tmp->next) {
+ for (tmp = nested_classes; tmp; tmp = tmp->next) {
res = (MonoClass *)tmp->data;
if (strcmp (res->name, name) == 0)
return res;
mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
{
g_assert (mono_class_has_failure (klass));
- MonoErrorBoxed *box = (MonoErrorBoxed*)mono_class_get_exception_data (klass);
+ MonoErrorBoxed *box = mono_class_get_exception_data ((MonoClass*)klass);
mono_error_set_from_boxed (oerror, box);
}
-
/*
* mono_class_alloc:
*
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;
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)
MonoProperty *properties;
guint32 last;
int first, count;
+ MonoClassPropertyInfo *info;
- MonoClassExt *ext = mono_class_get_ext (klass);
- if (ext && ext->properties)
+ info = mono_class_get_property_info (klass);
+ if (info)
return;
if (mono_class_is_ginst (klass)) {
if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
return;
- MonoClassExt *gext = mono_class_get_ext (gklass);
- properties = mono_class_new0 (klass, MonoProperty, gext->property.count + 1);
+ MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
+ properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
- for (i = 0; i < gext->property.count; i++) {
+ for (i = 0; i < ginfo->count; i++) {
MonoError error;
MonoProperty *prop = &properties [i];
- *prop = gext->properties [i];
+ *prop = ginfo->properties [i];
if (prop->get)
prop->get = mono_class_inflate_generic_method_full_checked (
prop->parent = klass;
}
- first = gext->property.first;
- count = gext->property.count;
+ first = ginfo->first;
+ count = ginfo->count;
} else {
first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
count = last - first;
}
}
- mono_class_alloc_ext (klass);
- ext = mono_class_get_ext (klass);
-
- mono_image_lock (klass->image);
-
- if (ext->properties) {
- /* We leak 'properties' which was allocated from the image mempool */
- mono_image_unlock (klass->image);
- return;
- }
-
- ext->property.first = first;
- ext->property.count = count;
-
- /* Flush any pending writes as we do double checked locking on klass->ext->properties */
+ info = mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
+ info->first = first;
+ info->count = count;
+ info->properties = properties;
mono_memory_barrier ();
- /* Leave this assignment as the last op in the function */
- ext->properties = properties;
-
- mono_image_unlock (klass->image);
+ /* This might leak 'info' which was allocated from the image mempool */
+ mono_class_set_property_info (klass, info);
}
static MonoMethod**
guint32 last;
MonoEvent *events;
- MonoClassExt *ext = mono_class_get_ext (klass);
- if (ext && ext->events)
+ MonoClassEventInfo *info = mono_class_get_event_info (klass);
+ if (info)
return;
if (mono_class_is_ginst (klass)) {
if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
return;
- MonoClassExt *gext = mono_class_get_ext (gklass);
- first = gext->event.first;
- count = gext->event.count;
+ MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
+ first = ginfo->first;
+ count = ginfo->count;
events = mono_class_new0 (klass, MonoEvent, count);
for (i = 0; i < count; i++) {
MonoError error;
MonoEvent *event = &events [i];
- MonoEvent *gevent = &gext->events [i];
+ MonoEvent *gevent = &ginfo->events [i];
mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok
}
}
- mono_class_alloc_ext (klass);
- ext = mono_class_get_ext (klass);
-
- mono_image_lock (klass->image);
-
- if (ext->events) {
- mono_image_unlock (klass->image);
- return;
- }
-
- ext->event.first = first;
- ext->event.count = count;
+ info = mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
+ info->events = events;
+ info->first = first;
+ info->count = count;
- /* Flush any pending writes as we do double checked locking on klass->ext.events */
mono_memory_barrier ();
- /* Leave this assignment as the last op in the function */
- ext->events = events;
-
- mono_image_unlock (klass->image);
+ mono_class_set_event_info (klass, info);
}
/*
if (i >= 0)
return i;
+ if (itf->is_array_special_interface && klass->rank < 2) {
+ MonoClass *gtd = mono_class_get_generic_type_definition (itf);
+
+ for (i = 0; i < klass->interface_offsets_count; i++) {
+ // printf ("\t%s\n", mono_type_get_full_name (klass->interfaces_packed [i]));
+ if (mono_class_get_generic_type_definition (klass->interfaces_packed [i]) == gtd) {
+ *non_exact_match = TRUE;
+ return klass->interface_offsets_packed [i];
+ }
+ }
+ }
+
if (!mono_class_has_variant_generic_params (itf))
return -1;
}
}
-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) {
- *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.
}
}
-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)
{
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];
}
}
- 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)
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 ++;
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);
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)
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) {
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);
}
}
}
- 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;
}
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
#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 (
mono_error_cleanup (&error);
}
}
+ mono_loader_lock ();
if (klass->parent)
mono_class_setup_parent (klass, klass->parent);
klass->cast_class = gtd->cast_class;
klass->element_class = gtd->element_class;
}
+ mono_loader_unlock ();
}
gboolean
klass->enumtype = gklass->enumtype;
klass->valuetype = gklass->valuetype;
+
if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
g_assert (gclass->context.class_inst);
g_assert (gclass->context.class_inst->type_argc > 0);
if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
klass->simd_type = 1;
}
+ klass->is_array_special_interface = gklass->is_array_special_interface;
klass->cast_class = klass->element_class = klass;
guint32 constant_cols [MONO_CONSTANT_SIZE];
int field_index;
MonoClass *klass = field->parent;
+ MonoFieldDefaultValue *def_values;
g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
- MonoClassExt *ext = mono_class_get_ext (klass);
- if (!ext || !ext->field_def_values) {
- MonoFieldDefaultValue *def_values;
-
- mono_class_alloc_ext (klass);
- ext = mono_class_get_ext (klass);
-
+ def_values = mono_class_get_field_def_values (klass);
+ if (!def_values) {
def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
- mono_image_lock (klass->image);
- mono_memory_barrier ();
- if (!ext->field_def_values)
- ext->field_def_values = def_values;
- mono_image_unlock (klass->image);
+ mono_class_set_field_def_values (klass, def_values);
}
field_index = mono_field_get_index (field);
- if (!ext->field_def_values [field_index].data) {
+ if (!def_values [field_index].data) {
cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
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);
- ext->field_def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
- ext->field_def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
+ def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
+ mono_memory_barrier ();
+ def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
}
- *def_type = ext->field_def_values [field_index].def_type;
- return ext->field_def_values [field_index].data;
+ *def_type = def_values [field_index].def_type;
+ return def_values [field_index].data;
}
static int
mono_property_get_index (MonoProperty *prop)
{
- MonoClassExt *ext = mono_class_get_ext (prop->parent);
- int index = prop - ext->properties;
+ MonoClassPropertyInfo *info = mono_class_get_property_info (prop->parent);
+ int index = prop - info->properties;
- g_assert (index >= 0 && index < ext->property.count);
+ g_assert (index >= 0 && index < info->count);
return index;
}
*/
if (image_is_dynamic (klass->image)) {
- MonoClassExt *ext = mono_class_get_ext (klass);
+ MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
int prop_index = mono_property_get_index (property);
- if (ext->prop_def_values && ext->prop_def_values [prop_index].data) {
- *def_type = ext->prop_def_values [prop_index].def_type;
- return ext->prop_def_values [prop_index].data;
+ if (info->def_values && info->def_values [prop_index].data) {
+ *def_type = info->def_values [prop_index].def_type;
+ return info->def_values [prop_index].data;
}
return NULL;
}
int i;
while (klass) {
- MonoClassExt *ext = mono_class_get_ext (klass);
- if (ext) {
- for (i = 0; i < ext->event.count; ++i) {
- if (&ext->events [i] == event)
- return mono_metadata_make_token (MONO_TABLE_EVENT, ext->event.first + i + 1);
+ MonoClassEventInfo *info = mono_class_get_event_info (klass);
+ if (info) {
+ for (i = 0; i < info->count; ++i) {
+ if (&info->events [i] == event)
+ return mono_metadata_make_token (MONO_TABLE_EVENT, info->first + i + 1);
}
}
klass = klass->parent;
MonoProperty* p;
int i = 0;
gpointer iter = NULL;
- MonoClassExt *ext = mono_class_get_ext (klass);
+ MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
while ((p = mono_class_get_properties (klass, &iter))) {
- if (&ext->properties [i] == prop)
- return mono_metadata_make_token (MONO_TABLE_PROPERTY, ext->property.first + i + 1);
+ if (&info->properties [i] == prop)
+ return mono_metadata_make_token (MONO_TABLE_PROPERTY, info->first + i + 1);
i ++;
}
if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
return TRUE;
+ if (klass->is_array_special_interface && oklass->rank == 1) {
+ //XXX we could offset this by having the cast target computed at JIT time
+ //XXX we could go even further and emit a wrapper that would do the extra type check
+ MonoClass *iface_klass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
+ MonoClass *obj_klass = oklass->cast_class; //This gets us the cast class of element type of the array
+
+ // If the target we're trying to cast to is a valuetype, we must account of weird valuetype equivalences such as IntEnum <> int or uint <> int
+ // We can't apply it for ref types as this would go wrong with arrays - IList<byte[]> would have byte tested
+ if (iface_klass->valuetype)
+ iface_klass = iface_klass->cast_class;
+
+ //array covariant casts only operates on scalar to scalar
+ //This is so int[] can't be casted to IComparable<int>[]
+ if (!(obj_klass->valuetype && !iface_klass->valuetype) && mono_class_is_assignable_from (iface_klass, obj_klass))
+ return TRUE;
+ }
+
if (mono_class_has_variant_generic_params (klass)) {
int i;
mono_class_setup_interfaces (oklass, &error);
/*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) {
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);
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);
}
{
mono_class_setup_properties (klass);
- return mono_class_get_ext (klass)->property.count;
+ return mono_class_get_property_info (klass)->count;
}
/**
{
mono_class_setup_events (klass);
- return mono_class_get_ext (klass)->event.count;
+ return mono_class_get_event_info (klass)->count;
}
/**
return NULL;
if (!*iter) {
mono_class_setup_properties (klass);
- MonoClassExt *ext = mono_class_get_ext (klass);
+ MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
/* start from the first */
- if (ext->property.count) {
- *iter = &ext->properties [0];
+ if (info->count) {
+ *iter = &info->properties [0];
return (MonoProperty *)*iter;
} else {
/* no fields */
}
property = (MonoProperty *)*iter;
property++;
- MonoClassExt *ext = mono_class_get_ext (klass);
- if (property < &ext->properties [ext->property.count]) {
+ MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
+ if (property < &info->properties [info->count]) {
*iter = property;
return (MonoProperty *)*iter;
}
return NULL;
if (!*iter) {
mono_class_setup_events (klass);
- MonoClassExt *ext = mono_class_get_ext (klass);
+ MonoClassEventInfo *info = mono_class_get_event_info (klass);
/* start from the first */
- if (ext->event.count) {
- *iter = &ext->events [0];
+ if (info->count) {
+ *iter = &info->events [0];
return (MonoEvent *)*iter;
} else {
/* no fields */
}
event = (MonoEvent *)*iter;
event++;
- MonoClassExt *ext = mono_class_get_ext (klass);
- if (event < &ext->events [ext->event.count]) {
+ MonoClassEventInfo *info = mono_class_get_event_info (klass);
+ if (event < &info->events [info->count]) {
*iter = event;
return (MonoEvent *)*iter;
}
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;
i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
}
- mono_class_alloc_ext (klass);
-
nested_classes = NULL;
for (l = classes; l; l = l->next)
nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data);
g_list_free (classes);
- mono_image_lock (klass->image);
-
- mono_memory_barrier ();
+ mono_loader_lock ();
if (!klass->nested_classes_inited) {
- mono_class_get_ext (klass)->nested_classes = nested_classes;
+ mono_class_set_nested_classes_property (klass, nested_classes);
mono_memory_barrier ();
klass->nested_classes_inited = TRUE;
}
-
- mono_image_unlock (klass->image);
+ mono_loader_unlock ();
}
/**
setup_nested_types (klass);
if (!*iter) {
- MonoClassExt *ext = mono_class_get_ext (klass);
+ GList *nested_classes = mono_class_get_nested_classes_property (klass);
/* start from the first */
- if (ext && ext->nested_classes) {
- *iter = ext->nested_classes;
- return (MonoClass *)ext->nested_classes->data;
+ if (nested_classes) {
+ *iter = nested_classes;
+ return (MonoClass *)nested_classes->data;
} else {
/* no nested types */
return NULL;
guint32 rva;
int field_index;
MonoClass *klass = field->parent;
- MonoFieldDefaultValue *field_def_values;
+ MonoFieldDefaultValue *def_values;
g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
- MonoClassExt *ext = mono_class_get_ext (klass);
- if (!ext || !ext->field_def_values) {
- mono_class_alloc_ext (klass);
- ext = mono_class_get_ext (klass);
-
- field_def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
+ def_values = mono_class_get_field_def_values (klass);
+ if (!def_values) {
+ def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
- mono_image_lock (klass->image);
- if (!ext->field_def_values)
- ext->field_def_values = field_def_values;
- mono_image_unlock (klass->image);
+ mono_class_set_field_def_values (klass, def_values);
}
field_index = mono_field_get_index (field);
- if (!ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
+ if (!def_values [field_index].data && !image_is_dynamic (klass->image)) {
int first_field_idx = mono_class_get_first_field_idx (klass);
mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL);
if (!rva)
g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
- ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
+ def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
}
- return ext->field_def_values [field_index].data;
+ return def_values [field_index].data;
}
/**
mono_loader_lock ();
klass->has_failure = 1;
- mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, boxed_error);
+ mono_class_set_exception_data (klass, boxed_error);
mono_loader_unlock ();
return TRUE;
return mono_class_set_failure (klass, box);
}
-/*
- * mono_class_get_exception_data:
- *
- * Return the exception_data property of KLASS.
- *
- * LOCKING: Acquires the loader lock.
- */
-static gpointer
-mono_class_get_exception_data (const MonoClass *klass)
-{
- return mono_image_property_lookup (klass->image, (MonoClass*)klass, MONO_CLASS_PROP_EXCEPTION_DATA);
-}
-
/**
* mono_classes_init:
*
MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
mono_counters_register ("MonoClass size",
MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
- mono_counters_register ("MonoClassExt size",
- MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
-
- mono_counters_register ("MonoClassExt count",
- MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_count);
}
/**
mono_loader_unlock ();
}
-/*
- * mono_class_alloc_ext:
- *
- * Allocate klass->ext if not already done.
- */
-void
-mono_class_alloc_ext (MonoClass *klass)
-{
- MonoClassExt *ext;
-
- if (mono_class_get_ext (klass))
- return;
-
- ext = (MonoClassExt *)mono_class_alloc0 (klass, sizeof (MonoClassExt));
- mono_image_lock (klass->image);
- mono_memory_barrier ();
- if (!mono_class_get_ext (klass))
- mono_class_set_ext (klass, ext);
- class_ext_size += sizeof (MonoClassExt);
- ++class_ext_count;
- mono_image_unlock (klass->image);
-}
-
/*
* mono_class_setup_interfaces:
*
interfaces = NULL;
}
- mono_image_lock (klass->image);
-
+ mono_loader_lock ();
if (!klass->interfaces_inited) {
klass->interface_count = interface_count;
klass->interfaces = interfaces;
klass->interfaces_inited = TRUE;
}
-
- mono_image_unlock (klass->image);
+ mono_loader_unlock ();
}
static void
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 = >d->fields [field_idx];
return mono_field_get_flags (gfield);
/* 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;
+}