static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
static guint32 mono_field_resolve_flags (MonoClassField *field);
static void mono_class_setup_vtable_full (MonoClass *class, GList *in_setup);
+static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
+
+/*
+We use gclass recording to allow recursive system f types to be referenced by a parent.
+
+Given the following type hierarchy:
+
+class TextBox : TextBoxBase<TextBox> {}
+class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
+class TextInput<T> : Input<T> where T: TextInput<T> {}
+class Input<T> {}
+
+The runtime tries to load TextBoxBase<>.
+To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
+To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
+To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
+
+At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
+at this point, iow, both are registered in the type map and both and a NULL parent. This means
+that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
+
+To fix that what we do is to record all generic instantes created while resolving the parent of
+any generic type definition and, after resolved, correct the parent field if needed.
+
+*/
+static int record_gclass_instantiation;
+static GSList *gclass_recorded_list;
+typedef gboolean (*gclass_record_func) (MonoClass*, void*);
+
+/*
+ * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
+*/
+static void
+enable_gclass_recording (void)
+{
+ ++record_gclass_instantiation;
+}
+
+/*
+ * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
+*/
+static void
+disable_gclass_recording (gclass_record_func func, void *user_data)
+{
+ GSList **head = &gclass_recorded_list;
+
+ g_assert (record_gclass_instantiation > 0);
+ --record_gclass_instantiation;
+
+ while (*head) {
+ GSList *node = *head;
+ if (func ((MonoClass*)node->data, user_data)) {
+ *head = node->next;
+ g_slist_free_1 (node);
+ } else {
+ head = &node->next;
+ }
+ }
+
+ /* We automatically discard all recorded gclasses when disabled. */
+ if (!record_gclass_instantiation && gclass_recorded_list) {
+ g_slist_free (gclass_recorded_list);
+ gclass_recorded_list = NULL;
+ }
+}
+
/*
* mono_class_from_typeref:
* @image: a MonoImage
}
}
+/*
+This is a simple function to catch the most common bad instances of generic types.
+Specially those that might lead to further failures in the runtime.
+*/
+static gboolean
+is_valid_generic_argument (MonoType *type)
+{
+ switch (type->type) {
+ case MONO_TYPE_VOID:
+ case MONO_TYPE_TYPEDBYREF:
+ return FALSE;
+ }
+ return TRUE;
+}
+
static MonoType*
inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
{
return NULL;
}
+ if (!is_valid_generic_argument (inst->type_argv [num])) {
+ MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
+ mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
+ num, info ? info->name : "", inst->type_argv [num]->type);
+ return NULL;
+ }
/*
* Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
* while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
num, info ? info->name : "", inst->type_argc);
return NULL;
}
+ if (!is_valid_generic_argument (inst->type_argv [num])) {
+ MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
+ mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
+ num, info ? info->name : "", inst->type_argv [num]->type);
+ return NULL;
+ }
nt = mono_metadata_type_dup (image, inst->type_argv [num]);
nt->byref = type->byref;
nt->attrs = type->attrs;
*/
/* corlib is missing [StructLayout] directives in many places */
if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
- if (class->byval_arg.type != MONO_TYPE_VALUETYPE)
+ if (!class->valuetype)
gc_aware_layout = TRUE;
}
continue;
size = mono_type_size (field->type, &align);
+ align = class->packing_size ? MIN (class->packing_size, align): align;
class->min_align = MAX (align, class->min_align);
/*
real_size = MAX (real_size, size + field->offset);
}
class->instance_size = MAX (real_size, class->instance_size);
+ if (class->instance_size & (class->min_align - 1)) {
+ class->instance_size += class->min_align - 1;
+ class->instance_size &= ~(class->min_align - 1);
+ }
break;
}
}
+#ifndef DISABLE_COM
/*
* COM initialization (using mono_init_com_types) is delayed until needed.
* However when a [ComImport] attribute is present on a type it will trigger
/* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
mono_init_com_types ();
}
+#endif /*DISABLE_COM*/
/*
* LOCKING: this assumes the loader lock is held
if (!MONO_CLASS_IS_INTERFACE (class)) {
/* Imported COM Objects always derive from __ComObject. */
+#ifndef DISABLE_COM
if (MONO_CLASS_IS_IMPORT (class)) {
init_com_from_comimport (class);
if (parent == mono_defaults.object_class)
parent = mono_defaults.com_object_class;
}
+#endif
if (!parent) {
/* set the parent to something useful and safe, but mark the type as broken */
parent = mono_defaults.object_class;
/*class->enumtype = class->parent->enumtype; */
} else {
/* initialize com types if COM interfaces are present */
+#ifndef DISABLE_COM
if (MONO_CLASS_IS_IMPORT (class))
init_com_from_comimport (class);
+#endif
class->parent = NULL;
}
mono_atomic_store_release (&class->supertypes, supertypes);
}
+static gboolean
+fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
+{
+ MonoClass *gtd = (MonoClass*)user_data;
+ /* Only try to fix generic instances of @gtd */
+ if (gclass->generic_class->container_class != gtd)
+ return FALSE;
+
+ /* Check if the generic instance has no parent. */
+ if (gtd->parent && !gclass->parent)
+ mono_generic_class_setup_parent (gclass, gtd);
+
+ return TRUE;
+}
+
/**
* mono_class_create_from_typedef:
* @image: image where the token is valid
context = &class->generic_container->context;
}
+ if (class->generic_container)
+ enable_gclass_recording ();
+
if (cols [MONO_TYPEDEF_EXTENDS]) {
MonoClass *tmp;
guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
/* uses ->valuetype, which is initialized by mono_class_setup_parent above */
mono_class_setup_mono_type (class);
+ if (class->generic_container)
+ disable_gclass_recording (fix_gclass_incomplete_instantiation, class);
+
/*
* This might access class->byval_arg for recursion generated by generic constraints,
* so it has to come after setup_mono_type ().
return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
}
+static void
+mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
+{
+ if (gtd->parent) {
+ MonoError error;
+ MonoGenericClass *gclass = klass->generic_class;
+
+ klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
+ if (!mono_error_ok (&error)) {
+ /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
+ klass->parent = mono_defaults.object_class;
+ mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_error_cleanup (&error);
+ }
+ }
+ if (klass->parent)
+ mono_class_setup_parent (klass, klass->parent);
+
+ if (klass->enumtype) {
+ klass->cast_class = gtd->cast_class;
+ klass->element_class = gtd->element_class;
+ }
+}
+
+
/*
* Create the `MonoClass' for an instantiation of a generic type.
* We only do this if we actually need it.
gklass = gclass->container_class;
+ if (record_gclass_instantiation > 0)
+ gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
+
if (gklass->nested_in) {
/* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
klass->nested_in = gklass->nested_in;
* We use the generic type definition to look for nested classes.
*/
- if (gklass->parent) {
- MonoError error;
- klass->parent = mono_class_inflate_generic_class_checked (gklass->parent, mono_generic_class_get_context (gclass), &error);
- if (!mono_error_ok (&error)) {
- /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
- klass->parent = mono_defaults.object_class;
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- mono_error_cleanup (&error);
- }
- }
-
- if (klass->parent)
- mono_class_setup_parent (klass, klass->parent);
-
- if (klass->enumtype) {
- klass->cast_class = gklass->cast_class;
- klass->element_class = gklass->element_class;
- }
+ mono_generic_class_setup_parent (klass, gklass);
if (gclass->is_dynamic) {
klass->inited = 1;
static MonoClass *
get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
{
- int n = mono_generic_param_num (param);
+ int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
MonoImage *image = param->image;
GHashTable *ht;
static void
set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
{
- int n = mono_generic_param_num (param);
+ int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
MonoImage *image = param->image;
GHashTable *ht;