X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=042c869adccf3ee198a8e02451ca412ce496b3db;hb=4c960e1dd530396fdd9400c87729a6ce3101e5c1;hp=e0d517519ffa06a9cf64f8db2fdc7b500c3a7e85;hpb=5022f7de419a89ea5edf55c4155fd1b4a5d777a4;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index e0d517519ff..042c869adcc 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -54,8 +54,9 @@ gboolean mono_print_vtable = FALSE; gboolean mono_align_small_structs = FALSE; /* Statistics */ -guint32 inflated_classes, inflated_classes_size, inflated_methods_size; -guint32 classes_size, class_ext_size; +guint32 inflated_classes_size, inflated_methods_size; +guint32 classes_size, class_ext_size, class_ext_count; +guint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count; /* Low level lock which protects data structures in this module */ static mono_mutex_t classes_mutex; @@ -108,6 +109,11 @@ static int record_gclass_instantiation; static GSList *gclass_recorded_list; typedef gboolean (*gclass_record_func) (MonoClass*, void*); +/* This TLS variable points to a GSList of classes which have setup_fields () executing */ +static MonoNativeTlsKey setup_fields_tls_id; + +static MonoNativeTlsKey init_pending_tls_id; + static inline void classes_lock (void) { @@ -501,8 +507,8 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed, } if (is_recursed) break; - if (klass->generic_class) { - MonoGenericClass *gclass = klass->generic_class; + if (mono_class_is_ginst (klass)) { + MonoGenericClass *gclass = mono_class_get_generic_class (klass); MonoGenericInst *inst = gclass->context.class_inst; MonoTypeNameFormat nested_format; int i; @@ -531,7 +537,7 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed, g_string_append_c (str, '>'); else g_string_append_c (str, ']'); - } else if (klass->generic_container && + } else if (mono_class_is_gtd (klass) && (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) && (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) { int i; @@ -540,10 +546,10 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed, g_string_append_c (str, '<'); else g_string_append_c (str, '['); - for (i = 0; i < klass->generic_container->type_argc; i++) { + for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) { if (i) g_string_append_c (str, ','); - g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name); + g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name); } if (format == MONO_TYPE_NAME_FORMAT_IL) g_string_append_c (str, '>'); @@ -662,7 +668,7 @@ mono_class_is_open_constructed_type (MonoType *t) return t->data.generic_class->context.class_inst->is_open; case MONO_TYPE_CLASS: case MONO_TYPE_VALUETYPE: - return t->data.klass->generic_container != NULL; + return mono_class_is_gtd (t->data.klass); default: return FALSE; } @@ -785,7 +791,7 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont case MONO_TYPE_CLASS: case MONO_TYPE_VALUETYPE: { MonoClass *klass = type->data.klass; - MonoGenericContainer *container = klass->generic_container; + MonoGenericContainer *container = mono_class_try_get_generic_container (klass); MonoGenericInst *inst; MonoGenericClass *gclass = NULL; MonoType *nt; @@ -822,33 +828,8 @@ mono_generic_class_get_context (MonoGenericClass *gclass) MonoGenericContext * mono_class_get_context (MonoClass *klass) { - return klass->generic_class ? mono_generic_class_get_context (klass->generic_class) : NULL; -} - -/* - * mono_class_get_generic_container: - * - * Return the generic container of KLASS which should be a generic type definition. - */ -MonoGenericContainer* -mono_class_get_generic_container (MonoClass *klass) -{ - g_assert (klass->is_generic); - - return klass->generic_container; -} - -/* - * mono_class_get_generic_class: - * - * Return the MonoGenericClass of KLASS, which should be a generic instance. - */ -MonoGenericClass* -mono_class_get_generic_class (MonoClass *klass) -{ - g_assert (klass->is_inflated); - - return klass->generic_class; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + return gklass ? mono_generic_class_get_context (gklass) : NULL; } /* @@ -1079,7 +1060,7 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k * */ if (!((method->is_generic && context->method_inst) || - (method->klass->generic_container && context->class_inst))) + (mono_class_is_gtd (method->klass) && context->class_inst))) return method; iresult = g_new0 (MonoMethodInflated, 1); @@ -1090,14 +1071,12 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst; if (!context->class_inst) { - g_assert (!iresult->declaring->klass->generic_class); - if (iresult->declaring->klass->generic_container) - iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst; - else if (iresult->declaring->klass->generic_class) - iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst; + g_assert (!mono_class_is_ginst (iresult->declaring->klass)); + if (mono_class_is_gtd (iresult->declaring->klass)) + iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst; } /* This can happen with some callers like mono_object_get_virtual_method () */ - if (!iresult->declaring->klass->generic_container && !iresult->declaring->klass->generic_class) + if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass)) iresult->context.class_inst = NULL; MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult); @@ -1155,12 +1134,13 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k } } - if (!klass_hint || !klass_hint->generic_class || - klass_hint->generic_class->container_class != method->klass || - klass_hint->generic_class->context.class_inst != context->class_inst) - klass_hint = NULL; + if (klass_hint) { + MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint); + if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst)) + klass_hint = NULL; + } - if (method->klass->generic_container) + if (mono_class_is_gtd (method->klass)) result->klass = klass_hint; if (!result->klass) { @@ -1235,8 +1215,8 @@ mono_method_get_context_general (MonoMethod *method, gboolean uninflated) return NULL; if (method->is_generic) return &(mono_method_get_generic_container (method)->context); - if (method->klass->generic_container) - return &method->klass->generic_container->context; + if (mono_class_is_gtd (method->klass)) + return &mono_class_get_generic_container (method->klass)->context; return NULL; } @@ -1301,31 +1281,31 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error) MonoGenericContainer *container = NULL; MonoImage *m = klass->image; const int top = klass->field.count; - int i; + int i, first_field_idx; g_assert (klass->enumtype); mono_error_init (error); - if (klass->generic_container) - container = klass->generic_container; - else if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + container = mono_class_try_get_generic_container (klass); + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; - container = gklass->generic_container; + container = mono_class_get_generic_container (gklass); g_assert (container); } /* * Fetch all the field information. */ + first_field_idx = mono_class_get_first_field_idx (klass); for (i = 0; i < top; i++){ const char *sig; guint32 cols [MONO_FIELD_SIZE]; - int idx = klass->field.first + i; + int idx = first_field_idx + i; MonoType *ftype; - /* klass->field.first and idx points into the fieldptr table */ + /* first_field_idx and idx points into the fieldptr table */ mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE); if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields @@ -1348,7 +1328,7 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error) if (!ftype) goto fail; - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { //FIXME do we leak here? ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error); if (!mono_error_ok (error)) @@ -1402,8 +1382,9 @@ mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass) gpointer mono_class_alloc (MonoClass *klass, int size) { - if (klass->generic_class) - return mono_image_set_alloc (klass->generic_class->owner, size); + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + if (gklass) + return mono_image_set_alloc (gklass->owner, size); else return mono_image_alloc (klass->image, size); } @@ -1425,13 +1406,18 @@ mono_class_alloc0 (MonoClass *klass, int size) * mono_class_setup_basic_field_info: * @class: The class to initialize * - * Initializes the klass->fields. - * LOCKING: Assumes the loader lock is held. + * Initializes the following fields in MonoClass: + * * klass->fields (only field->parent and field->name) + * * klass->field.count + * * klass->first_field_idx + * LOCKING: Acquires the loader lock */ static void mono_class_setup_basic_field_info (MonoClass *klass) { + MonoGenericClass *gklass; MonoClassField *field; + MonoClassField *fields; MonoClass *gtd; MonoImage *image; int i, top; @@ -1439,11 +1425,12 @@ mono_class_setup_basic_field_info (MonoClass *klass) if (klass->fields) return; - gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL; + gklass = mono_class_try_get_generic_class (klass); + gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL; image = klass->image; - top = klass->field.count; - if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) { + + if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) { /* * This happens when a generic instance of an unfinished generic typebuilder * is used as an element type for creating an array type. We can't initialize @@ -1456,30 +1443,40 @@ mono_class_setup_basic_field_info (MonoClass *klass) if (gtd) { mono_class_setup_basic_field_info (gtd); - top = gtd->field.count; - klass->field.first = gtd->field.first; + mono_loader_lock (); klass->field.count = gtd->field.count; + mono_loader_unlock (); } - klass->fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top); + top = klass->field.count; + + fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top); /* * Fetch all the field information. */ - for (i = 0; i < top; i++){ - field = &klass->fields [i]; + int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0; + for (i = 0; i < top; i++) { + field = &fields [i]; field->parent = klass; if (gtd) { field->name = mono_field_get_name (>d->fields [i]); } else { - int idx = klass->field.first + i; - /* klass->field.first and idx points into the fieldptr table */ + int idx = first_field_idx + i; + /* first_field_idx and idx points into the fieldptr table */ guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME); /* The name is needed for fieldrefs */ field->name = mono_metadata_string_heap (image, name_idx); } } + + mono_memory_barrier (); + + mono_loader_lock (); + if (!klass->fields) + klass->fields = fields; + mono_loader_unlock (); } /** @@ -1511,77 +1508,38 @@ mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoCla /** * mono_class_setup_fields: - * @class: The class to initialize + * @klass: The class to initialize * - * Initializes the klass->fields. - * LOCKING: Assumes the loader lock is held. + * Initializes klass->fields, computes class layout and sizes. + * typebuilder_setup_fields () is the corresponding function for dynamic classes. + * Sets the following fields in @klass: + * - all the fields initialized by mono_class_init_sizes () + * - element_class/cast_class (for enums) + * - field->type/offset for all fields + * - fields_inited + * + * LOCKING: Acquires the loader lock. */ -static void +void mono_class_setup_fields (MonoClass *klass) { MonoError error; MonoImage *m = klass->image; int top; - guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK; - int i, blittable = TRUE; + guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK; + int i; guint32 real_size = 0; guint32 packing_size = 0; int instance_size; gboolean explicit_size; MonoClassField *field; - MonoGenericContainer *container = NULL; - MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL; - /* - * FIXME: We have a race condition here. It's possible that this function returns - * to its caller with `instance_size` set to `0` instead of the actual size. This - * is not a problem when the function is called recursively on the same class, - * because the size will be initialized by the outer invocation. What follows is a - * description of how it can occur in other cases, too. There it is a problem, - * because it can lead to the GC being asked to allocate an object of size `0`, - * which SGen chokes on. The race condition is triggered infrequently by - * `tests/sgen-suspend.cs`. - * - * This function is called for a class whenever one of its subclasses is inited. - * For example, it's called for every subclass of Object. What it does is this: - * - * if (klass->setup_fields_called) - * return; - * ... - * klass->instance_size = 0; - * ... - * klass->setup_fields_called = 1; - * ... critical point - * klass->instance_size = actual_instance_size; - * - * The last two steps are sometimes reversed, but that only changes the way in which - * the race condition works. - * - * Assume thread A goes through this function and makes it to the critical point. - * Now thread B runs the function and, since `setup_fields_called` is set, returns - * immediately, but `instance_size` is incorrect. - * - * The other case looks like this: - * - * if (klass->setup_fields_called) - * return; - * ... critical point X - * klass->instance_size = 0; - * ... critical point Y - * klass->instance_size = actual_instance_size; - * ... - * klass->setup_fields_called = 1; - * - * Assume thread A goes through the function and makes it to critical point X. Now - * thread B runs through the whole of the function, returning, assuming - * `instance_size` is set. At that point thread A gets to run and makes it to - * critical point Y, at which time `instance_size` is `0` again, invalidating thread - * B's assumption. - */ - if (klass->setup_fields_called) + if (klass->fields_inited) return; - if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) { + if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) { /* * This happens when a generic instance of an unfinished generic typebuilder * is used as an element type for creating an array type. We can't initialize @@ -1601,89 +1559,46 @@ mono_class_setup_fields (MonoClass *klass) } instance_size = 0; - if (!klass->rank) - klass->sizes.class_size = 0; - if (klass->parent) { /* For generic instances, klass->parent might not have been initialized */ mono_class_init (klass->parent); - if (!klass->parent->size_inited) { - mono_class_setup_fields (klass->parent); - if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class")) - return; - } - instance_size += klass->parent->instance_size; - klass->min_align = klass->parent->min_align; - /* we use |= since it may have been set already */ - klass->has_references |= klass->parent->has_references; - blittable = klass->parent->blittable; + mono_class_setup_fields (klass->parent); + if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class")) + return; + instance_size = klass->parent->instance_size; } else { instance_size = sizeof (MonoObject); - klass->min_align = 1; } - /* We can't really enable 16 bytes alignment until the GC supports it. - The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the - boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type. - Bug #506144 is an example of this issue. - - if (klass->simd_type) - klass->min_align = 16; - */ /* Get the real size */ explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size); + if (explicit_size) + instance_size += real_size; - if (explicit_size) { - if ((packing_size & 0xffffff00) != 0) { - mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size); - return; - } - klass->packing_size = packing_size; - real_size += instance_size; - } - - if (!top) { - if (explicit_size && real_size) { - instance_size = MAX (real_size, instance_size); - } - klass->blittable = blittable; - if (!klass->instance_size) - klass->instance_size = instance_size; - mono_memory_barrier (); - klass->size_inited = 1; - klass->fields_inited = 1; - klass->setup_fields_called = 1; + /* + * This function can recursively call itself. + * Prevent infinite recursion by using a list in TLS. + */ + GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id); + if (g_slist_find (init_list, klass)) return; - } - - if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType"))) - blittable = FALSE; - - /* Prevent infinite loops if the class references itself */ - klass->setup_fields_called = 1; - - if (klass->generic_container) { - container = klass->generic_container; - } else if (gtd) { - container = gtd->generic_container; - g_assert (container); - } + init_list = g_slist_prepend (init_list, klass); + mono_native_tls_set_value (setup_fields_tls_id, init_list); /* * Fetch all the field information. */ - for (i = 0; i < top; i++){ - int idx = klass->field.first + i; + int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0; + for (i = 0; i < top; i++) { + int idx = first_field_idx + i; field = &klass->fields [i]; - field->parent = klass; - if (!field->type) { mono_field_resolve_type (field, &error); if (!mono_error_ok (&error)) { /*mono_field_resolve_type already failed class*/ mono_error_cleanup (&error); - return; + break; } if (!field->type) g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name); @@ -1692,57 +1607,24 @@ mono_class_setup_fields (MonoClass *klass) if (mono_field_is_deleted (field)) continue; - if (gtd) { - MonoClassField *gfield = >d->fields [i]; - field->offset = gfield->offset; - } else { - if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) { - guint32 offset; - mono_metadata_field_info (m, idx, &offset, NULL, NULL); - field->offset = offset; + if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) { + guint32 uoffset; + mono_metadata_field_info (m, idx, &uoffset, NULL, NULL); + int offset = uoffset; - if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { - mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name); - break; - } - if (field->offset < -1) { /*-1 is used to encode special static fields */ - mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, field->offset); - break; - } - if (klass->generic_container) { - mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout."); - break; - } + if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { + mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name); + break; } - } - - /* Only do these checks if we still think this type is blittable */ - if (blittable && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { - if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) { - blittable = FALSE; - } else { - MonoClass *field_class = mono_class_from_mono_type (field->type); - if (field_class) { - mono_class_setup_fields (field_class); - if (mono_class_has_failure (field_class)) { - MonoError field_error; - mono_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); - break; - } - } - if (!field_class || !field_class->blittable) - blittable = FALSE; + if (offset < -1) { /*-1 is used to encode special static fields */ + mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset); + break; + } + if (mono_class_is_gtd (klass)) { + mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout."); + break; } } - - if (klass->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { - klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type); - blittable = klass->element_class->blittable; - } - if (mono_type_has_exceptions (field->type)) { char *class_name = mono_type_get_full_name (klass); char *type_name = mono_type_full_name (field->type); @@ -1756,66 +1638,58 @@ mono_class_setup_fields (MonoClass *klass) /* The def_value of fields is compute lazily during vtable creation */ } - if (klass == mono_defaults.string_class) - blittable = FALSE; + if (!mono_class_has_failure (klass)) + mono_class_layout_fields (klass, instance_size, packing_size, FALSE); - klass->blittable = blittable; + init_list = g_slist_remove (init_list, klass); + mono_native_tls_set_value (setup_fields_tls_id, init_list); +} - if (klass->enumtype && !mono_class_enum_basetype (klass)) { - mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid."); - return; +static void +init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info) +{ + if (cached_info) { + klass->instance_size = cached_info->instance_size; + klass->sizes.class_size = cached_info->class_size; + klass->packing_size = cached_info->packing_size; + klass->min_align = cached_info->min_align; + klass->blittable = cached_info->blittable; + 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; } - if (explicit_size && real_size) { - instance_size = MAX (real_size, instance_size); + else { + if (!klass->size_inited) + mono_class_setup_fields (klass); } - - if (mono_class_has_failure (klass)) - return; - mono_class_layout_fields (klass, instance_size); - - /*valuetypes can't be neither bigger than 1Mb or empty. */ - if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject)))) - mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size); - - mono_memory_barrier (); - klass->fields_inited = 1; } +/* -/** - * mono_class_setup_fields_locking: - * @class: The class to initialize + * mono_class_init_sizes: * - * Initializes the klass->fields array of fields. - * Aquires the loader lock. - */ -void -mono_class_setup_fields_locking (MonoClass *klass) -{ - /* This can be checked without locks */ - if (klass->fields_inited) - return; - mono_loader_lock (); - mono_class_setup_fields (klass); - mono_loader_unlock (); -} - -/* - * mono_class_has_references: + * Initializes the size related fields of @klass without loading all field data if possible. + * Sets the following fields in @klass: + * - instance_size + * - sizes.class_size + * - packing_size + * - min_align + * - blittable + * - has_references + * - has_static_refs + * - size_inited + * Can fail the class. * - * Returns whenever @klass->has_references is set, initializing it if needed. - * Aquires the loader lock. + * LOCKING: Acquires the loader lock. */ -static gboolean -mono_class_has_references (MonoClass *klass) +static void +mono_class_init_sizes (MonoClass *klass) { - if (klass->init_pending) { - /* Be conservative */ - return TRUE; - } else { - mono_class_init (klass); + MonoCachedClassInfo cached_info; + gboolean has_cached_info; - return klass->has_references; - } + has_cached_info = mono_class_get_cached_class_info (klass, &cached_info); + + init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL); } /* @@ -1835,16 +1709,29 @@ mono_type_get_basic_type_from_generic (MonoType *type) return type; } +static gboolean +class_has_references (MonoClass *klass) +{ + mono_class_init_sizes (klass); + + /* + * has_references is not set if this is called recursively, but this is not a problem since this is only used + * during field layout, and instance fields are initialized before static fields, and instance fields can't + * embed themselves. + */ + return klass->has_references; +} + static gboolean type_has_references (MonoClass *klass, MonoType *ftype) { - if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) + if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type (ftype))))) return TRUE; if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) { MonoGenericParam *gparam = ftype->data.generic_param; if (gparam->gshared_constraint) - return mono_class_has_references (mono_class_from_mono_type (gparam->gshared_constraint)); + return class_has_references (mono_class_from_mono_type (gparam->gshared_constraint)); } return FALSE; } @@ -1852,28 +1739,59 @@ type_has_references (MonoClass *klass, MonoType *ftype) /* * mono_class_layout_fields: * @class: a class - * @instance_size: base instance size + * @base_instance_size: base instance size + * @packing_size: * - * Compute the placement of fields inside an object or struct, according to - * the layout rules and set the following fields in @class: - * - has_references (if the class contains instance references firled or structs that contain references) - * - has_static_refs (same, but for static fields) - * - instance_size (size of the object in memory) - * - class_size (size needed for the static fields) - * - size_inited (flag set when the instance_size is set) + * This contains the common code for computing the layout of classes and sizes. + * This should only be called from mono_class_setup_fields () and + * typebuilder_setup_fields (). * - * LOCKING: this is supposed to be called with the loader lock held. + * LOCKING: Acquires the loader lock */ void -mono_class_layout_fields (MonoClass *klass, int instance_size) +mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre) { int i; const int top = klass->field.count; - guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK; + guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK; guint32 pass, passes, real_size; gboolean gc_aware_layout = FALSE; gboolean has_static_fields = FALSE; + gboolean has_references = FALSE; + gboolean has_static_refs = FALSE; MonoClassField *field; + gboolean blittable; + int instance_size = base_instance_size; + int class_size, min_align; + int *field_offsets; + + /* + * We want to avoid doing complicated work inside locks, so we compute all the required + * information and write it to @klass inside a lock. + */ + if (klass->fields_inited) + return; + + if ((packing_size & 0xffffff00) != 0) { + mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size); + return; + } + + if (klass->parent) { + min_align = klass->parent->min_align; + /* we use | since it may have been set already */ + has_references = klass->has_references | klass->parent->has_references; + } else { + min_align = 1; + } + /* We can't really enable 16 bytes alignment until the GC supports it. + The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the + boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type. + Bug #506144 is an example of this issue. + + if (klass->simd_type) + min_align = 16; + */ /* * When we do generic sharing we need to have layout @@ -1882,6 +1800,21 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) * container), so we don't return in that case anymore. */ + if (klass->enumtype) { + for (i = 0; i < top; i++) { + field = &klass->fields [i]; + if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { + klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type); + break; + } + } + + if (!mono_class_enum_basetype (klass)) { + mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid."); + return; + } + } + /* * Enable GC aware auto layout: in this mode, reference * fields are grouped together inside objects, increasing collector @@ -1897,59 +1830,73 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) gc_aware_layout = TRUE; } - /* Compute klass->has_references */ - /* - * Process non-static fields first, since static fields might recursively - * refer to the class itself. - */ + /* Compute klass->blittable */ + blittable = TRUE; + if (klass->parent) + blittable = klass->parent->blittable; + if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top) + blittable = FALSE; for (i = 0; i < top; i++) { - MonoType *ftype; - field = &klass->fields [i]; - if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { - ftype = mono_type_get_underlying_type (field->type); - ftype = mono_type_get_basic_type_from_generic (ftype); - if (type_has_references (klass, ftype)) - klass->has_references = TRUE; + if (mono_field_is_deleted (field)) + continue; + if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) + continue; + if (blittable) { + if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) { + blittable = FALSE; + } else { + MonoClass *field_class = mono_class_from_mono_type (field->type); + if (field_class) { + mono_class_setup_fields (field_class); + if (mono_class_has_failure (field_class)) { + MonoError field_error; + mono_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); + break; + } + } + if (!field_class || !field_class->blittable) + blittable = FALSE; + } } + if (klass->enumtype) + blittable = klass->element_class->blittable; } + if (mono_class_has_failure (klass)) + return; + if (klass == mono_defaults.string_class) + blittable = FALSE; + /* Compute klass->has_references */ + /* + * Process non-static fields first, since static fields might recursively + * refer to the class itself. + */ for (i = 0; i < top; i++) { MonoType *ftype; field = &klass->fields [i]; - if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) { + if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { ftype = mono_type_get_underlying_type (field->type); ftype = mono_type_get_basic_type_from_generic (ftype); if (type_has_references (klass, ftype)) - klass->has_static_refs = TRUE; - } - } - - for (i = 0; i < top; i++) { - MonoType *ftype; - - field = &klass->fields [i]; - - ftype = mono_type_get_underlying_type (field->type); - ftype = mono_type_get_basic_type_from_generic (ftype); - if (type_has_references (klass, ftype)) { - if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) - klass->has_static_refs = TRUE; - else - klass->has_references = TRUE; + has_references = TRUE; } } /* * Compute field layout and total size (not considering static fields) */ + field_offsets = g_new0 (int, top); + int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0; switch (layout) { case TYPE_ATTRIBUTE_AUTO_LAYOUT: case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT: - if (gc_aware_layout) passes = 2; else @@ -1992,7 +1939,7 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) } } - if ((top == 1) && (klass->instance_size == sizeof (MonoObject)) && + if ((top == 1) && (instance_size == sizeof (MonoObject)) && (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) { /* This field is a hack inserted by MCS to empty structures */ continue; @@ -2001,29 +1948,29 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) size = mono_type_size (field->type, &align); /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */ - align = klass->packing_size ? MIN (klass->packing_size, align): align; + align = packing_size ? MIN (packing_size, align): align; /* if the field has managed references, we need to force-align it * see bug #77788 */ if (type_has_references (klass, ftype)) align = MAX (align, sizeof (gpointer)); - klass->min_align = MAX (align, klass->min_align); - field->offset = real_size; + min_align = MAX (align, min_align); + field_offsets [i] = real_size; if (align) { - field->offset += align - 1; - field->offset &= ~(align - 1); + field_offsets [i] += align - 1; + field_offsets [i] &= ~(align - 1); } /*TypeBuilders produce all sort of weird things*/ - g_assert (image_is_dynamic (klass->image) || field->offset > 0); - real_size = field->offset + size; + g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0); + real_size = field_offsets [i] + size; } instance_size = MAX (real_size, instance_size); - if (instance_size & (klass->min_align - 1)) { - instance_size += klass->min_align - 1; - instance_size &= ~(klass->min_align - 1); + if (instance_size & (min_align - 1)) { + instance_size += min_align - 1; + instance_size &= ~(min_align - 1); } } break; @@ -2048,20 +1995,22 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) continue; size = mono_type_size (field->type, &align); - align = klass->packing_size ? MIN (klass->packing_size, align): align; - klass->min_align = MAX (align, klass->min_align); + align = packing_size ? MIN (packing_size, align): align; + min_align = MAX (align, min_align); - /* - * When we get here, field->offset is already set by the - * loader (for either runtime fields or fields loaded from metadata). - * The offset is from the start of the object: this works for both - * classes and valuetypes. - */ - field->offset += sizeof (MonoObject); + if (sre) { + /* Already set by typebuilder_setup_fields () */ + field_offsets [i] = field->offset + sizeof (MonoObject); + } else { + int idx = first_field_idx + i; + guint32 offset; + mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL); + field_offsets [i] = offset + sizeof (MonoObject); + } ftype = mono_type_get_underlying_type (field->type); ftype = mono_type_get_basic_type_from_generic (ftype); if (type_has_references (klass, ftype)) { - if (field->offset % sizeof (gpointer)) { + if (field_offsets [i] % sizeof (gpointer)) { mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name); } } @@ -2069,7 +2018,7 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) /* * Calc max size. */ - real_size = MAX (real_size, size + field->offset); + real_size = MAX (real_size, size + field_offsets [i]); } if (klass->has_references) { @@ -2087,7 +2036,7 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) continue; ftype = mono_type_get_underlying_type (field->type); if (MONO_TYPE_IS_REFERENCE (ftype)) - ref_bitmap [field->offset / sizeof (gpointer)] = 1; + ref_bitmap [field_offsets [i] / sizeof (gpointer)] = 1; } for (i = 0; i < top; i++) { field = &klass->fields [i]; @@ -2099,8 +2048,8 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) // FIXME: Too much code does this #if 0 - if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field->offset / sizeof (gpointer)]) { - mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field->offset); + if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / sizeof (gpointer)]) { + mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field_offsets [i]); } #endif } @@ -2108,9 +2057,9 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) } instance_size = MAX (real_size, instance_size); - if (instance_size & (klass->min_align - 1)) { - instance_size += klass->min_align - 1; - instance_size &= ~(klass->min_align - 1); + if (instance_size & (min_align - 1)) { + instance_size += min_align - 1; + instance_size &= ~(min_align - 1); } break; } @@ -2125,25 +2074,46 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) * performance, and since the JIT memset/memcpy code assumes this and generates * unaligned accesses otherwise. See #78990 for a testcase. */ - if (mono_align_small_structs) { + if (mono_align_small_structs && top) { if (instance_size <= sizeof (MonoObject) + sizeof (gpointer)) - klass->min_align = MAX (klass->min_align, instance_size - sizeof (MonoObject)); + min_align = MAX (min_align, instance_size - sizeof (MonoObject)); } } + if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) + instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE); + else if (klass->byval_arg.type == MONO_TYPE_PTR) + instance_size = sizeof (MonoObject) + sizeof (gpointer); + + /* Publish the data */ + mono_loader_lock (); if (klass->instance_size && !klass->image->dynamic) { /* Might be already set using cached info */ g_assert (klass->instance_size == instance_size); } else { klass->instance_size = instance_size; } + klass->blittable = blittable; + klass->has_references = has_references; + klass->packing_size = packing_size; + klass->min_align = min_align; + for (i = 0; i < top; ++i) { + field = &klass->fields [i]; + if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) + klass->fields [i].offset = field_offsets [i]; + } + mono_memory_barrier (); klass->size_inited = 1; + mono_loader_unlock (); /* * Compute static field layout and size + * Static fields can reference the class itself, so this has to be + * done after instance_size etc. are initialized. */ - for (i = 0; i < top; i++){ + class_size = 0; + for (i = 0; i < top; i++) { gint32 align; guint32 size; @@ -2162,16 +2132,53 @@ mono_class_layout_fields (MonoClass *klass, int instance_size) has_static_fields = TRUE; size = mono_type_size (field->type, &align); - field->offset = klass->sizes.class_size; + field_offsets [i] = class_size; /*align is always non-zero here*/ - field->offset += align - 1; - field->offset &= ~(align - 1); - klass->sizes.class_size = field->offset + size; + field_offsets [i] += align - 1; + field_offsets [i] &= ~(align - 1); + class_size = field_offsets [i] + size; } - if (has_static_fields && klass->sizes.class_size == 0) + if (has_static_fields && class_size == 0) /* Simplify code which depends on class_size != 0 if the class has static fields */ - klass->sizes.class_size = 8; + class_size = 8; + + /* Compute klass->has_static_refs */ + has_static_refs = FALSE; + for (i = 0; i < top; i++) { + MonoType *ftype; + + field = &klass->fields [i]; + + if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) { + ftype = mono_type_get_underlying_type (field->type); + ftype = mono_type_get_basic_type_from_generic (ftype); + if (type_has_references (klass, ftype)) + has_static_refs = TRUE; + } + } + + /*valuetypes can't be neither bigger than 1Mb or empty. */ + if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject)))) + mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size); + + /* Publish the data */ + mono_loader_lock (); + if (!klass->rank) + klass->sizes.class_size = class_size; + klass->has_static_refs = has_static_refs; + for (i = 0; i < top; ++i) { + field = &klass->fields [i]; + + if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) + field->offset = field_offsets [i]; + } + + mono_memory_barrier (); + klass->fields_inited = 1; + mono_loader_unlock (); + + g_free (field_offsets); } static MonoMethod* @@ -2216,9 +2223,9 @@ mono_class_setup_methods (MonoClass *klass) if (klass->methods) return; - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { MonoError error; - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_init (gklass); if (!mono_class_has_failure (gklass)) @@ -2332,19 +2339,23 @@ mono_class_setup_methods (MonoClass *klass) for (i = 0; i < klass->interface_count; i++) setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic); - } else { + } else if (mono_class_has_static_metadata (klass)) { MonoError error; + int first_idx = mono_class_get_first_method_idx (klass); count = klass->method.count; methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count); for (i = 0; i < count; ++i) { - int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1); + int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1); methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error); if (!methods [i]) { mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error)); mono_error_cleanup (&error); } } + } else { + methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1); + count = 0; } if (MONO_CLASS_IS_INTERFACE (klass)) { @@ -2381,13 +2392,14 @@ MonoMethod* mono_class_get_method_by_index (MonoClass *klass, int index) { MonoError error; + + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); /* Avoid calling setup_methods () if possible */ - if (klass->generic_class && !klass->methods) { - MonoClass *gklass = klass->generic_class->container_class; + if (gklass && !klass->methods) { MonoMethod *m; m = mono_class_inflate_generic_method_full_checked ( - gklass->methods [index], klass, mono_class_get_context (klass), &error); + gklass->container_class->methods [index], klass, mono_class_get_context (klass), &error); g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */ /* * If setup_methods () is called later for this class, no duplicates are created, @@ -2417,7 +2429,7 @@ mono_class_get_method_by_index (MonoClass *klass, int index) MonoMethod* mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method) { - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; int i; g_assert (method->klass == gklass); @@ -2462,9 +2474,9 @@ mono_class_get_vtable_entry (MonoClass *klass, int offset) return klass->parent->vtable [offset]; } - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { MonoError error; - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_setup_vtable (gklass); m = gklass->vtable [offset]; @@ -2513,8 +2525,8 @@ mono_class_setup_properties (MonoClass *klass) if (klass->ext && klass->ext->properties) return; - if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_init (gklass); mono_class_setup_properties (gklass); @@ -2560,6 +2572,7 @@ mono_class_setup_properties (MonoClass *klass) properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]); startm = mono_metadata_methods_from_property (klass->image, i, &endm); + int first_idx = mono_class_get_first_method_idx (klass); for (j = startm; j < endm; ++j) { MonoMethod *method; @@ -2571,7 +2584,7 @@ mono_class_setup_properties (MonoClass *klass) method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error); mono_error_cleanup (&error); /* FIXME don't swallow this error */ } else { - method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first]; + method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx]; } switch (cols [MONO_METHOD_SEMA_SEMANTICS]) { @@ -2644,8 +2657,8 @@ mono_class_setup_events (MonoClass *klass) if (klass->ext && klass->ext->events) return; - if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; MonoGenericContext *context = NULL; mono_class_setup_events (gklass); @@ -2702,6 +2715,7 @@ mono_class_setup_events (MonoClass *klass) event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]); startm = mono_metadata_methods_from_event (klass->image, i, &endm); + int first_idx = mono_class_get_first_method_idx (klass); for (j = startm; j < endm; ++j) { MonoMethod *method; @@ -2713,7 +2727,7 @@ mono_class_setup_events (MonoClass *klass) method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error); mono_error_cleanup (&error); /* FIXME don't swallow this error */ } else { - method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first]; + method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx]; } switch (cols [MONO_METHOD_SEMA_SEMANTICS]) { @@ -2812,7 +2826,7 @@ mono_unload_interface_id (MonoClass *klass) * LOCKING: Acquires the classes lock. * Returns: The new ID. */ -static guint +static guint32 mono_get_unique_iid (MonoClass *klass) { int iid; @@ -2835,7 +2849,7 @@ mono_get_unique_iid (MonoClass *klass) } mono_bitset_set (global_interface_bitset, iid); /* set the bit also in the per-image set */ - if (!klass->generic_class) { + if (!mono_class_is_ginst (klass)) { if (klass->image->interface_bitset) { if (iid >= mono_bitset_size (klass->image->interface_bitset)) { MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1); @@ -2854,8 +2868,9 @@ mono_get_unique_iid (MonoClass *klass) if (mono_print_vtable) { int generic_id; char *type_name = mono_type_full_name (&klass->byval_arg); - if (klass->generic_class && !klass->generic_class->context.class_inst->is_open) { - generic_id = klass->generic_class->context.class_inst->id; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + if (gklass && !gklass->context.class_inst->is_open) { + generic_id = gklass->context.class_inst->id; g_assert (generic_id != 0); } else { generic_id = 0; @@ -2865,7 +2880,9 @@ mono_get_unique_iid (MonoClass *klass) } #endif - g_assert (iid <= 65535); + /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing. + * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */ + g_assert (iid < INT_MAX); return iid; } @@ -3068,6 +3085,12 @@ fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *ecla 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 @@ -3085,11 +3108,11 @@ static MonoClass** get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator) { MonoClass *eclass = klass->element_class; - static MonoClass* generic_icollection_class = NULL; - static MonoClass* generic_ienumerable_class = NULL; - static MonoClass* generic_ienumerator_class = NULL; - static MonoClass* generic_ireadonlylist_class = NULL; - static MonoClass* generic_ireadonlycollection_class = NULL; + 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; @@ -3105,11 +3128,12 @@ get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enume eclass_is_valuetype = FALSE; original_rank = eclass->rank; if (klass->byval_arg.type != MONO_TYPE_SZARRAY) { - if (klass->generic_class && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) { + 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 we need to get the list of interfaces for T. */ - eclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + eclass = mono_class_from_mono_type (gklass->context.class_inst->type_argv [0]); original_rank = eclass->rank; if (!eclass->rank) eclass = eclass->element_class; @@ -3127,18 +3151,11 @@ get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enume */ all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE; - if (!generic_icollection_class) { - generic_icollection_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "ICollection`1"); - generic_ienumerable_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "IEnumerable`1"); - generic_ienumerator_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "IEnumerator`1"); - generic_ireadonlylist_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "IReadOnlyList`1"); - generic_ireadonlycollection_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "IReadOnlyCollection`1"); - } + 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); @@ -3329,8 +3346,9 @@ count_virtual_methods (MonoClass *klass) ++count; } } else { + int first_idx = mono_class_get_first_method_idx (klass); for (i = 0; i < klass->method.count; ++i) { - flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS); + flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS); if (flags & METHOD_ATTRIBUTE_VIRTUAL) ++count; @@ -3504,15 +3522,16 @@ mono_class_interface_match (const uint8_t *bitmap, int id) #endif /* - * LOCKING: this is supposed to be called with the loader lock held. * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details. + * LOCKING: Acquires the loader lock. */ static int setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) { MonoError error; MonoClass *k, *ic; - int i, j, max_iid, num_ifaces; + int i, j, num_ifaces; + guint32 max_iid; MonoClass **interfaces_full = NULL; int *interface_offsets_full = NULL; GPtrArray *ifaces; @@ -3540,8 +3559,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) for (i = 0; i < k->interface_count; i++) { ic = k->interfaces [i]; - if (!ic->inited) - mono_class_init (ic); + mono_class_init (ic); if (max_iid < ic->interface_id) max_iid = ic->interface_id; @@ -3578,14 +3596,13 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) if (max_iid < klass->interface_id) max_iid = klass->interface_id; } - klass->max_interface_id = max_iid; + /* compute vtable offset for interfaces */ interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces); interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces); - for (i = 0; i < num_ifaces; i++) { + for (i = 0; i < num_ifaces; i++) interface_offsets_full [i] = -1; - } /* skip the current class */ for (j = 0; j < klass->idepth - 1; j++) { @@ -3659,7 +3676,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) for (i = 0; i < num_array_interfaces; ++i) { int offset; ic = array_interfaces [i]; - if (ic->generic_class->container_class == mono_defaults.generic_ilist_class) + 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; @@ -3678,11 +3695,14 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) } for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) { - if (interface_offsets_full [i] != -1) { + if (interface_offsets_full [i] != -1) interface_offsets_count ++; - } } + /* Publish the data */ + mono_loader_lock (); + + klass->max_interface_id = max_iid; /* * We might get called multiple times: * - mono_class_init () @@ -3707,7 +3727,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize); #endif for (i = 0; i < interface_offsets_count; i++) { - int id = interfaces_full [i]->interface_id; + guint32 id = interfaces_full [i]->interface_id; bitmap [id >> 3] |= (1 << (id & 7)); klass->interfaces_packed [i] = interfaces_full [i]; klass->interface_offsets_packed [i] = interface_offsets_full [i]; @@ -3723,6 +3743,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) klass->interface_bitmap = bitmap; #endif } + mono_loader_unlock (); end: g_free (interfaces_full); @@ -3737,7 +3758,7 @@ end: //printf ("JUST DONE: "); //print_implemented_interfaces (klass); - + return cur_slot; } @@ -3755,11 +3776,7 @@ end: void mono_class_setup_interface_offsets (MonoClass *klass) { - mono_loader_lock (); - setup_interface_offsets (klass, 0, FALSE); - - mono_loader_unlock (); } /*Checks if @klass has @parent as one of it's parents type gtd @@ -3786,16 +3803,17 @@ mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup) { MonoGenericInst *ginst; int i; - if (!klass->generic_class) { + + if (!mono_class_is_ginst (klass)) { mono_class_setup_vtable_full (klass, in_setup); return !mono_class_has_failure (klass); } mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup); - if (mono_class_set_type_load_failure_causedby_class (klass, klass->generic_class->container_class, "Failed to load generic definition vtable")) + if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable")) return FALSE; - ginst = klass->generic_class->context.class_inst; + ginst = mono_class_get_generic_class (klass)->context.class_inst; for (i = 0; i < ginst->type_argc; ++i) { MonoClass *arg; if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST) @@ -3866,7 +3884,7 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup) mono_stats.generic_vtable_count ++; in_setup = g_list_prepend (in_setup, klass); - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { if (!mono_class_check_vtable_constraints (klass, in_setup)) { mono_loader_unlock (); g_list_remove (in_setup, klass); @@ -3874,9 +3892,9 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup) } context = mono_class_get_context (klass); - type_token = klass->generic_class->container_class->type_token; + type_token = mono_class_get_generic_class (klass)->container_class->type_token; } else { - context = (MonoGenericContext *) klass->generic_container; + context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try? type_token = klass->type_token; } @@ -4339,7 +4357,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o MonoError error; MonoClass *k, *ic; MonoMethod **vtable; - int i, max_vtsize = 0, max_iid, cur_slot = 0; + int i, max_vtsize = 0, cur_slot = 0; + guint32 max_iid; GPtrArray *ifaces = NULL; GHashTable *override_map = NULL; MonoMethod *cm; @@ -4404,9 +4423,9 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot); /* Optimized version for generic instances */ - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { MonoError error; - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; MonoMethod **tmp; mono_class_setup_vtable_full (gklass, in_setup); @@ -4623,7 +4642,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o // it can happen (for injected generic array interfaces) that the same slot is // processed multiple times (those interfaces have overlapping slots), and it // will not always be the first pass the one that fills the slot. - if (! (klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) { + if (!mono_class_is_abstract (klass)) { for (i = 0; i < klass->interface_offsets_count; i++) { int ic_offset; int im_index; @@ -4767,7 +4786,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o virt_methods = NULL; /* Ensure that all vtable slots are filled with concrete instance methods */ - if (!(klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) { + if (!mono_class_is_abstract (klass)) { for (i = 0; i < cur_slot; ++i) { if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) { char *type_name = mono_type_get_full_name (klass); @@ -4780,8 +4799,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o } } - if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_init (gklass); @@ -4884,14 +4903,14 @@ mono_method_get_vtable_slot (MonoMethod *method) MonoClass *gklass; int i; - if (!method->klass->generic_class) { + if (!mono_class_is_ginst (method->klass)) { g_assert (method->is_inflated); return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring); } /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */ - g_assert (method->klass->generic_class); - gklass = method->klass->generic_class->container_class; + g_assert (mono_class_is_ginst (method->klass)); + gklass = mono_class_get_generic_class (method->klass)->container_class; mono_class_setup_methods (method->klass); g_assert (method->klass->methods); for (i = 0; i < method->klass->method.count; ++i) { @@ -5032,7 +5051,7 @@ setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **met int i; tmp_context.class_inst = NULL; - tmp_context.method_inst = iface->generic_class->context.class_inst; + tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst; //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0)); for (i = 0; i < generic_array_method_num; i++) { @@ -5062,21 +5081,30 @@ concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2) /** * mono_class_init: - * @class: the class to initialize + * @klass: the class to initialize * * Compute the instance_size, class_size and other infos that cannot be * computed at mono_class_get() time. Also compute vtable_size if possible. * Returns TRUE on success or FALSE if there was a problem in loading - * the type (incorrect assemblies, missing assemblies, methods, etc). + * the type (incorrect assemblies, missing assemblies, methods, etc). + * Initializes the following fields in @klass: + * - all the fields initialized by mono_class_init_sizes () + * - has_cctor + * - ghcimpl + * - inited * * LOCKING: Acquires the loader lock. */ gboolean mono_class_init (MonoClass *klass) { - int i; + int i, vtable_size = 0, array_method_count = 0; MonoCachedClassInfo cached_info; gboolean has_cached_info; + gboolean locked = FALSE; + gboolean ghcimpl = FALSE; + gboolean has_cctor = FALSE; + int first_iface_slot = 0; g_assert (klass); @@ -5086,28 +5114,27 @@ mono_class_init (MonoClass *klass) /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/ - /* We do everything inside the lock to prevent races */ - mono_loader_lock (); - - if (klass->inited || mono_class_has_failure (klass)) { - mono_loader_unlock (); - /* Somebody might have gotten in before us */ - return !mono_class_has_failure (klass); - } - - if (klass->init_pending) { + /* + * This function can recursively call itself. + */ + GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id); + if (g_slist_find (init_list, klass)) { mono_class_set_type_load_failure (klass, "Recursive type definition detected"); goto leave; } + init_list = g_slist_prepend (init_list, klass); + mono_native_tls_set_value (init_pending_tls_id, init_list); - klass->init_pending = 1; + /* + * We want to avoid doing complicated work inside locks, so we compute all the required + * information and write it to @klass inside a lock. + */ if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) { mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name)); goto leave; } - if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) { MonoClass *element_class = klass->element_class; if (!element_class->inited) @@ -5118,23 +5145,14 @@ mono_class_init (MonoClass *klass) mono_stats.initialized_class_count++; - if (klass->generic_class && !klass->generic_class->is_dynamic) { - MonoClass *gklass = klass->generic_class->container_class; - - mono_stats.generic_class_count++; - - klass->method = gklass->method; - klass->field = gklass->field; + if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_init (gklass); - // FIXME: Why is this needed ? - if (!mono_class_has_failure (gklass)) - mono_class_setup_methods (gklass); if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init")) goto leave; - if (MONO_CLASS_IS_INTERFACE (klass)) - klass->interface_id = mono_get_unique_iid (klass); + mono_class_setup_interface_id (klass); } if (klass->parent && !klass->parent->inited) @@ -5142,38 +5160,10 @@ mono_class_init (MonoClass *klass) has_cached_info = mono_class_get_cached_class_info (klass, &cached_info); - if (klass->generic_class || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes)) - klass->nested_classes_inited = TRUE; - - /* - * Computes the size used by the fields, and their locations - */ - if (has_cached_info) { - klass->instance_size = cached_info.instance_size; - klass->sizes.class_size = cached_info.class_size; - klass->packing_size = cached_info.packing_size; - klass->min_align = cached_info.min_align; - klass->blittable = cached_info.blittable; - 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; - } - else - if (!klass->size_inited){ - mono_class_setup_fields (klass); - if (mono_class_has_failure (klass)) - goto leave; - } - - /* Initialize arrays */ - if (klass->rank) { - klass->method.count = 3 + (klass->rank > 1? 2: 1); - - if (klass->interface_count) { - int count_generic = generic_array_methods (klass); - klass->method.count += klass->interface_count * count_generic; - } - } + /* Compute instance size etc. */ + init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL); + if (mono_class_has_failure (klass)) + goto leave; mono_class_setup_supertypes (klass); @@ -5187,11 +5177,9 @@ mono_class_init (MonoClass *klass) */ if (has_cached_info) { /* AOT case */ - klass->vtable_size = cached_info.vtable_size; - klass->has_finalize = cached_info.has_finalize; - klass->has_finalize_inited = TRUE; - klass->ghcimpl = cached_info.ghcimpl; - klass->has_cctor = cached_info.has_cctor; + vtable_size = cached_info.vtable_size; + ghcimpl = cached_info.ghcimpl; + has_cctor = cached_info.has_cctor; } else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) { /* SZARRAY can have 2 vtable layouts, with and without the stelemref method. * The first slot if for array with. @@ -5204,21 +5192,22 @@ mono_class_init (MonoClass *klass) if (!szarray_vtable_size [slot]) { mono_class_setup_vtable (klass); szarray_vtable_size [slot] = klass->vtable_size; + vtable_size = klass->vtable_size; } else { - klass->vtable_size = szarray_vtable_size[slot]; + vtable_size = szarray_vtable_size[slot]; } - } else if (klass->generic_class && !MONO_CLASS_IS_INTERFACE (klass)) { - MonoClass *gklass = klass->generic_class->container_class; + } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; /* Generic instance case */ - klass->ghcimpl = gklass->ghcimpl; - klass->has_cctor = gklass->has_cctor; + ghcimpl = gklass->ghcimpl; + has_cctor = gklass->has_cctor; mono_class_setup_vtable (gklass); if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init")) goto leave; - klass->vtable_size = gklass->vtable_size; + vtable_size = gklass->vtable_size; } else { /* General case */ @@ -5238,11 +5227,17 @@ mono_class_init (MonoClass *klass) if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) { MonoMethod *cmethod = NULL; - if (klass->type_token && !image_is_dynamic(klass->image)) { + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; + + /* Generic instance case */ + ghcimpl = gklass->ghcimpl; + has_cctor = gklass->has_cctor; + } else if (klass->type_token && !image_is_dynamic(klass->image)) { cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME); /* The find_method function ignores the 'flags' argument */ if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME)) - klass->has_cctor = 1; + has_cctor = 1; } else { mono_class_setup_methods (klass); if (mono_class_has_failure (klass)) @@ -5252,7 +5247,7 @@ mono_class_init (MonoClass *klass) MonoMethod *method = klass->methods [i]; if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".cctor", method->name) == 0)) { - klass->has_cctor = 1; + has_cctor = 1; break; } } @@ -5260,45 +5255,85 @@ mono_class_init (MonoClass *klass) } } - if (klass->parent) { - MonoError parent_error; - mono_error_init (&parent_error); - int first_iface_slot; - /* This will compute klass->parent->vtable_size for some classes */ - mono_class_init (klass->parent); - if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to initialize")) { - goto leave; + if (klass->rank) { + array_method_count = 3 + (klass->rank > 1? 2: 1); + + if (klass->interface_count) { + int count_generic = generic_array_methods (klass); + array_method_count += klass->interface_count * count_generic; } - if (!klass->parent->vtable_size) { - /* FIXME: Get rid of this somehow */ + } + + if (klass->parent) { + if (!klass->parent->vtable_size) mono_class_setup_vtable (klass->parent); - if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize")) { - goto leave; - } - } + if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize")) + goto leave; + g_assert (klass->parent->vtable_size); first_iface_slot = klass->parent->vtable_size; if (mono_class_need_stelemref_method (klass)) ++first_iface_slot; - setup_interface_offsets (klass, first_iface_slot, TRUE); - } else { - setup_interface_offsets (klass, 0, TRUE); } + /* + * Do the actual changes to @klass inside the loader lock + */ + mono_loader_lock (); + locked = TRUE; + + if (klass->inited || mono_class_has_failure (klass)) { + mono_loader_unlock (); + /* Somebody might have gotten in before us */ + return !mono_class_has_failure (klass); + } + + mono_stats.initialized_class_count++; + + if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; + + mono_stats.generic_class_count++; + + klass->method = gklass->method; + klass->field = gklass->field; + } + + if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes)) + klass->nested_classes_inited = TRUE; + klass->ghcimpl = ghcimpl; + klass->has_cctor = has_cctor; + if (vtable_size) + klass->vtable_size = vtable_size; + if (has_cached_info) { + klass->has_finalize = cached_info.has_finalize; + klass->has_finalize_inited = TRUE; + } + if (klass->rank) + klass->method.count = array_method_count; + + mono_loader_unlock (); + locked = FALSE; + + setup_interface_offsets (klass, first_iface_slot, TRUE); + if (mono_security_core_clr_enabled ()) mono_security_core_clr_check_inheritance (klass); - if (klass->generic_class && !mono_verifier_class_is_valid_generic_instantiation (klass)) + if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass)) mono_class_set_type_load_failure (klass, "Invalid generic instantiation"); goto leave; leave: + 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; - klass->init_pending = 0; - mono_loader_unlock (); + if (locked) + mono_loader_unlock (); return !mono_class_has_failure (klass); } @@ -5322,8 +5357,8 @@ mono_class_has_finalizer (MonoClass *klass) MonoMethod *cmethod = NULL; if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) { - } else if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + } else if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; has_finalize = mono_class_has_finalizer (gklass); } else if (klass->parent && klass->parent->has_finalize) { @@ -5371,11 +5406,7 @@ mono_class_has_finalizer (MonoClass *klass) gboolean mono_is_corlib_image (MonoImage *image) { - /* FIXME: allow the dynamic case for our compilers and with full trust */ - if (image_is_dynamic (image)) - return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib"); - else - return image == mono_defaults.corlib; + return image == mono_defaults.corlib; } /* @@ -5504,7 +5535,6 @@ mono_class_setup_mono_type (MonoClass *klass) if (MONO_CLASS_IS_INTERFACE (klass)) klass->interface_id = mono_get_unique_iid (klass); - } #ifndef DISABLE_COM @@ -5569,11 +5599,12 @@ mono_class_setup_parent (MonoClass *klass, MonoClass *parent) /* set the parent to something useful and safe, but mark the type as broken */ parent = mono_defaults.object_class; mono_class_set_type_load_failure (klass, ""); + g_assert (parent); } klass->parent = parent; - if (parent->generic_class && !parent->name) { + if (mono_class_is_ginst (parent) && !parent->name) { /* * If the parent is a generic instance, we may get * called before it is fully initialized, especially @@ -5673,7 +5704,7 @@ 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) + if (mono_class_get_generic_class (gclass)->container_class != gtd) return FALSE; /* Check if the generic instance has no parent. */ @@ -5735,7 +5766,17 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); - klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass)); + if (mono_metadata_has_generic_params (image, type_token)) { + klass = mono_image_alloc0 (image, sizeof (MonoClassGtd)); + klass->class_kind = MONO_CLASS_GTD; + classes_size += sizeof (MonoClassGtd); + ++class_gtd_count; + } else { + klass = mono_image_alloc0 (image, sizeof (MonoClassDef)); + klass->class_kind = MONO_CLASS_DEF; + classes_size += sizeof (MonoClassDef); + ++class_def_count; + } klass->name = name; klass->name_space = nspace; @@ -5744,25 +5785,21 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError klass->image = image; klass->type_token = type_token; - klass->flags = cols [MONO_TYPEDEF_FLAGS]; + mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]); mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass); - classes_size += sizeof (MonoClass); - /* * Check whether we're a generic type definition. */ - klass->generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL); - if (klass->generic_container) { - klass->is_generic = 1; - klass->generic_container->owner.klass = klass; - klass->generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous - context = &klass->generic_container->context; - } - - if (klass->generic_container) + if (mono_class_is_gtd (klass)) { + MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL); + generic_container->owner.klass = klass; + generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous + context = &generic_container->context; + mono_class_set_generic_container (klass, generic_container); enable_gclass_recording (); + } if (cols [MONO_TYPEDEF_EXTENDS]) { MonoClass *tmp; @@ -5790,7 +5827,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent"); goto parent_failure; } - if (klass->generic_container && tmp->generic_class && tmp->generic_class->container_class == klass) { + if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) { mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type"); goto parent_failure; } @@ -5802,7 +5839,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError /* uses ->valuetype, which is initialized by mono_class_setup_parent above */ mono_class_setup_mono_type (klass); - if (klass->generic_container) + if (mono_class_is_gtd (klass)) disable_gclass_recording (fix_gclass_incomplete_instantiation, klass); /* @@ -5820,11 +5857,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError } } - if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS) + if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS) klass->unicode = 1; #ifdef HOST_WIN32 - if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS) + if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS) klass->unicode = 1; #endif @@ -5840,6 +5877,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError return NULL; } + /* This is required now that it is possible for more than 2^16 interfaces to exist. */ + g_assert(icount <= 65535); + klass->interfaces = interfaces; klass->interface_count = icount; klass->interfaces_inited = 1; @@ -5850,8 +5890,10 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError /* * Compute the field and method lists */ - klass->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1; - klass->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1; + int first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1; + mono_class_set_first_field_idx (klass, first_field_idx); + int first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1; + mono_class_set_first_method_idx (klass, first_method_idx); if (tt->rows > tidx){ mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE); @@ -5864,12 +5906,12 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError if (cols [MONO_TYPEDEF_FIELD_LIST] && cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows) - klass->field.count = field_last - klass->field.first; + klass->field.count = field_last - first_field_idx; else klass->field.count = 0; if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows) - klass->method.count = method_last - klass->method.first; + klass->method.count = method_last - first_method_idx; else klass->method.count = 0; @@ -5897,7 +5939,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError * We must do this after the class has been constructed to make certain recursive scenarios * work. */ - if (klass->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, klass->generic_container, error)) { + if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) { mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error)); mono_loader_unlock (); mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED); @@ -5926,8 +5968,8 @@ parent_failure: gboolean mono_class_is_nullable (MonoClass *klass) { - return klass->generic_class != NULL && - klass->generic_class->container_class == mono_defaults.generic_nullable_class; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + return gklass && gklass->container_class == mono_defaults.generic_nullable_class; } @@ -5936,7 +5978,7 @@ MonoClass* mono_class_get_nullable_param (MonoClass *klass) { g_assert (mono_class_is_nullable (klass)); - return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + return mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]); } static void @@ -5944,7 +5986,7 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd) { if (gtd->parent) { MonoError error; - MonoGenericClass *gclass = klass->generic_class; + MonoGenericClass *gclass = mono_class_get_generic_class (klass); klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error); if (!mono_error_ok (&error)) { @@ -5982,7 +6024,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass) return gclass->cached_class; } - klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass)); + klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst)); gklass = gclass->container_class; @@ -6000,12 +6042,12 @@ mono_generic_class_get_class (MonoGenericClass *gclass) mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); klass->image = gklass->image; - klass->flags = gklass->flags; klass->type_token = gklass->type_token; klass->field.count = gklass->field.count; - klass->is_inflated = 1; - klass->generic_class = gclass; + klass->class_kind = MONO_CLASS_GINST; + //FIXME add setter + ((MonoClassGenericInst*)klass)->generic_class = gclass; klass->byval_arg.type = MONO_TYPE_GENERICINST; klass->this_arg.type = klass->byval_arg.type; @@ -6055,8 +6097,8 @@ mono_generic_class_get_class (MonoGenericClass *gclass) mono_profiler_class_loaded (klass, MONO_PROFILE_OK); - inflated_classes ++; - inflated_classes_size += sizeof (MonoClass); + ++class_ginst_count; + inflated_classes_size += sizeof (MonoClassGenericInst); mono_loader_unlock (); @@ -6117,8 +6159,10 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo) gboolean is_mvar = container->is_method; gboolean is_anonymous = container->is_anonymous; - klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass)); - classes_size += sizeof (MonoClass); + klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam)); + klass->class_kind = MONO_CLASS_GPARAM; + classes_size += sizeof (MonoClassGenericParam); + ++class_gparam_count; if (pinfo) { CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name ); @@ -6168,7 +6212,6 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo) klass->inited = TRUE; CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass ); CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass ); - klass->flags = TYPE_ATTRIBUTE_PUBLIC; klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR; klass->this_arg.type = klass->byval_arg.type; @@ -6188,7 +6231,6 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo) klass->instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE); mono_memory_barrier (); klass->size_inited = 1; - klass->setup_fields_called = 1; mono_class_setup_supertypes (klass); @@ -6395,23 +6437,23 @@ mono_ptr_class_get (MonoType *type) } mono_image_unlock (image); - result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass)); + result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer)); - classes_size += sizeof (MonoClass); + classes_size += sizeof (MonoClassPointer); + ++class_pointer_count; result->parent = NULL; /* no parent for PTR types */ result->name_space = el_class->name_space; name = g_strdup_printf ("%s*", el_class->name); result->name = mono_image_strdup (image, name); + result->class_kind = MONO_CLASS_POINTER; g_free (name); mono_profiler_class_event (result, MONO_PROFILE_START_LOAD); result->image = el_class->image; result->inited = TRUE; - result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); - /* Can pointers get boxed? */ - result->instance_size = sizeof (gpointer); + result->instance_size = sizeof (MonoObject) + sizeof (gpointer); result->cast_class = result->element_class = el_class; result->blittable = TRUE; @@ -6460,17 +6502,19 @@ mono_fnptr_class_get (MonoMethodSignature *sig) } result = g_new0 (MonoClass, 1); + classes_size += sizeof (MonoClassPointer); + ++class_pointer_count; + result->parent = NULL; /* no parent for PTR types */ result->name_space = "System"; result->name = "MonoFNPtrFakeClass"; + result->class_kind = MONO_CLASS_POINTER; mono_profiler_class_event (result, MONO_PROFILE_START_LOAD); result->image = mono_defaults.corlib; /* need to fix... */ result->inited = TRUE; - result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */ - /* Can pointers get boxed? */ - result->instance_size = sizeof (gpointer); + result->instance_size = sizeof (MonoObject) + sizeof (gpointer); result->cast_class = result->element_class = result; result->blittable = TRUE; @@ -6631,7 +6675,6 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) GSList *list, *rootlist = NULL; int nsize; char *name; - gboolean corlib_type = FALSE; g_assert (rank <= 255); @@ -6673,20 +6716,16 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) } } - /* for the building corlib use System.Array from it */ - if (image->assembly && assembly_is_dynamic (image->assembly) && image->assembly_name && strcmp (image->assembly_name, "mscorlib") == 0) { - parent = mono_class_load_from_name (image, "System", "Array"); - corlib_type = TRUE; - } else { - parent = mono_defaults.array_class; - if (!parent->inited) - mono_class_init (parent); - } + parent = mono_defaults.array_class; + if (!parent->inited) + mono_class_init (parent); - klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass)); + klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray)); klass->image = image; klass->name_space = eclass->name_space; + klass->class_kind = MONO_CLASS_ARRAY; + nsize = strlen (eclass->name); name = (char *)g_malloc (nsize + 2 + rank + 1); memcpy (name, eclass->name, nsize); @@ -6702,11 +6741,10 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); - classes_size += sizeof (MonoClass); + classes_size += sizeof (MonoClassArray); + ++class_array_count; klass->type_token = 0; - /* all arrays are marked serializable and sealed, bug #42779 */ - klass->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC; klass->parent = parent; klass->instance_size = mono_class_instance_size (klass->parent); @@ -6729,7 +6767,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) mono_class_setup_supertypes (klass); - if (eclass->generic_class) + if (mono_class_is_ginst (eclass)) mono_class_init (eclass); if (!eclass->size_inited) mono_class_setup_fields (eclass); @@ -6785,11 +6823,9 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) } klass->this_arg = klass->byval_arg; klass->this_arg.byref = 1; - if (corlib_type) { - klass->inited = 1; - } - klass->generic_container = eclass->generic_container; + //WTF was this? it's wrong + // klass->generic_container = eclass->generic_container; if (rank == 1 && !bounded) { MonoClass *prev_class; @@ -6851,7 +6887,7 @@ mono_class_instance_size (MonoClass *klass) * * Use to get the computed minimum alignment requirements for the specified class. * - * Returns: minimm alignment requirements + * Returns: minimum alignment requirements */ gint32 mono_class_min_align (MonoClass *klass) @@ -6872,7 +6908,7 @@ mono_class_min_align (MonoClass *klass) * Returns: the size of a value of kind @klass */ gint32 -mono_class_value_size (MonoClass *klass, guint32 *align) +mono_class_value_size (MonoClass *klass, guint32 *align) { gint32 size; @@ -6902,7 +6938,7 @@ mono_class_data_size (MonoClass *klass) mono_class_init (klass); /* This can happen with dynamically created types */ if (!klass->fields_inited) - mono_class_setup_fields_locking (klass); + mono_class_setup_fields (klass); /* in arrays, sizes.class_size is unioned with element_size * and arrays have no static fields @@ -6920,14 +6956,15 @@ mono_class_data_size (MonoClass *klass) static MonoClassField * mono_class_get_field_idx (MonoClass *klass, int idx) { - mono_class_setup_fields_locking (klass); + mono_class_setup_fields (klass); if (mono_class_has_failure (klass)) return NULL; while (klass) { + int first_field_idx = mono_class_get_first_field_idx (klass); if (klass->image->uncompressed_metadata) { /* - * klass->field.first points to the FieldPtr table, while idx points into the + * first_field_idx points to the FieldPtr table, while idx points into the * Field table, so we have to do a search. */ /*FIXME this is broken for types with multiple fields with the same name.*/ @@ -6940,8 +6977,8 @@ mono_class_get_field_idx (MonoClass *klass, int idx) g_assert_not_reached (); } else { if (klass->field.count) { - if ((idx >= klass->field.first) && (idx < klass->field.first + klass->field.count)){ - return &klass->fields [idx - klass->field.first]; + if ((idx >= first_field_idx) && (idx < first_field_idx + klass->field.count)){ + return &klass->fields [idx - first_field_idx]; } } } @@ -7002,7 +7039,7 @@ mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoTyp { int i; - mono_class_setup_fields_locking (klass); + mono_class_setup_fields (klass); if (mono_class_has_failure (klass)) return NULL; @@ -7040,14 +7077,15 @@ mono_class_get_field_token (MonoClassField *field) MonoClass *klass = field->parent; int i; - mono_class_setup_fields_locking (klass); + mono_class_setup_fields (klass); while (klass) { if (!klass->fields) return 0; + int first_field_idx = mono_class_get_first_field_idx (klass); for (i = 0; i < klass->field.count; ++i) { if (&klass->fields [i] == field) { - int idx = klass->field.first + i + 1; + int idx = first_field_idx + i + 1; if (klass->image->uncompressed_metadata) idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx); @@ -8091,10 +8129,10 @@ mono_class_has_variant_generic_params (MonoClass *klass) int i; MonoGenericContainer *container; - if (!klass->generic_class) + if (!mono_class_is_ginst (klass)) return FALSE; - container = klass->generic_class->container_class->generic_container; + container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class); for (i = 0; i < container->type_argc; ++i) if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)) @@ -8138,7 +8176,7 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean int j; MonoType **klass_argv, **oklass_argv; MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass); - MonoGenericContainer *container = klass_gtd->generic_container; + MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd); if (klass == oklass) return TRUE; @@ -8147,8 +8185,8 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd) return FALSE; - klass_argv = &klass->generic_class->context.class_inst->type_argv [0]; - oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0]; + klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]; + oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0]; for (j = 0; j < container->type_argc; ++j) { MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]); @@ -8403,14 +8441,14 @@ mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass) int j; MonoType **klass_argv, **oklass_argv; MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass); - MonoGenericContainer *container = klass_gtd->generic_container; + MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd); /*Viable candidates are instances of the same generic interface*/ if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd) return FALSE; - klass_argv = &klass->generic_class->context.class_inst->type_argv [0]; - oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0]; + klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]; + oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0]; for (j = 0; j < container->type_argc; ++j) { MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]); @@ -8587,8 +8625,8 @@ mono_class_get_cctor (MonoClass *klass) return result; } - if (klass->generic_class && !klass->methods) - return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class)); + 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); } @@ -8969,22 +9007,6 @@ mono_class_get_rank (MonoClass *klass) return klass->rank; } -/** - * mono_class_get_flags: - * @klass: the MonoClass to act on - * - * The type flags from the TypeDef table from the metadata. - * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the - * different values. - * - * Returns: The flags from the TypeDef table. - */ -guint32 -mono_class_get_flags (MonoClass *klass) -{ - return klass->flags; -} - /** * mono_class_get_name * @klass: the MonoClass to act on @@ -9120,7 +9142,7 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter) if (!iter) return NULL; if (!*iter) { - mono_class_setup_fields_locking (klass); + mono_class_setup_fields (klass); if (mono_class_has_failure (klass)) return NULL; /* start from the first */ @@ -9236,11 +9258,12 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) start_index = GPOINTER_TO_UINT (*iter); } + int first_idx = mono_class_get_first_method_idx (klass); for (i = start_index; i < klass->method.count; ++i) { guint32 flags; - /* klass->method.first points into the methodptr table */ - flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS); + /* first_idx points into the methodptr table */ + flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS); if (flags & METHOD_ATTRIBUTE_VIRTUAL) break; @@ -9248,7 +9271,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) if (i < klass->method.count) { MonoError error; - res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error); + res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error); mono_error_cleanup (&error); /* FIXME don't swallow the error */ /* Add 1 here so the if (*iter) check fails */ @@ -9615,7 +9638,8 @@ mono_field_get_rva (MonoClassField *field) field_index = mono_field_get_index (field); if (!klass->ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) { - mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL); + 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); klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva); @@ -9805,17 +9829,18 @@ find_method_in_metadata (MonoClass *klass, const char *name, int param_count, in int i; /* Search directly in the metadata to avoid calling setup_methods () */ + int first_idx = mono_class_get_first_method_idx (klass); for (i = 0; i < klass->method.count; ++i) { MonoError error; guint32 cols [MONO_METHOD_SIZE]; MonoMethod *method; MonoMethodSignature *sig; - /* klass->method.first points into the methodptr table */ - mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE); + /* first_idx points into the methodptr table */ + mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE); if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) { - method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error); + method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error); if (!method) { mono_error_cleanup (&error); /* FIXME don't swallow the error */ continue; @@ -9857,8 +9882,8 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p mono_class_init (klass); - if (klass->generic_class && !klass->methods) { - res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags); + if (mono_class_is_ginst (klass) && !klass->methods) { + res = mono_class_get_method_from_name_flags (mono_class_get_generic_class (klass)->container_class, name, param_count, flags); if (res) { MonoError error; res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error); @@ -9987,16 +10012,32 @@ mono_classes_init (void) { mono_os_mutex_init (&classes_mutex); + mono_native_tls_alloc (&setup_fields_tls_id, NULL); + mono_native_tls_alloc (&init_pending_tls_id, NULL); + + mono_counters_register ("MonoClassDef count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count); + mono_counters_register ("MonoClassGtd count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count); + mono_counters_register ("MonoClassGenericInst count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count); + mono_counters_register ("MonoClassGenericParam count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count); + mono_counters_register ("MonoClassArray count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count); + mono_counters_register ("MonoClassPointer count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count); mono_counters_register ("Inflated methods size", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size); - mono_counters_register ("Inflated classes", - MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes); mono_counters_register ("Inflated classes size", 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); } /** @@ -10007,6 +10048,9 @@ mono_classes_init (void) void mono_classes_cleanup (void) { + mono_native_tls_free (setup_fields_tls_id); + mono_native_tls_free (init_pending_tls_id); + if (global_interface_bitset) mono_bitset_free (global_interface_bitset); global_interface_bitset = NULL; @@ -10048,7 +10092,8 @@ is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass) MonoClass * mono_class_get_generic_type_definition (MonoClass *klass) { - return klass->generic_class ? klass->generic_class->container_class : klass; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + return gklass ? gklass->container_class : klass; } /* @@ -10145,8 +10190,9 @@ static MonoClass* get_generic_definition_class (MonoClass *klass) { while (klass) { - if (klass->generic_class && klass->generic_class->container_class) - return klass->generic_class->container_class; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + if (gklass && gklass->container_class) + return gklass->container_class; klass = klass->parent; } return NULL; @@ -10200,12 +10246,12 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass) if (member_klass->element_class && !member_klass->enumtype) member_klass = member_klass->element_class; - access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; + access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK; if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR) return TRUE; - if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst)) + if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst)) return FALSE; if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass))) @@ -10256,15 +10302,16 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal) return TRUE; - if (((access_klass->generic_class && access_klass->generic_class->container_class) || - access_klass->generic_container) && + MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass); + if (((access_gklass && access_gklass->container_class) || + mono_class_is_gtd (access_klass)) && (member_generic_def = get_generic_definition_class (member_klass))) { MonoClass *access_container; - if (access_klass->generic_container) + if (mono_class_is_gtd (access_klass)) access_container = access_klass; else - access_container = access_klass->generic_class->container_class; + access_container = access_gklass->container_class; if (can_access_member (access_container, member_generic_def, context_klass, access_level)) return TRUE; @@ -10502,7 +10549,9 @@ gboolean mono_type_is_valid_enum_basetype (MonoType * type) { * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3) */ -gboolean mono_class_is_valid_enum (MonoClass *klass) { +gboolean +mono_class_is_valid_enum (MonoClass *klass) +{ MonoClassField * field; gpointer iter = NULL; gboolean found_base_field = FALSE; @@ -10513,7 +10562,7 @@ gboolean mono_class_is_valid_enum (MonoClass *klass) { return FALSE; } - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) + if (!mono_class_is_auto_layout (klass)) return FALSE; while ((field = mono_class_get_fields (klass, &iter))) { @@ -10538,7 +10587,7 @@ gboolean mono_class_is_valid_enum (MonoClass *klass) { gboolean mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass) { - return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst; + return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst; } /* @@ -10576,6 +10625,7 @@ mono_class_alloc_ext (MonoClass *klass) if (!klass->ext) klass->ext = ext; class_ext_size += sizeof (MonoClassExt); + ++class_ext_count; mono_image_unlock (klass->image); } @@ -10610,8 +10660,8 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error) if (interface_count > 1) interfaces [1] = mono_class_bind_generic_parameters ( mono_defaults.generic_ireadonlylist_class, 1, args, FALSE); - } else if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + } else if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_setup_interfaces (gklass, error); if (!mono_error_ok (error)) { @@ -10622,7 +10672,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error) interface_count = gklass->interface_count; interfaces = mono_class_new0 (klass, MonoClass *, interface_count); for (i = 0; i < interface_count; i++) { - interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error); + interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error); if (!mono_error_ok (error)) { mono_class_set_type_load_failure (klass, "Could not setup the interfaces"); return; @@ -10652,7 +10702,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) { MonoClass *klass = field->parent; MonoImage *image = klass->image; - MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL; + MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL; int field_idx = field - klass->fields; mono_error_init (error); @@ -10661,35 +10711,41 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) MonoClassField *gfield = >d->fields [field_idx]; MonoType *gtype = mono_field_get_type_checked (gfield, error); if (!mono_error_ok (error)) { - mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error)); + char *full_name = mono_type_get_full_name (gtd); + mono_class_set_type_load_failure (klass, "Could not load generic type of field '%s:%s' (%d) due to: %s", full_name, gfield->name, field_idx, mono_error_get_message (error)); + g_free (full_name); } field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error); if (!mono_error_ok (error)) { - mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error)); + char *full_name = mono_type_get_full_name (klass); + mono_class_set_type_load_failure (klass, "Could not load instantiated type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error)); + g_free (full_name); } } else { const char *sig; guint32 cols [MONO_FIELD_SIZE]; MonoGenericContainer *container = NULL; - int idx = klass->field.first + field_idx; + int idx = mono_class_get_first_field_idx (klass) + field_idx; /*FIXME, in theory we do not lazy load SRE fields*/ g_assert (!image_is_dynamic (image)); - if (klass->generic_container) { - container = klass->generic_container; + if (mono_class_is_gtd (klass)) { + container = mono_class_get_generic_container (klass); } else if (gtd) { - container = gtd->generic_container; + container = mono_class_get_generic_container (gtd); g_assert (container); } - /* klass->field.first and idx points into the fieldptr table */ + /* first_field_idx and idx points into the fieldptr table */ mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE); if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) { - mono_error_set_type_load_class (error, klass, "Could not verify field %s signature", field->name);; + char *full_name = mono_type_get_full_name (klass); + mono_error_set_type_load_class (error, klass, "Could not verify field '%s:%s' signature", full_name, field->name);; mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error)); + g_free (full_name); return; } @@ -10701,7 +10757,9 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error); if (!field->type) { - mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error)); + char *full_name = mono_type_get_full_name (klass); + mono_class_set_type_load_failure (klass, "Could not load type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error)); + g_free (full_name); } } } @@ -10711,7 +10769,7 @@ mono_field_resolve_flags (MonoClassField *field) { MonoClass *klass = field->parent; MonoImage *image = klass->image; - MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL; + MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL; int field_idx = field - klass->fields; @@ -10719,7 +10777,7 @@ mono_field_resolve_flags (MonoClassField *field) MonoClassField *gfield = >d->fields [field_idx]; return mono_field_get_flags (gfield); } else { - int idx = klass->field.first + field_idx; + int idx = mono_class_get_first_field_idx (klass) + field_idx; /*FIXME, in theory we do not lazy load SRE fields*/ g_assert (!image_is_dynamic (image)); @@ -10728,21 +10786,6 @@ mono_field_resolve_flags (MonoClassField *field) } } -/** - * mono_class_setup_basic_field_info: - * @class: The class to initialize - * - * Initializes the klass->fields array of fields. - * Aquires the loader lock. - */ -static void -mono_class_setup_basic_field_info_locking (MonoClass *klass) -{ - mono_loader_lock (); - mono_class_setup_basic_field_info (klass); - mono_loader_unlock (); -} - /** * mono_class_get_fields_lazy: * @klass: the MonoClass to act on @@ -10764,7 +10807,7 @@ mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter) if (!iter) return NULL; if (!*iter) { - mono_class_setup_basic_field_info_locking (klass); + mono_class_setup_basic_field_info (klass); if (!klass->fields) return NULL; /* start from the first */