X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=4cf5fcf45754804080565adb1ab40e4b2f8c377e;hb=b3d9af902387c719edf27251049c5214854897b1;hp=e5d95f1c18e14dbc45f68bf344076952168fbbdd;hpb=96c46ddad421fad6b381c00d38bec5804c5191e2;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index e5d95f1c18e..4cf5fcf4575 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; @@ -78,7 +79,6 @@ static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup); static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass); static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error); -static gpointer mono_class_get_exception_data (const MonoClass *klass); /* @@ -244,9 +244,10 @@ mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error); return_val_if_nok (error, NULL); - if (enclosing->nested_classes_inited && enclosing->ext) { + GList *nested_classes = mono_class_get_nested_classes_property (enclosing); + if (enclosing->nested_classes_inited && nested_classes) { /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */ - for (tmp = enclosing->ext->nested_classes; tmp; tmp = tmp->next) { + for (tmp = nested_classes; tmp; tmp = tmp->next) { res = (MonoClass *)tmp->data; if (strcmp (res->name, name) == 0) return res; @@ -1279,8 +1280,8 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error) { MonoGenericContainer *container = NULL; MonoImage *m = klass->image; - const int top = klass->field.count; - int i; + const int top = mono_class_get_field_count (klass); + int i, first_field_idx; g_assert (klass->enumtype); @@ -1297,13 +1298,14 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error) /* * 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 @@ -1366,11 +1368,10 @@ void mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass) { g_assert (mono_class_has_failure (klass)); - MonoErrorBoxed *box = (MonoErrorBoxed*)mono_class_get_exception_data (klass); + MonoErrorBoxed *box = mono_class_get_exception_data ((MonoClass*)klass); mono_error_set_from_boxed (oerror, box); } - /* * mono_class_alloc: * @@ -1407,7 +1408,7 @@ mono_class_alloc0 (MonoClass *klass, int size) * Initializes the following fields in MonoClass: * * klass->fields (only field->parent and field->name) * * klass->field.count - * * klass->field.first + * * klass->first_field_idx * LOCKING: Acquires the loader lock */ static void @@ -1442,27 +1443,27 @@ mono_class_setup_basic_field_info (MonoClass *klass) mono_class_setup_basic_field_info (gtd); mono_loader_lock (); - klass->field.first = gtd->field.first; - klass->field.count = gtd->field.count; + mono_class_set_field_count (klass, mono_class_get_field_count (gtd)); mono_loader_unlock (); } - top = klass->field.count; + top = mono_class_get_field_count (klass); fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top); /* * Fetch all the field information. */ - for (i = 0; i < top; 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); @@ -1531,7 +1532,6 @@ mono_class_setup_fields (MonoClass *klass) int instance_size; gboolean explicit_size; MonoClassField *field; - MonoGenericContainer *container = NULL; MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL; @@ -1549,9 +1549,8 @@ mono_class_setup_fields (MonoClass *klass) } mono_class_setup_basic_field_info (klass); - top = klass->field.count; + top = mono_class_get_field_count (klass); - gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL; if (gtd) { mono_class_setup_fields (gtd); if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed")) @@ -1588,8 +1587,9 @@ mono_class_setup_fields (MonoClass *klass) /* * Fetch all the field information. */ + 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 = klass->field.first + i; + int idx = first_field_idx + i; field = &klass->fields [i]; if (!field->type) { @@ -1619,7 +1619,7 @@ mono_class_setup_fields (MonoClass *klass) mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset); break; } - if (klass->generic_container) { + if (mono_class_is_gtd (klass)) { mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout."); break; } @@ -1637,8 +1637,11 @@ mono_class_setup_fields (MonoClass *klass) /* The def_value of fields is compute lazily during vtable creation */ } - if (!mono_class_has_failure (klass)) + if (!mono_class_has_failure (klass)) { + mono_loader_lock (); mono_class_layout_fields (klass, instance_size, packing_size, FALSE); + mono_loader_unlock (); + } init_list = g_slist_remove (init_list, klass); mono_native_tls_set_value (setup_fields_tls_id, init_list); @@ -1648,6 +1651,7 @@ static void init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info) { if (cached_info) { + mono_loader_lock (); klass->instance_size = cached_info->instance_size; klass->sizes.class_size = cached_info->class_size; klass->packing_size = cached_info->packing_size; @@ -1656,6 +1660,7 @@ init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info) klass->has_references = cached_info->has_references; klass->has_static_refs = cached_info->has_static_refs; klass->no_special_static_fields = cached_info->no_special_static_fields; + mono_loader_unlock (); } else { if (!klass->size_inited) @@ -1686,6 +1691,9 @@ mono_class_init_sizes (MonoClass *klass) MonoCachedClassInfo cached_info; gboolean has_cached_info; + if (klass->size_inited) + return; + has_cached_info = mono_class_get_cached_class_info (klass, &cached_info); init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL); @@ -1751,7 +1759,7 @@ void mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre) { int i; - const int top = klass->field.count; + const int top = mono_class_get_field_count (klass); guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK; guint32 pass, passes, real_size; gboolean gc_aware_layout = FALSE; @@ -1763,6 +1771,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ int instance_size = base_instance_size; int class_size, min_align; int *field_offsets; + gboolean *fields_has_references; /* * We want to avoid doing complicated work inside locks, so we compute all the required @@ -1892,6 +1901,8 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ * Compute field layout and total size (not considering static fields) */ field_offsets = g_new0 (int, top); + fields_has_references = g_new0 (gboolean, 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: @@ -1928,7 +1939,8 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ ftype = mono_type_get_underlying_type (field->type); ftype = mono_type_get_basic_type_from_generic (ftype); if (gc_aware_layout) { - if (type_has_references (klass, ftype)) { + fields_has_references [i] = type_has_references (klass, ftype); + if (fields_has_references [i]) { if (pass == 1) continue; } else { @@ -1964,6 +1976,9 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ real_size = field_offsets [i] + size; } + /* Make SIMD types as big as a SIMD register since they can be stored into using simd stores */ + if (klass->simd_type) + real_size = MAX (real_size, sizeof (MonoObject) + 16); instance_size = MAX (real_size, instance_size); if (instance_size & (min_align - 1)) { @@ -2000,7 +2015,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ /* Already set by typebuilder_setup_fields () */ field_offsets [i] = field->offset + sizeof (MonoObject); } else { - int idx = klass->field.first + i; + int idx = first_field_idx + i; guint32 offset; mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL); field_offsets [i] = offset + sizeof (MonoObject); @@ -2087,6 +2102,18 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ mono_loader_lock (); if (klass->instance_size && !klass->image->dynamic) { /* Might be already set using cached info */ + if (klass->instance_size != instance_size) { + /* Emit info to help debugging */ + g_print ("%s\n", mono_class_full_name (klass)); + g_print ("%d %d %d %d\n", klass->instance_size, instance_size, klass->blittable, blittable); + g_print ("%d %d %d %d\n", klass->has_references, has_references, klass->packing_size, packing_size); + g_print ("%d %d\n", klass->min_align, min_align); + for (i = 0; i < top; ++i) { + field = &klass->fields [i]; + if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) + printf (" %s %d %d %d\n", klass->fields [i].name, klass->fields [i].offset, field_offsets [i], fields_has_references [i]); + } + } g_assert (klass->instance_size == instance_size); } else { klass->instance_size = instance_size; @@ -2177,6 +2204,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ mono_loader_unlock (); g_free (field_offsets); + g_free (fields_has_references); } static MonoMethod* @@ -2232,7 +2260,7 @@ mono_class_setup_methods (MonoClass *klass) return; /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */ - count = gklass->method.count; + count = mono_class_get_method_count (gklass); methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1)); for (i = 0; i < count; i++) { @@ -2262,7 +2290,7 @@ mono_class_setup_methods (MonoClass *klass) if (klass->rank == 1 && klass->element_class->rank) { jagged_ctor = TRUE; - klass->method.count ++; + count ++; } if (klass->interface_count) { @@ -2337,19 +2365,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; + count = mono_class_get_method_count (klass); 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)) { @@ -2364,7 +2396,7 @@ mono_class_setup_methods (MonoClass *klass) mono_image_lock (klass->image); if (!klass->methods) { - klass->method.count = count; + mono_class_set_method_count (klass, count); /* Needed because of the double-checking locking pattern */ mono_memory_barrier (); @@ -2409,7 +2441,7 @@ mono_class_get_method_by_index (MonoClass *klass, int index) mono_class_setup_methods (klass); if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/ return NULL; - g_assert (index >= 0 && index < klass->method.count); + g_assert (index >= 0 && index < mono_class_get_method_count (klass)); return klass->methods [index]; } } @@ -2424,14 +2456,15 @@ MonoMethod* mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method) { MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; - int i; + int i, mcount; g_assert (method->klass == gklass); mono_class_setup_methods (gklass); g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/ - for (i = 0; i < gklass->method.count; ++i) { + mcount = mono_class_get_method_count (gklass); + for (i = 0; i < mcount; ++i) { if (gklass->methods [i] == method) { if (klass->methods) { return klass->methods [i]; @@ -2515,8 +2548,10 @@ mono_class_setup_properties (MonoClass *klass) MonoProperty *properties; guint32 last; int first, count; + MonoClassPropertyInfo *info; - if (klass->ext && klass->ext->properties) + info = mono_class_get_property_info (klass); + if (info) return; if (mono_class_is_ginst (klass)) { @@ -2527,13 +2562,14 @@ mono_class_setup_properties (MonoClass *klass) if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load")) return; - properties = mono_class_new0 (klass, MonoProperty, gklass->ext->property.count + 1); + MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass); + properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1); - for (i = 0; i < gklass->ext->property.count; i++) { + for (i = 0; i < ginfo->count; i++) { MonoError error; MonoProperty *prop = &properties [i]; - *prop = gklass->ext->properties [i]; + *prop = ginfo->properties [i]; if (prop->get) prop->get = mono_class_inflate_generic_method_full_checked ( @@ -2546,8 +2582,8 @@ mono_class_setup_properties (MonoClass *klass) prop->parent = klass; } - first = gklass->ext->property.first; - count = gklass->ext->property.count; + first = ginfo->first; + count = ginfo->count; } else { first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last); count = last - first; @@ -2566,6 +2602,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; @@ -2577,7 +2614,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]) { @@ -2594,26 +2631,14 @@ mono_class_setup_properties (MonoClass *klass) } } - mono_class_alloc_ext (klass); - - mono_image_lock (klass->image); - - if (klass->ext->properties) { - /* We leak 'properties' which was allocated from the image mempool */ - mono_image_unlock (klass->image); - return; - } - - klass->ext->property.first = first; - klass->ext->property.count = count; - - /* Flush any pending writes as we do double checked locking on klass->ext->properties */ + info = mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo)); + info->first = first; + info->count = count; + info->properties = properties; mono_memory_barrier (); - /* Leave this assignment as the last op in the function */ - klass->ext->properties = properties; - - mono_image_unlock (klass->image); + /* This might leak 'info' which was allocated from the image mempool */ + mono_class_set_property_info (klass, info); } static MonoMethod** @@ -2647,7 +2672,8 @@ mono_class_setup_events (MonoClass *klass) guint32 last; MonoEvent *events; - if (klass->ext && klass->ext->events) + MonoClassEventInfo *info = mono_class_get_event_info (klass); + if (info) return; if (mono_class_is_ginst (klass)) { @@ -2658,8 +2684,9 @@ mono_class_setup_events (MonoClass *klass) if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load")) return; - first = gklass->ext->event.first; - count = gklass->ext->event.count; + MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass); + first = ginfo->first; + count = ginfo->count; events = mono_class_new0 (klass, MonoEvent, count); @@ -2669,7 +2696,7 @@ mono_class_setup_events (MonoClass *klass) for (i = 0; i < count; i++) { MonoError error; MonoEvent *event = &events [i]; - MonoEvent *gevent = &gklass->ext->events [i]; + MonoEvent *gevent = &ginfo->events [i]; mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok @@ -2708,6 +2735,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; @@ -2719,7 +2747,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]) { @@ -2756,25 +2784,14 @@ mono_class_setup_events (MonoClass *klass) } } - mono_class_alloc_ext (klass); - - mono_image_lock (klass->image); - - if (klass->ext->events) { - mono_image_unlock (klass->image); - return; - } - - klass->ext->event.first = first; - klass->ext->event.count = count; + info = mono_class_alloc0 (klass, sizeof (MonoClassEventInfo)); + info->events = events; + info->first = first; + info->count = count; - /* Flush any pending writes as we do double checked locking on klass->ext.events */ mono_memory_barrier (); - /* Leave this assignment as the last op in the function */ - klass->ext->events = events; - - mono_image_unlock (klass->image); + mono_class_set_event_info (klass, info); } /* @@ -2818,7 +2835,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; @@ -2872,12 +2889,14 @@ 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; } static void -collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, MonoError *error) +collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, GHashTable **ifaces, MonoError *error) { int i; MonoClass *ic; @@ -2890,14 +2909,19 @@ collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, MonoError if (*res == NULL) *res = g_ptr_array_new (); + if (*ifaces == NULL) + *ifaces = g_hash_table_new (NULL, NULL); + if (g_hash_table_lookup (*ifaces, ic)) + continue; g_ptr_array_add (*res, ic); + g_hash_table_insert (*ifaces, ic, ic); mono_class_init (ic); if (mono_class_has_failure (ic)) { mono_error_set_type_load_class (error, ic, "Error Loading class"); return; } - collect_implemented_interfaces_aux (ic, res, error); + collect_implemented_interfaces_aux (ic, res, ifaces, error); return_if_nok (error); } } @@ -2906,8 +2930,11 @@ GPtrArray* mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error) { GPtrArray *res = NULL; + GHashTable *ifaces = NULL; - collect_implemented_interfaces_aux (klass, &res, error); + collect_implemented_interfaces_aux (klass, &res, &ifaces, error); + if (ifaces) + g_hash_table_destroy (ifaces); if (!mono_error_ok (error)) { if (res) g_ptr_array_free (res, TRUE); @@ -2917,7 +2944,8 @@ mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error) } static int -compare_interface_ids (const void *p_key, const void *p_element) { +compare_interface_ids (const void *p_key, const void *p_element) +{ const MonoClass *key = (const MonoClass *)p_key; const MonoClass *element = *(const MonoClass **)p_element; @@ -2926,7 +2954,8 @@ compare_interface_ids (const void *p_key, const void *p_element) { /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/ int -mono_class_interface_offset (MonoClass *klass, MonoClass *itf) { +mono_class_interface_offset (MonoClass *klass, MonoClass *itf) +{ MonoClass **result = (MonoClass **)mono_binary_search ( itf, klass->interfaces_packed, @@ -2951,12 +2980,25 @@ mono_class_interface_offset (MonoClass *klass, MonoClass *itf) { * FIXME figure out MS disambiguation rules and fix this function. */ int -mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match) { +mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match) +{ int i = mono_class_interface_offset (klass, itf); *non_exact_match = FALSE; if (i >= 0) return i; + if (itf->is_array_special_interface && klass->rank < 2) { + MonoClass *gtd = mono_class_get_generic_type_definition (itf); + + for (i = 0; i < klass->interface_offsets_count; i++) { + // printf ("\t%s\n", mono_type_get_full_name (klass->interfaces_packed [i])); + if (mono_class_get_generic_type_definition (klass->interfaces_packed [i]) == gtd) { + *non_exact_match = TRUE; + return klass->interface_offsets_packed [i]; + } + } + } + if (!mono_class_has_variant_generic_params (itf)) return -1; @@ -2971,7 +3013,8 @@ mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gbo } static void -print_implemented_interfaces (MonoClass *klass) { +print_implemented_interfaces (MonoClass *klass) +{ char *name; MonoError error; GPtrArray *ifaces = NULL; @@ -2986,7 +3029,7 @@ print_implemented_interfaces (MonoClass *klass) { printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i, klass->interfaces_packed [i]->interface_id, klass->interface_offsets_packed [i], - klass->interfaces_packed [i]->method.count, + mono_class_get_method_count (klass->interfaces_packed [i]), klass->interfaces_packed [i]->name_space, klass->interfaces_packed [i]->name ); printf ("Interface flags: "); @@ -3025,7 +3068,7 @@ print_implemented_interfaces (MonoClass *klass) { printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i, ic->interface_id, mono_class_interface_offset (klass, ic), - ic->method.count, + mono_class_get_method_count (ic), ic->name_space, ic->name ); } @@ -3036,282 +3079,6 @@ print_implemented_interfaces (MonoClass *klass) { } } -static MonoClass* -inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0) -{ - MonoType *args [1]; - args [0] = &arg0->byval_arg; - - return mono_class_bind_generic_parameters (gtype, 1, args, FALSE); -} - -static MonoClass* -array_class_get_if_rank (MonoClass *klass, guint rank) -{ - return rank ? mono_array_class_get (klass, rank) : klass; -} - -static void -fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *eclass, int rank) -{ - valuetype_types [0] = eclass; - if (eclass == mono_defaults.int16_class) - valuetype_types [1] = mono_defaults.uint16_class; - else if (eclass == mono_defaults.uint16_class) - valuetype_types [1] = mono_defaults.int16_class; - else if (eclass == mono_defaults.int32_class) - valuetype_types [1] = mono_defaults.uint32_class; - else if (eclass == mono_defaults.uint32_class) - valuetype_types [1] = mono_defaults.int32_class; - else if (eclass == mono_defaults.int64_class) - valuetype_types [1] = mono_defaults.uint64_class; - else if (eclass == mono_defaults.uint64_class) - valuetype_types [1] = mono_defaults.int64_class; - else if (eclass == mono_defaults.byte_class) - valuetype_types [1] = mono_defaults.sbyte_class; - else if (eclass == mono_defaults.sbyte_class) - valuetype_types [1] = mono_defaults.byte_class; - else if (eclass->enumtype && mono_class_enum_basetype (eclass)) - valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass)); -} - -static GENERATE_GET_CLASS_WITH_CACHE (generic_icollection, System.Collections.Generic, ICollection`1) -static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerable, System.Collections.Generic, IEnumerable`1) -static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerator, System.Collections.Generic, IEnumerator`1) -static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlylist, System.Collections.Generic, IReadOnlyList`1) -static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlycollection, System.Collections.Generic, IReadOnlyCollection`1) - -/* this won't be needed once bug #325495 is completely fixed - * though we'll need something similar to know which interfaces to allow - * in arrays when they'll be lazyly created - * - * FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery. - * MS returns diferrent types based on which instance is called. For example: - * object obj = new byte[10][]; - * Type a = ((IEnumerable)obj).GetEnumerator ().GetType (); - * Type b = ((IEnumerable>)obj).GetEnumerator ().GetType (); - * a != b ==> true - * - * Fixing this should kill quite some code, save some bits and improve compatibility. - */ -static MonoClass** -get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator) -{ - MonoClass *eclass = klass->element_class; - MonoClass* generic_icollection_class; - MonoClass* generic_ienumerable_class; - MonoClass* generic_ienumerator_class; - MonoClass* generic_ireadonlylist_class; - MonoClass* generic_ireadonlycollection_class; - MonoClass *valuetype_types[2] = { NULL, NULL }; - MonoClass **interfaces = NULL; - int i, nifaces, interface_count, real_count, original_rank; - int all_interfaces; - gboolean internal_enumerator; - gboolean eclass_is_valuetype; - - if (!mono_defaults.generic_ilist_class) { - *num = 0; - return NULL; - } - internal_enumerator = FALSE; - eclass_is_valuetype = FALSE; - original_rank = eclass->rank; - if (klass->byval_arg.type != MONO_TYPE_SZARRAY) { - MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); - if (gklass && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) { - /* - * For a Enumerator we need to get the list of interfaces for T. - */ - eclass = mono_class_from_mono_type (gklass->context.class_inst->type_argv [0]); - original_rank = eclass->rank; - if (!eclass->rank) - eclass = eclass->element_class; - internal_enumerator = TRUE; - *is_enumerator = TRUE; - } else { - *num = 0; - return NULL; - } - } - - /* - * with this non-lazy impl we can't implement all the interfaces so we do just the minimal stuff - * for deep levels of arrays of arrays (string[][] has all the interfaces, string[][][] doesn't) - */ - all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE; - - generic_icollection_class = mono_class_get_generic_icollection_class (); - generic_ienumerable_class = mono_class_get_generic_ienumerable_class (); - generic_ienumerator_class = mono_class_get_generic_ienumerator_class (); - generic_ireadonlylist_class = mono_class_get_generic_ireadonlylist_class (); - generic_ireadonlycollection_class = mono_class_get_generic_ireadonlycollection_class (); - - mono_class_init (eclass); - - /* - * Arrays in 2.0 need to implement a number of generic interfaces - * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending - * on the element class). For net 4.5, we also need to implement IReadOnlyList`1/IReadOnlyCollection`1. - * We collect the types needed to build the - * instantiations in interfaces at intervals of 3/5, because 3/5 are - * the generic interfaces needed to implement. - * - * On 4.5, as an optimization, we don't expand ref classes for the variant generic interfaces - * (IEnumerator, IReadOnlyList and IReadOnlyColleciton). The regular dispatch code can handle those cases. - */ - if (eclass->valuetype) { - nifaces = generic_ireadonlylist_class ? 5 : 3; - fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank); - - /* IList, ICollection, IEnumerable, IReadOnlyList`1 */ - real_count = interface_count = valuetype_types [1] ? (nifaces * 2) : nifaces; - if (internal_enumerator) { - ++real_count; - if (valuetype_types [1]) - ++real_count; - } - - interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count); - interfaces [0] = valuetype_types [0]; - if (valuetype_types [1]) - interfaces [nifaces] = valuetype_types [1]; - - eclass_is_valuetype = TRUE; - } else { - int j; - int idepth = eclass->idepth; - if (!internal_enumerator) - idepth--; - nifaces = generic_ireadonlylist_class ? 2 : 3; - - // FIXME: This doesn't seem to work/required for generic params - if (!(eclass->this_arg.type == MONO_TYPE_VAR || eclass->this_arg.type == MONO_TYPE_MVAR || (image_is_dynamic (eclass->image) && !eclass->wastypebuilder))) - mono_class_setup_interface_offsets (eclass); - - interface_count = all_interfaces? eclass->interface_offsets_count: eclass->interface_count; - /* we add object for interfaces and the supertypes for the other - * types. The last of the supertypes is the element class itself which we - * already created the explicit interfaces for (so we include it for IEnumerator - * and exclude it for arrays). - */ - if (MONO_CLASS_IS_INTERFACE (eclass)) - interface_count++; - else - interface_count += idepth; - if (eclass->rank && eclass->element_class->valuetype) { - fill_valuetype_array_derived_types (valuetype_types, eclass->element_class, original_rank); - if (valuetype_types [1]) - ++interface_count; - } - /* IList, ICollection, IEnumerable, IReadOnlyList */ - interface_count *= nifaces; - real_count = interface_count; - if (internal_enumerator) { - real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count; - if (valuetype_types [1]) - ++real_count; - } - interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count); - if (MONO_CLASS_IS_INTERFACE (eclass)) { - interfaces [0] = mono_defaults.object_class; - j = nifaces; - } else { - j = 0; - for (i = 0; i < idepth; i++) { - mono_class_init (eclass->supertypes [i]); - interfaces [j] = eclass->supertypes [i]; - j += nifaces; - } - } - if (all_interfaces) { - for (i = 0; i < eclass->interface_offsets_count; i++) { - interfaces [j] = eclass->interfaces_packed [i]; - j += nifaces; - } - } else { - for (i = 0; i < eclass->interface_count; i++) { - interfaces [j] = eclass->interfaces [i]; - j += nifaces; - } - } - if (valuetype_types [1]) { - interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank); - j += nifaces; - } - } - - /* instantiate the generic interfaces */ - for (i = 0; i < interface_count; i += nifaces) { - MonoClass *iface = interfaces [i]; - - interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface); - interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface); - - if (eclass->valuetype) { - interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface); - if (generic_ireadonlylist_class) { - interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface); - interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface); - } - } else { - if (!generic_ireadonlylist_class) - interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface); - } - } - if (internal_enumerator) { - int j; - /* instantiate IEnumerator */ - for (i = 0; i < interface_count; i++) { - interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]); - } - j = interface_count; - if (!eclass_is_valuetype) { - if (MONO_CLASS_IS_INTERFACE (eclass)) { - interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, mono_defaults.object_class); - j ++; - } else { - for (i = 0; i < eclass->idepth; i++) { - interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->supertypes [i]); - j ++; - } - } - for (i = 0; i < eclass->interface_offsets_count; i++) { - interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->interfaces_packed [i]); - j ++; - } - } else { - interfaces [j++] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [0], original_rank)); - } - if (valuetype_types [1]) - interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [1], original_rank)); - } -#if 0 - { - char *type_name = mono_type_get_name_full (&klass->byval_arg, 0); - for (i = 0; i < real_count; ++i) { - char *name = mono_type_get_name_full (&interfaces [i]->byval_arg, 0); - g_print ("%s implements %s\n", type_name, name); - g_free (name); - } - g_free (type_name); - } -#endif - *num = real_count; - return interfaces; -} - -static int -find_array_interface (MonoClass *klass, const char *name) -{ - int i; - for (i = 0; i < klass->interface_count; ++i) { - if (strcmp (klass->interfaces [i]->name, name) == 0) - return i; - } - return -1; -} - /* * Return the number of virtual methods. * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods. @@ -3321,7 +3088,7 @@ find_array_interface (MonoClass *klass, const char *name) static int count_virtual_methods (MonoClass *klass) { - int i, count = 0; + int i, mcount, vcount = 0; guint32 flags; klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/ @@ -3330,20 +3097,23 @@ count_virtual_methods (MonoClass *klass) if (mono_class_has_failure (klass)) return -1; - for (i = 0; i < klass->method.count; ++i) { + mcount = mono_class_get_method_count (klass); + for (i = 0; i < mcount; ++i) { flags = klass->methods [i]->flags; if (flags & METHOD_ATTRIBUTE_VIRTUAL) - ++count; + ++vcount; } } else { - 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); + int first_idx = mono_class_get_first_method_idx (klass); + mcount = mono_class_get_method_count (klass); + for (i = 0; i < mcount; ++i) { + flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS); if (flags & METHOD_ATTRIBUTE_VIRTUAL) - ++count; + ++vcount; } } - return count; + return vcount; } static int @@ -3368,15 +3138,6 @@ find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic) } } -static int -find_interface_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic) -{ - int i = find_interface (num_ifaces, interfaces_full, ic); - if (i >= 0) - return interface_offsets_full [i]; - return -1; -} - static mono_bool set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set) { @@ -3519,30 +3280,25 @@ 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; GPtrArray **ifaces_array = NULL; int interface_offsets_count; - MonoClass **array_interfaces = NULL; - int num_array_interfaces; - int is_enumerator = FALSE; + + mono_loader_lock (); mono_class_setup_supertypes (klass); - /* - * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator - * implicit interfaces have the property that they are assigned the same slot in the - * vtables for compatible interfaces - */ - array_interfaces = get_implicit_generic_array_interfaces (klass, &num_array_interfaces, &is_enumerator); /* compute maximum number of slots and maximum interface id */ max_iid = 0; - num_ifaces = num_array_interfaces; /* this can include duplicated ones */ + num_ifaces = 0; /* this can include duplicated ones */ ifaces_array = g_new0 (GPtrArray *, klass->idepth); for (j = 0; j < klass->idepth; j++) { k = klass->supertypes [j]; + g_assert (k); num_ifaces += k->interface_count; for (i = 0; i < k->interface_count; i++) { ic = k->interfaces [i]; @@ -3572,13 +3328,6 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) } } - for (i = 0; i < num_array_interfaces; ++i) { - ic = array_interfaces [i]; - mono_class_init (ic); - if (max_iid < ic->interface_id) - max_iid = ic->interface_id; - } - if (MONO_CLASS_IS_INTERFACE (klass)) { num_ifaces++; if (max_iid < klass->interface_id) @@ -3633,63 +3382,12 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) if (MONO_CLASS_IS_INTERFACE (klass)) set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE); - if (num_array_interfaces) { - if (is_enumerator) { - int ienumerator_idx = find_array_interface (klass, "IEnumerator`1"); - int ienumerator_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ienumerator_idx]); - g_assert (ienumerator_offset >= 0); - for (i = 0; i < num_array_interfaces; ++i) { - ic = array_interfaces [i]; - if (strcmp (ic->name, "IEnumerator`1") == 0) - set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, ienumerator_offset, TRUE); - else - g_assert_not_reached (); - /*g_print ("type %s has %s offset at %d (%s)\n", klass->name, ic->name, interface_offsets_full [ic->interface_id], klass->interfaces [0]->name);*/ - } - } else { - int ilist_offset, icollection_offset, ienumerable_offset, ireadonlylist_offset, ireadonlycollection_offset; - int ilist_iface_idx = find_array_interface (klass, "IList`1"); - MonoClass* ilist_class = klass->interfaces [ilist_iface_idx]; - int ireadonlylist_iface_idx = find_array_interface (klass, "IReadOnlyList`1"); - MonoClass* ireadonlylist_class = ireadonlylist_iface_idx != -1 ? klass->interfaces [ireadonlylist_iface_idx] : NULL; - int icollection_iface_idx = find_array_interface (ilist_class, "ICollection`1"); - int ienumerable_iface_idx = find_array_interface (ilist_class, "IEnumerable`1"); - int ireadonlycollection_iface_idx = ireadonlylist_iface_idx != -1 ? find_array_interface (ireadonlylist_class, "IReadOnlyCollection`1") : -1; - ilist_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ilist_iface_idx]); - icollection_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [icollection_iface_idx]); - ienumerable_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [ienumerable_iface_idx]); - ireadonlylist_offset = ireadonlylist_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ireadonlylist_iface_idx]) : -1; - ireadonlycollection_offset = ireadonlycollection_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ireadonlylist_class->interfaces [ireadonlycollection_iface_idx]) : -1; - g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0); - for (i = 0; i < num_array_interfaces; ++i) { - int offset; - ic = array_interfaces [i]; - if (mono_class_get_generic_class (ic)->container_class == mono_defaults.generic_ilist_class) - offset = ilist_offset; - else if (strcmp (ic->name, "ICollection`1") == 0) - offset = icollection_offset; - else if (strcmp (ic->name, "IEnumerable`1") == 0) - offset = ienumerable_offset; - else if (strcmp (ic->name, "IReadOnlyList`1") == 0) - offset = ireadonlylist_offset; - else if (strcmp (ic->name, "IReadOnlyCollection`1") == 0) - offset = ireadonlycollection_offset; - else - g_assert_not_reached (); - set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, offset, TRUE); - /*g_print ("type %s has %s offset at %d (%s)\n", klass->name, ic->name, offset, klass->interfaces [0]->name);*/ - } - } - } - for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) { if (interface_offsets_full [i] != -1) interface_offsets_count ++; } /* Publish the data */ - mono_loader_lock (); - klass->max_interface_id = max_iid; /* * We might get called multiple times: @@ -3715,12 +3413,10 @@ 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]; - /*if (num_array_interfaces) - g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&klass->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/ } #ifdef COMPRESSED_INTERFACE_BITMAP i = mono_compress_bitmap (NULL, bitmap, bsize); @@ -3731,12 +3427,11 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) klass->interface_bitmap = bitmap; #endif } +end: mono_loader_unlock (); -end: g_free (interfaces_full); g_free (interface_offsets_full); - g_free (array_interfaces); for (i = 0; i < klass->idepth; i++) { ifaces = ifaces_array [i]; if (ifaces) @@ -4201,7 +3896,7 @@ mono_method_try_get_vtable_index (MonoMethod *method) static void mono_class_verify_vtable (MonoClass *klass) { - int i; + int i, count; char *full_name = mono_type_full_name (&klass->byval_arg); printf ("*** Verifying VTable of class '%s' \n", full_name); @@ -4211,7 +3906,8 @@ mono_class_verify_vtable (MonoClass *klass) if (!klass->methods) return; - for (i = 0; i < klass->method.count; ++i) { + count = mono_class_method_count (klass); + for (i = 0; i < count; ++i) { MonoMethod *cm = klass->methods [i]; int slot; @@ -4241,33 +3937,35 @@ mono_class_verify_vtable (MonoClass *klass) #endif static void -print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) { - int index; +print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) +{ + int index, mcount; char *method_signature; char *type_name; for (index = 0; index < onum; ++index) { - mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name, + mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)", im_slot, overrides [index*2+1]->name, overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot); } method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE); type_name = mono_type_full_name (&klass->byval_arg); - mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s\n", + mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s", mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name); g_free (method_signature); g_free (type_name); mono_class_setup_methods (klass); if (mono_class_has_failure (klass)) { char *name = mono_type_get_full_name (klass); - mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name); + mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods", name); g_free (name); return; } - for (index = 0; index < klass->method.count; ++index) { + mcount = mono_class_get_method_count (klass); + for (index = 0; index < mcount; ++index) { MonoMethod *cm = klass->methods [index]; method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE); - mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)\n", cm->name, method_signature); + mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)", cm->name, method_signature); g_free (method_signature); } } @@ -4344,8 +4042,9 @@ 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; + MonoMethod **vtable = NULL; + int i, max_vtsize = 0, cur_slot = 0; + guint32 max_iid; GPtrArray *ifaces = NULL; GHashTable *override_map = NULL; MonoMethod *cm; @@ -4371,7 +4070,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o } else if (ifaces) { for (i = 0; i < ifaces->len; i++) { MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i); - max_vtsize += ic->method.count; + max_vtsize += mono_class_get_method_count (ic); } g_ptr_array_free (ifaces, TRUE); ifaces = NULL; @@ -4388,7 +4087,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o cur_slot = klass->parent->vtable_size; } - max_vtsize += klass->method.count; + max_vtsize += mono_class_get_method_count (klass); /*Array have a slot for stelemref*/ if (mono_class_need_stelemref_method (klass)) { @@ -4397,9 +4096,6 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o ++cur_slot; } - vtable = (MonoMethod **)alloca (sizeof (gpointer) * max_vtsize); - memset (vtable, 0, sizeof (gpointer) * max_vtsize); - /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */ cur_slot = setup_interface_offsets (klass, cur_slot, TRUE); @@ -4437,7 +4133,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o /* Have to set method->slot for abstract virtual methods */ if (klass->methods && gklass->methods) { - for (i = 0; i < klass->method.count; ++i) + int mcount = mono_class_get_method_count (klass); + for (i = 0; i < mcount; ++i) if (klass->methods [i]->slot == -1) klass->methods [i]->slot = gklass->methods [i]->slot; } @@ -4445,6 +4142,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o return; } + vtable = (MonoMethod **)g_malloc0 (sizeof (gpointer) * max_vtsize); + if (klass->parent && klass->parent->vtable_size) { MonoClass *parent = klass->parent; int i; @@ -4468,7 +4167,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/ TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name)); - for (j = 0; j < parent_interface->method.count && !mono_class_has_failure (klass); j++) { + int mcount = mono_class_get_method_count (parent_interface); + for (j = 0; j < mcount && !mono_class_has_failure (klass); j++) { vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j]; TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n", parent_interface_offset + j, parent_interface_offset, j, @@ -4499,7 +4199,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o dslot = mono_method_get_vtable_slot (decl); if (dslot == -1) { mono_class_set_type_load_failure (klass, ""); - return; + goto fail; } dslot += mono_class_interface_offset (klass, decl->klass); @@ -4563,7 +4263,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o } // Loop on all interface methods... - for (im_index = 0; im_index < ic->method.count; im_index++) { + int mcount = mono_class_get_method_count (ic); + for (im_index = 0; im_index < mcount; im_index++) { MonoMethod *im = ic->methods [im_index]; int im_slot = ic_offset + im->slot; MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL; @@ -4629,7 +4330,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 (! (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_ABSTRACT)) { + if (!mono_class_is_abstract (klass)) { for (i = 0; i < klass->interface_offsets_count; i++) { int ic_offset; int im_index; @@ -4637,7 +4338,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o ic = klass->interfaces_packed [i]; ic_offset = mono_class_interface_offset (klass, ic); - for (im_index = 0; im_index < ic->method.count; im_index++) { + int mcount = mono_class_get_method_count (ic); + for (im_index = 0; im_index < mcount; im_index++) { MonoMethod *im = ic->methods [im_index]; int im_slot = ic_offset + im->slot; @@ -4772,8 +4474,10 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o g_slist_free (virt_methods); virt_methods = NULL; + g_assert (cur_slot <= max_vtsize); + /* Ensure that all vtable slots are filled with concrete instance methods */ - if (!(mono_class_get_flags (klass) & 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); @@ -4781,6 +4485,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name); g_free (type_name); g_free (method_name); + g_free (vtable); return; } } @@ -4856,6 +4561,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o } } + g_free (vtable); + VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass)); return; @@ -4864,6 +4571,7 @@ fail: char *name = mono_type_get_full_name (klass); mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name); g_free (name); + g_free (vtable); if (override_map) g_hash_table_destroy (override_map); if (virt_methods) @@ -4888,7 +4596,7 @@ mono_method_get_vtable_slot (MonoMethod *method) return -1; if (method->slot == -1) { MonoClass *gklass; - int i; + int i, mcount; if (!mono_class_is_ginst (method->klass)) { g_assert (method->is_inflated); @@ -4900,11 +4608,12 @@ mono_method_get_vtable_slot (MonoMethod *method) 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) { + mcount = mono_class_get_method_count (method->klass); + for (i = 0; i < mcount; ++i) { if (method->klass->methods [i] == method) break; } - g_assert (i < method->klass->method.count); + g_assert (i < mcount); g_assert (gklass->methods); method->slot = gklass->methods [i]->slot; } @@ -4975,13 +4684,14 @@ static GenericArrayMethodInfo *generic_array_method_info = NULL; static int generic_array_methods (MonoClass *klass) { - int i, count_generic = 0; + int i, count_generic = 0, mcount; GList *list = NULL, *tmp; if (generic_array_method_num) return generic_array_method_num; mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/ g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/ - for (i = 0; i < klass->parent->method.count; i++) { + mcount = mono_class_get_method_count (klass->parent); + for (i = 0; i < mcount; i++) { MonoMethod *m = klass->parent->methods [i]; if (!strncmp (m->name, "InternalArray__", 15)) { count_generic++; @@ -5214,7 +4924,13 @@ 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)) @@ -5224,7 +4940,8 @@ mono_class_init (MonoClass *klass) if (mono_class_has_failure (klass)) goto leave; - for (i = 0; i < klass->method.count; ++i) { + int mcount = mono_class_get_method_count (klass); + for (i = 0; i < mcount; ++i) { MonoMethod *method = klass->methods [i]; if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".cctor", method->name) == 0)) { @@ -5270,16 +4987,10 @@ 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; - + if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) mono_stats.generic_class_count++; - klass->method = gklass->method; - klass->field = gklass->field; - } - - if (klass->generic_class || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes)) + 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; @@ -5290,7 +5001,7 @@ mono_class_init (MonoClass *klass) klass->has_finalize_inited = TRUE; } if (klass->rank) - klass->method.count = array_method_count; + mono_class_set_method_count (klass, array_method_count); mono_loader_unlock (); locked = FALSE; @@ -5309,13 +5020,14 @@ mono_class_init (MonoClass *klass) init_list = g_slist_remove (init_list, klass); mono_native_tls_set_value (init_pending_tls_id, init_list); - /* Because of the double-checking locking pattern */ - mono_memory_barrier (); - klass->inited = 1; - if (locked) mono_loader_unlock (); + /* Leave this for last */ + mono_loader_lock (); + klass->inited = 1; + mono_loader_unlock (); + return !mono_class_has_failure (klass); } @@ -5370,16 +5082,14 @@ mono_class_has_finalizer (MonoClass *klass) } } - mono_image_lock (klass->image); - + mono_loader_lock (); if (!klass->has_finalize_inited) { klass->has_finalize = has_finalize ? 1 : 0; mono_memory_barrier (); klass->has_finalize_inited = TRUE; } - - mono_image_unlock (klass->image); + mono_loader_unlock (); return klass->has_finalize; } @@ -5514,8 +5224,22 @@ mono_class_setup_mono_type (MonoClass *klass) klass->this_arg.type = (MonoTypeEnum)t; } - if (MONO_CLASS_IS_INTERFACE (klass)) + if (MONO_CLASS_IS_INTERFACE (klass)) { klass->interface_id = mono_get_unique_iid (klass); + + if (is_corlib && !strcmp (nspace, "System.Collections.Generic")) { + //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood + /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery. + * MS returns diferrent types based on which instance is called. For example: + * object obj = new byte[10][]; + * Type a = ((IEnumerable)obj).GetEnumerator ().GetType (); + * Type b = ((IEnumerable>)obj).GetEnumerator ().GetType (); + * a != b ==> true + */ + if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1")) + klass->is_array_special_interface = 1; + } + } } #ifndef DISABLE_COM @@ -5645,12 +5369,12 @@ mono_class_setup_parent (MonoClass *klass, MonoClass *parent) * - supertypes: array of classes: each element has a class in the hierarchy * starting from @class up to System.Object * - * LOCKING: This function is atomic, in case of contention we waste memory. + * LOCKING: Acquires the loader lock. */ void mono_class_setup_supertypes (MonoClass *klass) { - int ms; + int ms, idepth; MonoClass **supertypes; mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes); @@ -5660,15 +5384,15 @@ mono_class_setup_supertypes (MonoClass *klass) if (klass->parent && !klass->parent->supertypes) mono_class_setup_supertypes (klass->parent); if (klass->parent) - klass->idepth = klass->parent->idepth + 1; + idepth = klass->parent->idepth + 1; else - klass->idepth = 1; + idepth = 1; - ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, klass->idepth); + ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth); supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms); if (klass->parent) { - CHECKED_METADATA_WRITE_PTR ( supertypes [klass->idepth - 1] , klass ); + CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass ); int supertype_idx; for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++) @@ -5677,7 +5401,14 @@ mono_class_setup_supertypes (MonoClass *klass) CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass ); } - CHECKED_METADATA_WRITE_PTR_ATOMIC ( klass->supertypes , supertypes ); + mono_memory_barrier (); + + mono_loader_lock (); + klass->idepth = idepth; + /* Needed so idepth is visible before supertypes is set */ + mono_memory_barrier (); + klass->supertypes = supertypes; + mono_loader_unlock (); } static gboolean @@ -5751,10 +5482,12 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError 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; @@ -5845,6 +5578,42 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError #endif klass->cast_class = klass->element_class = klass; + if (mono_is_corlib_image (klass->image)) { + switch (klass->byval_arg.type) { + case MONO_TYPE_I1: + if (mono_defaults.byte_class) + klass->cast_class = mono_defaults.byte_class; + break; + case MONO_TYPE_U1: + if (mono_defaults.sbyte_class) + mono_defaults.sbyte_class = klass; + break; + case MONO_TYPE_I2: + if (mono_defaults.uint16_class) + mono_defaults.uint16_class = klass; + break; + case MONO_TYPE_U2: + if (mono_defaults.int16_class) + klass->cast_class = mono_defaults.int16_class; + break; + case MONO_TYPE_I4: + if (mono_defaults.uint32_class) + mono_defaults.uint32_class = klass; + break; + case MONO_TYPE_U4: + if (mono_defaults.int32_class) + klass->cast_class = mono_defaults.int32_class; + break; + case MONO_TYPE_I8: + if (mono_defaults.uint64_class) + mono_defaults.uint64_class = klass; + break; + case MONO_TYPE_U8: + if (mono_defaults.int64_class) + klass->cast_class = mono_defaults.int64_class; + break; + } + } if (!klass->enumtype) { if (!mono_metadata_interfaces_from_typedef_full ( @@ -5856,6 +5625,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; @@ -5866,8 +5638,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); @@ -5880,19 +5654,14 @@ 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; - else - klass->field.count = 0; - + mono_class_set_field_count (klass, field_last - first_field_idx); if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows) - klass->method.count = method_last - klass->method.first; - else - klass->method.count = 0; + mono_class_set_method_count (klass, method_last - first_method_idx); /* reserve space to store vector pointer in arrays */ if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) { klass->instance_size += 2 * sizeof (gpointer); - g_assert (klass->field.count == 0); + g_assert (mono_class_get_field_count (klass) == 0); } if (klass->enumtype) { @@ -5923,6 +5692,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) { if (!strncmp (name, "Vector", 6)) klass->simd_type = !strcmp (name + 6, "2d") || !strcmp (name + 6, "2ul") || !strcmp (name + 6, "2l") || !strcmp (name + 6, "4f") || !strcmp (name + 6, "4ui") || !strcmp (name + 6, "4i") || !strcmp (name + 6, "8s") || !strcmp (name + 6, "8us") || !strcmp (name + 6, "16b") || !strcmp (name + 6, "16sb"); + } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) { + if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4")) + klass->simd_type = 1; } mono_loader_unlock (); @@ -5970,6 +5742,7 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd) mono_error_cleanup (&error); } } + mono_loader_lock (); if (klass->parent) mono_class_setup_parent (klass, klass->parent); @@ -5977,8 +5750,15 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd) klass->cast_class = gtd->cast_class; klass->element_class = gtd->element_class; } + mono_loader_unlock (); } +gboolean +mono_type_is_primitive (MonoType *type) +{ + return (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_R8) || + type-> type == MONO_TYPE_I || type->type == MONO_TYPE_U; +} /* * Create the `MonoClass' for an instantiation of a generic type. @@ -5992,19 +5772,10 @@ mono_generic_class_get_class (MonoGenericClass *gclass) if (gclass->cached_class) return gclass->cached_class; - mono_loader_lock (); - if (gclass->cached_class) { - mono_loader_unlock (); - return gclass->cached_class; - } - klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst)); gklass = gclass->container_class; - if (record_gclass_instantiation > 0) - gclass_recorded_list = g_slist_append (gclass_recorded_list, klass); - if (gklass->nested_in) { /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/ klass->nested_in = gklass->nested_in; @@ -6013,11 +5784,8 @@ mono_generic_class_get_class (MonoGenericClass *gclass) klass->name = gklass->name; klass->name_space = gklass->name_space; - mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); - klass->image = gklass->image; klass->type_token = gklass->type_token; - klass->field.count = gklass->field.count; klass->class_kind = MONO_CLASS_GINST; //FIXME add setter @@ -6030,17 +5798,16 @@ mono_generic_class_get_class (MonoGenericClass *gclass) klass->enumtype = gklass->enumtype; klass->valuetype = gklass->valuetype; - klass->cast_class = klass->element_class = klass; - - if (mono_class_is_nullable (klass)) - klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass); - /* - * We're not interested in the nested classes of a generic instance. - * We use the generic type definition to look for nested classes. - */ + if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) { + g_assert (gclass->context.class_inst); + g_assert (gclass->context.class_inst->type_argc > 0); + if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0])) + klass->simd_type = 1; + } + klass->is_array_special_interface = gklass->is_array_special_interface; - mono_generic_class_setup_parent (klass, gklass); + klass->cast_class = klass->element_class = klass; if (gclass->is_dynamic) { /* @@ -6051,8 +5818,6 @@ mono_generic_class_get_class (MonoGenericClass *gclass) if (!gklass->wastypebuilder) klass->inited = 1; - mono_class_setup_supertypes (klass); - if (klass->enumtype) { /* * For enums, gklass->fields might not been set, but instance_size etc. is @@ -6061,17 +5826,36 @@ mono_generic_class_get_class (MonoGenericClass *gclass) */ klass->instance_size = gklass->instance_size; klass->sizes.class_size = gklass->sizes.class_size; - mono_memory_barrier (); klass->size_inited = 1; } } + mono_loader_lock (); + + if (gclass->cached_class) { + mono_loader_unlock (); + return gclass->cached_class; + } + + if (record_gclass_instantiation > 0) + gclass_recorded_list = g_slist_append (gclass_recorded_list, klass); + + if (mono_class_is_nullable (klass)) + klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass); + + mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); + + mono_generic_class_setup_parent (klass, gklass); + + if (gclass->is_dynamic) + mono_class_setup_supertypes (klass); + mono_memory_barrier (); gclass->cached_class = klass; mono_profiler_class_loaded (klass, MONO_PROFILE_OK); - inflated_classes ++; + ++class_ginst_count; inflated_classes_size += sizeof (MonoClassGenericInst); mono_loader_unlock (); @@ -6136,6 +5920,7 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo) 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 ); @@ -6389,7 +6174,6 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GN return mono_class_from_generic_parameter_internal (param); } - MonoClass * mono_ptr_class_get (MonoType *type) { @@ -6413,6 +6197,7 @@ mono_ptr_class_get (MonoType *type) result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer)); classes_size += sizeof (MonoClassPointer); + ++class_pointer_count; result->parent = NULL; /* no parent for PTR types */ result->name_space = el_class->name_space; @@ -6458,20 +6243,19 @@ mono_ptr_class_get (MonoType *type) static MonoClass * mono_fnptr_class_get (MonoMethodSignature *sig) { - MonoClass *result; + MonoClass *result, *cached; static GHashTable *ptr_hash = NULL; /* FIXME: These should be allocate from a mempool as well, but which one ? */ mono_loader_lock (); - if (!ptr_hash) ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); - - if ((result = (MonoClass *)g_hash_table_lookup (ptr_hash, sig))) { - mono_loader_unlock (); - return result; - } + cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig); + mono_loader_unlock (); + if (cached) + return cached; + result = g_new0 (MonoClass, 1); result->parent = NULL; /* no parent for PTR types */ @@ -6479,22 +6263,32 @@ mono_fnptr_class_get (MonoMethodSignature *sig) 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->instance_size = sizeof (MonoObject) + sizeof (gpointer); result->cast_class = result->element_class = result; - result->blittable = TRUE; - result->byval_arg.type = MONO_TYPE_FNPTR; result->this_arg.type = result->byval_arg.type; result->this_arg.data.method = result->byval_arg.data.method = sig; result->this_arg.byref = TRUE; result->blittable = TRUE; + result->inited = TRUE; mono_class_setup_supertypes (result); + mono_loader_lock (); + + cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig); + if (cached) { + g_free (result); + mono_loader_unlock (); + return cached; + } + + mono_profiler_class_event (result, MONO_PROFILE_START_LOAD); + + classes_size += sizeof (MonoClassPointer); + ++class_pointer_count; + g_hash_table_insert (ptr_hash, sig, result); mono_loader_unlock (); @@ -6639,7 +6433,7 @@ MonoClass * mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) { MonoImage *image; - MonoClass *klass; + MonoClass *klass, *cached, *k; MonoClass *parent = NULL; GSList *list, *rootlist = NULL; int nsize; @@ -6653,37 +6447,35 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) image = eclass->image; + /* Check cache */ + cached = NULL; if (rank == 1 && !bounded) { - /* - * This case is very frequent not just during compilation because of calls - * from mono_class_from_mono_type (), mono_array_new (), + /* + * This case is very frequent not just during compilation because of calls + * from mono_class_from_mono_type (), mono_array_new (), * Array:CreateInstance (), etc, so use a separate cache + a separate lock. */ mono_os_mutex_lock (&image->szarray_cache_lock); if (!image->szarray_cache) image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - klass = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass); + cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass); mono_os_mutex_unlock (&image->szarray_cache_lock); - if (klass) - return klass; - - mono_loader_lock (); } else { mono_loader_lock (); - if (!image->array_cache) image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - - if ((rootlist = list = (GSList *)g_hash_table_lookup (image->array_cache, eclass))) { - for (; list; list = list->next) { - klass = (MonoClass *)list->data; - if ((klass->rank == rank) && (klass->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) { - mono_loader_unlock (); - return klass; - } + rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass); + for (list = rootlist; list; list = list->next) { + k = (MonoClass *)list->data; + if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) { + cached = k; + break; } } + mono_loader_unlock (); } + if (cached) + return cached; parent = mono_defaults.array_class; if (!parent->inited) @@ -6708,10 +6500,6 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) klass->name = mono_image_strdup (image, name); g_free (name); - mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); - - classes_size += sizeof (MonoClassArray); - klass->type_token = 0; klass->parent = parent; klass->instance_size = mono_class_instance_size (klass->parent); @@ -6724,9 +6512,10 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image)); mono_error_cleanup (&prepared_error); } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) { - if (!eclass->ref_info_handle || eclass->wastypebuilder) { + guint32 ref_info_handle = mono_class_get_ref_info_handle (eclass); + if (!ref_info_handle || eclass->wastypebuilder) { g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type"); - g_assert (eclass->ref_info_handle && !eclass->wastypebuilder); + g_assert (ref_info_handle && !eclass->wastypebuilder); } /* element_size -1 is ok as this is not an instantitable type*/ klass->sizes.element_size = -1; @@ -6737,7 +6526,8 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) if (mono_class_is_ginst (eclass)) mono_class_init (eclass); - mono_class_init_sizes (eclass); + if (!eclass->size_inited) + mono_class_setup_fields (eclass); mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type"); /*FIXME we fail the array type, but we have to let other fields be set.*/ @@ -6791,19 +6581,37 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) klass->this_arg = klass->byval_arg; klass->this_arg.byref = 1; - //WTF was this? it's wrong - // klass->generic_container = eclass->generic_container; + mono_loader_lock (); + /* Check cache again */ + cached = NULL; if (rank == 1 && !bounded) { - MonoClass *prev_class; + mono_os_mutex_lock (&image->szarray_cache_lock); + cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass); + mono_os_mutex_unlock (&image->szarray_cache_lock); + } else { + rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass); + for (list = rootlist; list; list = list->next) { + k = (MonoClass *)list->data; + if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) { + cached = k; + break; + } + } + } + if (cached) { + mono_loader_unlock (); + return cached; + } + + mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); + classes_size += sizeof (MonoClassArray); + ++class_array_count; + + if (rank == 1 && !bounded) { mono_os_mutex_lock (&image->szarray_cache_lock); - prev_class = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass); - if (prev_class) - /* Someone got in before us */ - klass = prev_class; - else - g_hash_table_insert (image->szarray_cache, eclass, klass); + g_hash_table_insert (image->szarray_cache, eclass, klass); mono_os_mutex_unlock (&image->szarray_cache_lock); } else { list = g_slist_append (rootlist, klass); @@ -6843,7 +6651,7 @@ gint32 mono_class_instance_size (MonoClass *klass) { if (!klass->size_inited) - mono_class_init_sizes (klass); + mono_class_init (klass); return klass->instance_size; } @@ -6860,7 +6668,7 @@ gint32 mono_class_min_align (MonoClass *klass) { if (!klass->size_inited) - mono_class_init_sizes (klass); + mono_class_init (klass); return klass->min_align; } @@ -6904,8 +6712,8 @@ mono_class_data_size (MonoClass *klass) if (!klass->inited) mono_class_init (klass); /* This can happen with dynamically created types */ - if (!klass->size_inited) - mono_class_init_sizes (klass); + if (!klass->fields_inited) + mono_class_setup_fields (klass); /* in arrays, sizes.class_size is unioned with element_size * and arrays have no static fields @@ -6928,23 +6736,25 @@ mono_class_get_field_idx (MonoClass *klass, int idx) return NULL; while (klass) { + int first_field_idx = mono_class_get_first_field_idx (klass); + int fcount = mono_class_get_field_count (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.*/ const char *name = mono_metadata_string_heap (klass->image, mono_metadata_decode_row_col (&klass->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME)); int i; - for (i = 0; i < klass->field.count; ++i) + for (i = 0; i < fcount; ++i) if (mono_field_get_name (&klass->fields [i]) == name) return &klass->fields [i]; 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 (fcount) { + if ((idx >= first_field_idx) && (idx < first_field_idx + fcount)){ + return &klass->fields [idx - first_field_idx]; } } } @@ -7010,7 +6820,8 @@ mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoTyp return NULL; while (klass) { - for (i = 0; i < klass->field.count; ++i) { + int fcount = mono_class_get_field_count (klass); + for (i = 0; i < fcount; ++i) { MonoClassField *field = &klass->fields [i]; if (strcmp (name, mono_field_get_name (field)) != 0) @@ -7048,9 +6859,11 @@ mono_class_get_field_token (MonoClassField *field) while (klass) { if (!klass->fields) return 0; - for (i = 0; i < klass->field.count; ++i) { + int first_field_idx = mono_class_get_first_field_idx (klass); + int fcount = mono_class_get_field_count (klass); + for (i = 0; i < fcount; ++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); @@ -7068,8 +6881,7 @@ static int mono_field_get_index (MonoClassField *field) { int index = field - field->parent->fields; - - g_assert (index >= 0 && index < field->parent->field.count); + g_assert (index >= 0 && index < mono_class_get_field_count (field->parent)); return index; } @@ -7086,26 +6898,20 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ guint32 constant_cols [MONO_CONSTANT_SIZE]; int field_index; MonoClass *klass = field->parent; + MonoFieldDefaultValue *def_values; g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT); - if (!klass->ext || !klass->ext->field_def_values) { - MonoFieldDefaultValue *def_values; - - mono_class_alloc_ext (klass); + def_values = mono_class_get_field_def_values (klass); + if (!def_values) { + def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass)); - def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count); - - mono_image_lock (klass->image); - mono_memory_barrier (); - if (!klass->ext->field_def_values) - klass->ext->field_def_values = def_values; - mono_image_unlock (klass->image); + mono_class_set_field_def_values (klass, def_values); } field_index = mono_field_get_index (field); - if (!klass->ext->field_def_values [field_index].data) { + if (!def_values [field_index].data) { cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0); if (!cindex) return NULL; @@ -7113,20 +6919,22 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)); mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE); - klass->ext->field_def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE]; - klass->ext->field_def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]); + def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE]; + mono_memory_barrier (); + def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]); } - *def_type = klass->ext->field_def_values [field_index].def_type; - return klass->ext->field_def_values [field_index].data; + *def_type = def_values [field_index].def_type; + return def_values [field_index].data; } static int mono_property_get_index (MonoProperty *prop) { - int index = prop - prop->parent->ext->properties; + MonoClassPropertyInfo *info = mono_class_get_property_info (prop->parent); + int index = prop - info->properties; - g_assert (index >= 0 && index < prop->parent->ext->property.count); + g_assert (index >= 0 && index < info->count); return index; } @@ -7151,10 +6959,11 @@ mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def */ if (image_is_dynamic (klass->image)) { + MonoClassPropertyInfo *info = mono_class_get_property_info (klass); int prop_index = mono_property_get_index (property); - if (klass->ext->prop_def_values && klass->ext->prop_def_values [prop_index].data) { - *def_type = klass->ext->prop_def_values [prop_index].def_type; - return klass->ext->prop_def_values [prop_index].data; + if (info->def_values && info->def_values [prop_index].data) { + *def_type = info->def_values [prop_index].def_type; + return info->def_values [prop_index].data; } return NULL; } @@ -7174,10 +6983,11 @@ mono_class_get_event_token (MonoEvent *event) int i; while (klass) { - if (klass->ext) { - for (i = 0; i < klass->ext->event.count; ++i) { - if (&klass->ext->events [i] == event) - return mono_metadata_make_token (MONO_TABLE_EVENT, klass->ext->event.first + i + 1); + MonoClassEventInfo *info = mono_class_get_event_info (klass); + if (info) { + for (i = 0; i < info->count; ++i) { + if (&info->events [i] == event) + return mono_metadata_make_token (MONO_TABLE_EVENT, info->first + i + 1); } } klass = klass->parent; @@ -7225,9 +7035,10 @@ mono_class_get_property_token (MonoProperty *prop) MonoProperty* p; int i = 0; gpointer iter = NULL; + MonoClassPropertyInfo *info = mono_class_get_property_info (klass); while ((p = mono_class_get_properties (klass, &iter))) { - if (&klass->ext->properties [i] == prop) - return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->ext->property.first + i + 1); + if (&info->properties [i] == prop) + return mono_metadata_make_token (MONO_TABLE_PROPERTY, info->first + i + 1); i ++; } @@ -8324,7 +8135,7 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) } /* interface_offsets might not be set for dynamic classes */ - if (oklass->ref_info_handle && !oklass->interface_bitmap) { + if (mono_class_get_ref_info_handle (oklass) && !oklass->interface_bitmap) { /* * oklass might be a generic type parameter but they have * interface_offsets set. @@ -8342,6 +8153,23 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id)) return TRUE; + if (klass->is_array_special_interface && oklass->rank == 1) { + //XXX we could offset this by having the cast target computed at JIT time + //XXX we could go even further and emit a wrapper that would do the extra type check + MonoClass *iface_klass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]); + MonoClass *obj_klass = oklass->cast_class; //This gets us the cast class of element type of the array + + // If the target we're trying to cast to is a valuetype, we must account of weird valuetype equivalences such as IntEnum <> int or uint <> int + // We can't apply it for ref types as this would go wrong with arrays - IList would have byte tested + if (iface_klass->valuetype) + iface_klass = iface_klass->cast_class; + + //array covariant casts only operates on scalar to scalar + //This is so int[] can't be casted to IComparable[] + if (!(obj_klass->valuetype && !iface_klass->valuetype) && mono_class_is_assignable_from (iface_klass, obj_klass)) + return TRUE; + } + if (mono_class_has_variant_generic_params (klass)) { int i; mono_class_setup_interfaces (oklass, &error); @@ -8458,7 +8286,7 @@ mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate) /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/ if (image_is_dynamic (candidate->image) && !candidate->wastypebuilder) { - MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info (candidate); + MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info_raw (candidate); /* FIXME use handles */ int j; if (tb && tb->interfaces) { for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) { @@ -8579,9 +8407,14 @@ mono_class_get_cctor (MonoClass *klass) return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME); } + mono_class_init (klass); + if (!klass->has_cctor) return NULL; + if (mono_class_is_ginst (klass) && !klass->methods) + return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class)); + if (mono_class_get_cached_class_info (klass, &cached_info)) { MonoError error; MonoMethod *result = mono_get_method_checked (klass->image, cached_info.cctor_token, klass, NULL, &error); @@ -8590,9 +8423,6 @@ mono_class_get_cctor (MonoClass *klass) return result; } - if (mono_class_is_ginst (klass) && !klass->methods) - return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class)); - return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME); } @@ -9045,7 +8875,7 @@ mono_class_get_byref_type (MonoClass *klass) int mono_class_num_fields (MonoClass *klass) { - return klass->field.count; + return mono_class_get_field_count (klass); } /** @@ -9057,7 +8887,7 @@ mono_class_num_fields (MonoClass *klass) int mono_class_num_methods (MonoClass *klass) { - return klass->method.count; + return mono_class_get_method_count (klass); } /** @@ -9071,7 +8901,7 @@ mono_class_num_properties (MonoClass *klass) { mono_class_setup_properties (klass); - return klass->ext->property.count; + return mono_class_get_property_info (klass)->count; } /** @@ -9085,7 +8915,7 @@ mono_class_num_events (MonoClass *klass) { mono_class_setup_events (klass); - return klass->ext->event.count; + return mono_class_get_event_info (klass)->count; } /** @@ -9111,7 +8941,7 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter) if (mono_class_has_failure (klass)) return NULL; /* start from the first */ - if (klass->field.count) { + if (mono_class_get_field_count (klass)) { *iter = &klass->fields [0]; return &klass->fields [0]; } else { @@ -9121,7 +8951,7 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter) } field = (MonoClassField *)*iter; field++; - if (field < &klass->fields [klass->field.count]) { + if (field < &klass->fields [mono_class_get_field_count (klass)]) { *iter = field; return field; } @@ -9156,7 +8986,7 @@ mono_class_get_methods (MonoClass* klass, gpointer *iter) if (!klass->methods) return NULL; /* start from the first */ - if (klass->method.count) { + if (mono_class_get_method_count (klass)) { *iter = &klass->methods [0]; return klass->methods [0]; } else { @@ -9166,7 +8996,7 @@ mono_class_get_methods (MonoClass* klass, gpointer *iter) } method = (MonoMethod **)*iter; method++; - if (method < &klass->methods [klass->method.count]) { + if (method < &klass->methods [mono_class_get_method_count (klass)]) { *iter = method; return *method; } @@ -9201,12 +9031,13 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) method = (MonoMethod **)*iter; method++; } - while (method < &klass->methods [klass->method.count]) { + int mcount = mono_class_get_method_count (klass); + while (method < &klass->methods [mcount]) { if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL)) break; method ++; } - if (method < &klass->methods [klass->method.count]) { + if (method < &klass->methods [mcount]) { *iter = method; return *method; } else { @@ -9223,19 +9054,21 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) start_index = GPOINTER_TO_UINT (*iter); } - for (i = start_index; i < klass->method.count; ++i) { + int first_idx = mono_class_get_first_method_idx (klass); + int mcount = mono_class_get_method_count (klass); + for (i = start_index; i < mcount; ++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; } - if (i < klass->method.count) { + if (i < mcount) { 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 */ @@ -9267,9 +9100,10 @@ mono_class_get_properties (MonoClass* klass, gpointer *iter) return NULL; if (!*iter) { mono_class_setup_properties (klass); + MonoClassPropertyInfo *info = mono_class_get_property_info (klass); /* start from the first */ - if (klass->ext->property.count) { - *iter = &klass->ext->properties [0]; + if (info->count) { + *iter = &info->properties [0]; return (MonoProperty *)*iter; } else { /* no fields */ @@ -9278,7 +9112,8 @@ mono_class_get_properties (MonoClass* klass, gpointer *iter) } property = (MonoProperty *)*iter; property++; - if (property < &klass->ext->properties [klass->ext->property.count]) { + MonoClassPropertyInfo *info = mono_class_get_property_info (klass); + if (property < &info->properties [info->count]) { *iter = property; return (MonoProperty *)*iter; } @@ -9305,9 +9140,10 @@ mono_class_get_events (MonoClass* klass, gpointer *iter) return NULL; if (!*iter) { mono_class_setup_events (klass); + MonoClassEventInfo *info = mono_class_get_event_info (klass); /* start from the first */ - if (klass->ext->event.count) { - *iter = &klass->ext->events [0]; + if (info->count) { + *iter = &info->events [0]; return (MonoEvent *)*iter; } else { /* no fields */ @@ -9316,7 +9152,8 @@ mono_class_get_events (MonoClass* klass, gpointer *iter) } event = (MonoEvent *)*iter; event++; - if (event < &klass->ext->events [klass->ext->event.count]) { + MonoClassEventInfo *info = mono_class_get_event_info (klass); + if (event < &info->events [info->count]) { *iter = event; return (MonoEvent *)*iter; } @@ -9380,8 +9217,12 @@ setup_nested_types (MonoClass *klass) if (klass->nested_classes_inited) return; - if (!klass->type_token) + if (!klass->type_token) { + mono_loader_lock (); klass->nested_classes_inited = TRUE; + mono_loader_unlock (); + return; + } i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1); classes = NULL; @@ -9403,23 +9244,18 @@ setup_nested_types (MonoClass *klass) i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1); } - mono_class_alloc_ext (klass); - nested_classes = NULL; for (l = classes; l; l = l->next) nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data); g_list_free (classes); - mono_image_lock (klass->image); - - mono_memory_barrier (); + mono_loader_lock (); if (!klass->nested_classes_inited) { - klass->ext->nested_classes = nested_classes; + mono_class_set_nested_classes_property (klass, nested_classes); mono_memory_barrier (); klass->nested_classes_inited = TRUE; } - - mono_image_unlock (klass->image); + mono_loader_unlock (); } /** @@ -9446,10 +9282,11 @@ mono_class_get_nested_types (MonoClass* klass, gpointer *iter) setup_nested_types (klass); if (!*iter) { + GList *nested_classes = mono_class_get_nested_classes_property (klass); /* start from the first */ - if (klass->ext && klass->ext->nested_classes) { - *iter = klass->ext->nested_classes; - return (MonoClass *)klass->ext->nested_classes->data; + if (nested_classes) { + *iter = nested_classes; + return (MonoClass *)nested_classes->data; } else { /* no nested types */ return NULL; @@ -9584,31 +9421,28 @@ mono_field_get_rva (MonoClassField *field) guint32 rva; int field_index; MonoClass *klass = field->parent; - MonoFieldDefaultValue *field_def_values; + MonoFieldDefaultValue *def_values; g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA); - if (!klass->ext || !klass->ext->field_def_values) { - mono_class_alloc_ext (klass); - - field_def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count); + def_values = mono_class_get_field_def_values (klass); + if (!def_values) { + def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass)); - mono_image_lock (klass->image); - if (!klass->ext->field_def_values) - klass->ext->field_def_values = field_def_values; - mono_image_unlock (klass->image); + mono_class_set_field_def_values (klass, def_values); } field_index = mono_field_get_index (field); - if (!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); + if (!def_values [field_index].data && !image_is_dynamic (klass->image)) { + int first_field_idx = mono_class_get_first_field_idx (klass); + mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL); if (!rva) g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name); - klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva); + def_values [field_index].data = mono_image_rva_map (field->parent->image, rva); } - return klass->ext->field_def_values [field_index].data; + return def_values [field_index].data; } /** @@ -9792,17 +9626,19 @@ 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 () */ - for (i = 0; i < klass->method.count; ++i) { + int first_idx = mono_class_get_first_method_idx (klass); + int mcount = mono_class_get_method_count (klass); + for (i = 0; i < mcount; ++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; @@ -9864,7 +9700,8 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p */ if (!klass->methods) return NULL; - for (i = 0; i < klass->method.count; ++i) { + int mcount = mono_class_get_method_count (klass); + for (i = 0; i < mcount; ++i) { MonoMethod *method = klass->methods [i]; if (method->name[0] == name [0] && @@ -9904,7 +9741,7 @@ mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error) mono_loader_lock (); klass->has_failure = 1; - mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, boxed_error); + mono_class_set_exception_data (klass, boxed_error); mono_loader_unlock (); return TRUE; @@ -9951,19 +9788,6 @@ mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...) return mono_class_set_failure (klass, box); } -/* - * mono_class_get_exception_data: - * - * Return the exception_data property of KLASS. - * - * LOCKING: Acquires the loader lock. - */ -static gpointer -mono_class_get_exception_data (const MonoClass *klass) -{ - return mono_image_property_lookup (klass->image, (MonoClass*)klass, MONO_CLASS_PROP_EXCEPTION_DATA); -} - /** * mono_classes_init: * @@ -9977,16 +9801,24 @@ mono_classes_init (void) 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); } /** @@ -10498,7 +10330,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; @@ -10509,7 +10343,7 @@ gboolean mono_class_is_valid_enum (MonoClass *klass) { return FALSE; } - if ((mono_class_get_flags (klass) & 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))) { @@ -10525,7 +10359,7 @@ gboolean mono_class_is_valid_enum (MonoClass *klass) { if (!found_base_field) return FALSE; - if (klass->method.count > 0) + if (mono_class_get_method_count (klass) > 0) return FALSE; return TRUE; @@ -10553,28 +10387,6 @@ mono_class_setup_interface_id (MonoClass *klass) mono_loader_unlock (); } -/* - * mono_class_alloc_ext: - * - * Allocate klass->ext if not already done. - */ -void -mono_class_alloc_ext (MonoClass *klass) -{ - MonoClassExt *ext; - - if (klass->ext) - return; - - ext = (MonoClassExt *)mono_class_alloc0 (klass, sizeof (MonoClassExt)); - mono_image_lock (klass->image); - mono_memory_barrier (); - if (!klass->ext) - klass->ext = ext; - class_ext_size += sizeof (MonoClassExt); - mono_image_unlock (klass->image); -} - /* * mono_class_setup_interfaces: * @@ -10629,8 +10441,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error) interfaces = NULL; } - mono_image_lock (klass->image); - + mono_loader_lock (); if (!klass->interfaces_inited) { klass->interface_count = interface_count; klass->interfaces = interfaces; @@ -10639,8 +10450,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error) klass->interfaces_inited = TRUE; } - - mono_image_unlock (klass->image); + mono_loader_unlock (); } static void @@ -10649,6 +10459,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) MonoClass *klass = field->parent; MonoImage *image = klass->image; MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL; + MonoType *ftype; int field_idx = field - klass->fields; mono_error_init (error); @@ -10662,7 +10473,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) g_free (full_name); } - field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error); + ftype = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error); if (!mono_error_ok (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)); @@ -10672,7 +10483,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) 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)); @@ -10684,7 +10495,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) 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)) { @@ -10701,13 +10512,15 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) /* FIELD signature == 0x06 */ g_assert (*sig == 0x06); - field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error); - if (!field->type) { + ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error); + if (!ftype) { 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); } } + mono_memory_barrier (); + field->type = ftype; } static guint32 @@ -10718,12 +10531,11 @@ mono_field_resolve_flags (MonoClassField *field) MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL; int field_idx = field - klass->fields; - if (gtd) { MonoClassField *gfield = >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)); @@ -10757,7 +10569,7 @@ mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter) if (!klass->fields) return NULL; /* start from the first */ - if (klass->field.count) { + if (mono_class_get_field_count (klass)) { *iter = &klass->fields [0]; return (MonoClassField *)*iter; } else { @@ -10767,7 +10579,7 @@ mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter) } field = (MonoClassField *)*iter; field++; - if (field < &klass->fields [klass->field.count]) { + if (field < &klass->fields [mono_class_get_field_count (klass)]) { *iter = field; return (MonoClassField *)*iter; } @@ -10782,3 +10594,156 @@ mono_class_full_name (MonoClass *klass) /* Declare all shared lazy type lookup functions */ GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle) + +/** + * mono_method_get_base_method: + * @method: a method + * @definition: if true, get the definition + * @error: set on failure + * + * Given a virtual method associated with a subclass, return the corresponding + * method from an ancestor. If @definition is FALSE, returns the method in the + * superclass of the given method. If @definition is TRUE, return the method + * in the ancestor class where it was first declared. The type arguments will + * be inflated in the ancestor classes. If the method is not associated with a + * class, or isn't virtual, returns the method itself. On failure returns NULL + * and sets @error. + */ +MonoMethod* +mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error) +{ + MonoClass *klass, *parent; + MonoGenericContext *generic_inst = NULL; + MonoMethod *result = NULL; + int slot; + + if (method->klass == NULL) + return method; + + if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || + MONO_CLASS_IS_INTERFACE (method->klass) || + method->flags & METHOD_ATTRIBUTE_NEW_SLOT) + return method; + + slot = mono_method_get_vtable_slot (method); + if (slot == -1) + return method; + + klass = method->klass; + if (mono_class_is_ginst (klass)) { + generic_inst = mono_class_get_context (klass); + klass = mono_class_get_generic_class (klass)->container_class; + } + +retry: + if (definition) { + /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */ + for (parent = klass->parent; parent != NULL; parent = parent->parent) { + /* on entry, klass is either a plain old non-generic class and generic_inst == NULL + or klass is the generic container class and generic_inst is the instantiation. + + when we go to the parent, if the parent is an open constructed type, we need to + replace the type parameters by the definitions from the generic_inst, and then take it + apart again into the klass and the generic_inst. + + For cases like this: + class C : B { + public override void Foo () { ... } + } + class B : A> { + public override void Foo () { ... } + } + class A { + public virtual void Foo () { ... } + } + + if at each iteration the parent isn't open, we can skip inflating it. if at some + iteration the parent isn't generic (after possible inflation), we set generic_inst to + NULL; + */ + MonoGenericContext *parent_inst = NULL; + if (mono_class_is_open_constructed_type (mono_class_get_type (parent))) { + parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error); + return_val_if_nok (error, NULL); + } + if (mono_class_is_ginst (parent)) { + parent_inst = mono_class_get_context (parent); + parent = mono_class_get_generic_class (parent)->container_class; + } + + mono_class_setup_vtable (parent); + if (parent->vtable_size <= slot) + break; + klass = parent; + generic_inst = parent_inst; + } + } else { + klass = klass->parent; + if (!klass) + return method; + if (mono_class_is_open_constructed_type (mono_class_get_type (klass))) { + klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error); + return_val_if_nok (error, NULL); + + generic_inst = NULL; + } + if (mono_class_is_ginst (klass)) { + generic_inst = mono_class_get_context (klass); + klass = mono_class_get_generic_class (klass)->container_class; + } + + } + + if (generic_inst) { + klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error); + return_val_if_nok (error, NULL); + } + + if (klass == method->klass) + return method; + + /*This is possible if definition == FALSE. + * Do it here to be really sure we don't read invalid memory. + */ + if (slot >= klass->vtable_size) + return method; + + mono_class_setup_vtable (klass); + + result = klass->vtable [slot]; + if (result == NULL) { + /* It is an abstract method */ + gboolean found = FALSE; + gpointer iter = NULL; + while ((result = mono_class_get_methods (klass, &iter))) { + if (result->slot == slot) { + found = TRUE; + break; + } + } + /* found might be FALSE if we looked in an abstract class + * that doesn't override an abstract method of its + * parent: + * abstract class Base { + * public abstract void Foo (); + * } + * abstract class Derived : Base { } + * class Child : Derived { + * public override void Foo () { } + * } + * + * if m was Child.Foo and we ask for the base method, + * then we get here with klass == Derived and found == FALSE + */ + /* but it shouldn't be the case that if we're looking + * for the definition and didn't find a result; the + * loop above should've taken us as far as we could + * go! */ + g_assert (!(definition && !found)); + if (!found) + goto retry; + } + + g_assert (result != NULL); + return result; +}