X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=4cdd90efbc65b23268ce3a76736e17c9a89a7729;hb=cd0f05d6fd528c0f63327a908e2be2f4a9620933;hp=aec749bd499416a18f95fc8dda2e789a98e70dd1;hpb=08224d944e54989a25d4f9b04ff3b852e8890fe6;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index aec749bd499..4cdd90efbc6 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -4,14 +4,8 @@ * Author: * Miguel de Icaza (miguel@ximian.com) * - * (C) 2001 Ximian, Inc. + * (C) 2001-2006 Novell, Inc. * - * Possible Optimizations: - * in mono_class_create, do not allocate the class right away, - * but wait until you know the size of the FieldMap, so that - * the class embeds directly the FieldMap after the vtable. - * - * */ #include #include @@ -35,11 +29,15 @@ #include #include #include +#include MonoStats mono_stats; gboolean mono_print_vtable = FALSE; +/* Function supplied by the runtime to find classes by name using information from the AOT file */ +static MonoGetClassFromName get_class_from_name = NULL; + static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token); static void mono_class_create_generic (MonoInflatedGenericClass *gclass); static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res); @@ -47,6 +45,16 @@ static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedCl void (*mono_debugger_start_class_init_func) (MonoClass *klass) = NULL; void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL; +/* + * mono_class_from_typeref: + * @image: a MonoImage + * @type_token: a TypeRef token + * + * Creates the MonoClass* structure representing the type defined by + * the typeref token valid inside @image. + * Returns: the MonoClass* representing the typeref token, NULL ifcould + * not be loaded. + */ MonoClass * mono_class_from_typeref (MonoImage *image, guint32 type_token) { @@ -70,7 +78,19 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) /* a typedef in disguise */ return mono_class_from_name (image, nspace, name); case MONO_RESOLTION_SCOPE_MODULEREF: - return mono_class_from_name (image->modules [idx - 1], nspace, name); + if (image->modules [idx-1]) + return mono_class_from_name (image->modules [idx - 1], nspace, name); + else { + char *msg = g_strdup_printf ("%s%s%s", nspace, nspace [0] ? "." : "", name); + char *human_name; + + human_name = mono_stringify_assembly_name (&image->assembly->aname); + mono_loader_set_error_type_load (msg, human_name); + g_free (msg); + g_free (human_name); + + return NULL; + } case MONO_RESOLTION_SCOPE_TYPEREF: { MonoClass *enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx); GList *tmp; @@ -109,8 +129,19 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) /* If this assert fails, it probably means that you haven't installed an assembly load/search hook */ g_assert (references == image->references); g_assert (references [idx - 1]); - if (references [idx - 1] == (gpointer)-1) + + /* If the assembly did not load, register this as a type load exception */ + if (references [idx - 1] == REFERENCE_MISSING){ + MonoAssemblyName aname; + char *human_name; + + mono_assembly_get_assemblyref (image, idx - 1, &aname); + human_name = mono_stringify_assembly_name (&aname); + mono_loader_set_error_assembly_load (human_name, image->assembly->ref_only); + g_free (human_name); + return NULL; + } return mono_class_from_name (references [idx - 1]->image, nspace, name); } @@ -189,6 +220,8 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed, mono_type_get_name_recurse ( &type->data.array->eklass->byval_arg, str, FALSE, nested_format); g_string_append_c (str, '['); + if (rank == 1) + g_string_append_c (str, '*'); for (i = 1; i < rank; i++) g_string_append_c (str, ','); g_string_append_c (str, ']'); @@ -352,6 +385,12 @@ mono_type_get_full_name (MonoClass *class) return mono_type_get_name_full (mono_class_get_type (class), MONO_TYPE_NAME_FORMAT_REFLECTION); } +/** + * mono_type_get_name: + * @type: a type + * + * Returns: the string representation for type as it would be represented in IL code. + */ char* mono_type_get_name (MonoType *type) { @@ -373,6 +412,14 @@ mono_type_get_underlying_type (MonoType *type) return type; } +/* + * mono_class_is_open_constructed_type: + * @type: a type + * + * Returns TRUE if type represents a generics open constructed type + * (not all the type parameters required for the instantiation have + * been provided). + */ gboolean mono_class_is_open_constructed_type (MonoType *t) { @@ -530,6 +577,15 @@ mono_get_inflated_generic_class (MonoGenericClass *gclass) return (MonoInflatedGenericClass *) gclass; } +/* + * mono_class_inflate_generic_type: + * @type: a type + * @context: a generics context + * + * Instantiate the generic type @type, using the generics context @context. + * + * Returns: the instantiated type + */ MonoType* mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context) { @@ -576,6 +632,15 @@ inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflat return res; } +/* + * mono_class_inflate_generic_method: + * @method: a generic method + * @context: a generics context + * + * Instantiate the generic method @method using the generics context @context. + * + * Returns: the new instantiated method + */ MonoMethod * mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context) { @@ -659,6 +724,7 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin * For performance reasons, mono_class_inflate_generic_method() does not actually instantiate the * method, it just "prepares" it for that. If you really need to fully instantiate the method * (including its signature and header), call this method. + * FIXME: Martin? this description looks completely wrong. */ MonoMethod * mono_get_inflated_method (MonoMethod *method) @@ -678,7 +744,6 @@ mono_class_find_enum_basetype (MonoClass *class) { MonoImage *m = class->image; const int top = class->field.count; - MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD]; int i; g_assert (class->enumtype); @@ -693,7 +758,7 @@ mono_class_find_enum_basetype (MonoClass *class) MonoGenericContainer *container = NULL; MonoType *ftype; - mono_metadata_decode_row (t, idx, cols, MONO_FIELD_SIZE); + mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE); sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]); mono_metadata_decode_value (sig, &sig); /* FIELD signature == 0x06 */ @@ -726,16 +791,16 @@ mono_class_find_enum_basetype (MonoClass *class) * @class: The class to initialize * * Initializes the class->fields. - * Assumes the loader lock is held. + * LOCKING: Assumes the loader lock is held. */ static void mono_class_setup_fields (MonoClass *class) { MonoImage *m = class->image; - const int top = class->field.count; + int top = class->field.count; guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK; - MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD]; - int i, blittable = TRUE, real_size = 0; + int i, blittable = TRUE; + guint32 real_size = 0; guint32 packing_size = 0; gboolean explicit_size; MonoClassField *field; @@ -745,13 +810,19 @@ mono_class_setup_fields (MonoClass *class) if (class->size_inited) return; - if (class->inited) - mono_class_init (class); + if (class->generic_class) { + MonoClass *gklass = class->generic_class->container_class; + mono_class_setup_fields (gklass); + top = gklass->field.count; + } class->instance_size = 0; - class->class_size = 0; + if (!class->rank) + class->sizes.class_size = 0; if (class->parent) { + /* For generic instances, class->parent might not have been initialized */ + mono_class_init (class->parent); if (!class->parent->size_inited) mono_class_setup_fields (class->parent); class->instance_size += class->parent->instance_size; @@ -827,7 +898,7 @@ mono_class_setup_fields (MonoClass *class) const char *sig; guint32 cols [MONO_FIELD_SIZE]; - mono_metadata_decode_row (t, idx, cols, MONO_FIELD_SIZE); + mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE); /* The name is needed for fieldrefs */ field->name = mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]); sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]); @@ -837,12 +908,14 @@ mono_class_setup_fields (MonoClass *class) field->type = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig); if (!field->type) { mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); - continue; + break; } if (mono_field_is_deleted (field)) continue; if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) { - mono_metadata_field_info (m, idx, &field->offset, NULL, NULL); + guint32 offset; + mono_metadata_field_info (m, idx, &offset, NULL, NULL); + field->offset = offset; if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) g_warning ("%s not initialized correctly (missing field layout info for %s)", class->name, field->name); @@ -889,6 +962,8 @@ mono_class_setup_fields (MonoClass *class) class->instance_size = MAX (real_size, class->instance_size); } + if (class->exception_type) + return; mono_class_layout_fields (class); } @@ -896,7 +971,7 @@ mono_class_setup_fields (MonoClass *class) * mono_class_setup_fields_locking: * @class: The class to initialize * - * Initializes the class->fields. + * Initializes the class->fields array of fields. * Aquires the loader lock. */ static void @@ -927,9 +1002,24 @@ mono_class_has_references (MonoClass *klass) } /* useful until we keep track of gc-references in corlib etc. */ +#ifdef HAVE_SGEN_GC +#define IS_GC_REFERENCE(t) FALSE +#else #define IS_GC_REFERENCE(t) ((t)->type == MONO_TYPE_U || (t)->type == MONO_TYPE_I || (t)->type == MONO_TYPE_PTR) +#endif /* + * mono_class_layout_fields: + * @class: a class + * + * Compute the placement of fields inside an object or struct, according to + * the layout rules and set the following fields in @class: + * - has_references (if the class contains instance references firled or structs that contain references) + * - has_static_refs (same, but for static fields) + * - instance_size (size of the object in memory) + * - class_size (size needed for the static fields) + * - size_inited (flag set when the instance_size is set) + * * LOCKING: this is supposed to be called with the loader lock held. */ void @@ -1115,6 +1205,16 @@ mono_class_layout_fields (MonoClass *class) break; } + if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) { + /* + * For small structs, set min_align to at least the struct size, since the + * JIT memset/memcpy code assumes this and generates unaligned accesses + * otherwise. See #78990 for a testcase. + */ + if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer)) + class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject)); + } + class->size_inited = 1; /* @@ -1131,19 +1231,22 @@ mono_class_layout_fields (MonoClass *class) continue; size = mono_type_size (field->type, &align); - field->offset = class->class_size; + field->offset = class->sizes.class_size; field->offset += align - 1; field->offset &= ~(align - 1); - class->class_size = field->offset + size; + class->sizes.class_size = field->offset + size; } } /* * mono_class_setup_methods: + * @class: a class * * Initializes the 'methods' array in the klass. * Calling this method should be avoided if possible since it allocates a lot * of long-living MonoMethod structures. + * Methods belonging to an interface are assigned a sequential slot starting + * from 0. */ void mono_class_setup_methods (MonoClass *class) @@ -1186,7 +1289,6 @@ mono_class_setup_properties (MonoClass *class) { guint startm, endm, i, j; guint32 cols [MONO_PROPERTY_SIZE]; - MonoTableInfo *pt = &class->image->tables [MONO_TABLE_PROPERTY]; MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS]; MonoProperty *properties; guint32 last; @@ -1209,7 +1311,7 @@ mono_class_setup_properties (MonoClass *class) properties = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoProperty) * class->property.count); for (i = class->property.first; i < last; ++i) { - mono_metadata_decode_row (pt, i, cols, MONO_PROPERTY_SIZE); + mono_metadata_decode_table_row (class->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE); properties [i - class->property.first].parent = class; properties [i - class->property.first].attrs = cols [MONO_PROPERTY_FLAGS]; properties [i - class->property.first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]); @@ -1236,6 +1338,9 @@ mono_class_setup_properties (MonoClass *class) mono_loader_unlock (); } +/* + * LOCKING: assumes the loader lock is held. + */ static void inflate_event (MonoClass *class, MonoEvent *event, MonoInflatedGenericClass *gclass) { @@ -1263,10 +1368,22 @@ inflate_event (MonoClass *class, MonoEvent *event, MonoInflatedGenericClass *gcl } if (event->other) { - MonoMethod *inflated = mono_class_inflate_generic_method_full ( - event->other, class, gclass->generic_class.context); + MonoMethod **om = event->other; + int count = 0; + while (*om) { + count++; + om++; + } + om = event->other; + event->other = g_new0 (MonoMethod*, count + 1); + count = 0; + while (*om) { + MonoMethod *inflated = mono_class_inflate_generic_method_full ( + *om, class, gclass->generic_class.context); - event->other = mono_get_inflated_method (inflated); + event->other [count++] = mono_get_inflated_method (inflated); + om++; + } } } @@ -1275,7 +1392,6 @@ mono_class_setup_events (MonoClass *class) { guint startm, endm, i, j; guint32 cols [MONO_EVENT_SIZE]; - MonoTableInfo *pt = &class->image->tables [MONO_TABLE_EVENT]; MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS]; guint32 last; MonoEvent *events; @@ -1320,8 +1436,8 @@ mono_class_setup_events (MonoClass *class) events = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoEvent) * class->event.count); for (i = class->event.first; i < last; ++i) { MonoEvent *event = &events [i - class->event.first]; - - mono_metadata_decode_row (pt, i, cols, MONO_EVENT_SIZE); + + mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE); event->parent = class; event->attrs = cols [MONO_EVENT_FLAGS]; event->name = mono_metadata_string_heap (class->image, cols [MONO_EVENT_NAME]); @@ -1343,13 +1459,15 @@ mono_class_setup_events (MonoClass *class) int n = 0; if (event->other == NULL) { - event->other = g_new0 (MonoMethod*, 1); + event->other = g_new0 (MonoMethod*, 2); } else { while (event->other [n]) n++; - event->other = g_realloc (event->other, (n + 1) * sizeof (MonoMethod*)); + event->other = g_realloc (event->other, (n + 2) * sizeof (MonoMethod*)); } event->other [n] = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first]; + /* NULL terminated */ + event->other [n + 1] = NULL; break; } default: @@ -1363,49 +1481,84 @@ mono_class_setup_events (MonoClass *class) mono_loader_unlock (); } +/* + * Global pool of interface IDs, represented as a bitset. + * LOCKING: this is supposed to be accessed with the loader lock held. + */ +static MonoBitSet *global_interface_bitset = NULL; + +/* + * mono_unload_interface_ids: + * @bitset: bit set of interface IDs + * + * When an image is unloaded, the interface IDs associated with + * the image are put back in the global pool of IDs so the numbers + * can be reused. + */ +void +mono_unload_interface_ids (MonoBitSet *bitset) +{ + mono_loader_lock (); + mono_bitset_sub (global_interface_bitset, bitset); + mono_loader_unlock (); +} + +/* + * mono_get_unique_iid: + * @class: interface + * + * Assign a unique integer ID to the interface represented by @class. + * The ID will positive and as small as possible. + * LOCKING: this is supposed to be called with the loader lock held. + * Returns: the new ID. + */ static guint mono_get_unique_iid (MonoClass *class) { - static GHashTable *iid_hash = NULL; - static guint iid = 0; - char *str, *type_name; - gpointer value; - int generic_id; + int iid; g_assert (MONO_CLASS_IS_INTERFACE (class)); - mono_loader_lock (); - - if (!iid_hash) - iid_hash = g_hash_table_new (g_str_hash, g_str_equal); - - if (class->generic_class && !class->generic_class->inst->is_open) { - generic_id = class->generic_class->inst->id; - g_assert (generic_id != 0); - } else - generic_id = 0; - - type_name = mono_type_full_name (&class->byval_arg); - str = g_strdup_printf ("%s|%s|%d", class->image->name, type_name, generic_id); - g_free (type_name); - - if (g_hash_table_lookup_extended (iid_hash, str, NULL, &value)) { - mono_loader_unlock (); - if (mono_print_vtable) - printf ("Interface: reusing id %d for %s\n", iid, str); - g_free (str); - return GPOINTER_TO_INT (value); + if (!global_interface_bitset) { + global_interface_bitset = mono_bitset_new (128, 0); + } + + iid = mono_bitset_find_first_unset (global_interface_bitset, -1); + if (iid < 0) { + int old_size = mono_bitset_size (global_interface_bitset); + MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2); + mono_bitset_free (global_interface_bitset); + global_interface_bitset = new_set; + iid = old_size; + } + mono_bitset_set (global_interface_bitset, iid); + /* set the bit also in the per-image set */ + if (class->image->interface_bitset) { + if (iid >= mono_bitset_size (class->image->interface_bitset)) { + MonoBitSet *new_set = mono_bitset_clone (class->image->interface_bitset, iid + 1); + mono_bitset_free (class->image->interface_bitset); + class->image->interface_bitset = new_set; + } } else { - if (mono_print_vtable) - printf ("Interface: assigned id %d to %s\n", iid, str); - g_hash_table_insert (iid_hash, str, GINT_TO_POINTER (iid)); - ++iid; + class->image->interface_bitset = mono_bitset_new (iid + 1, 0); } + mono_bitset_set (class->image->interface_bitset, iid); - mono_loader_unlock (); + if (mono_print_vtable) { + int generic_id; + char *type_name = mono_type_full_name (&class->byval_arg); + if (class->generic_class && !class->generic_class->inst->is_open) { + generic_id = class->generic_class->inst->id; + g_assert (generic_id != 0); + } else { + generic_id = 0; + } + printf ("Interface: assigned id %d to %s|%s|%d\n", iid, class->image->name, type_name, generic_id); + g_free (type_name); + } g_assert (iid <= 65535); - return iid - 1; + return iid; } static void @@ -1502,6 +1655,9 @@ cache_interface_offsets (int max_iid, int *data) return cached; } +/* + * LOCKING: this is supposed to be called with the loader lock held. + */ static int setup_interface_offsets (MonoClass *class, int cur_slot) { @@ -1539,7 +1695,7 @@ setup_interface_offsets (MonoClass *class, int cur_slot) } class->max_interface_id = max_iid; /* compute vtable offset for interfaces */ - class->interface_offsets = g_malloc (sizeof (gpointer) * (max_iid + 1)); + class->interface_offsets = g_malloc (sizeof (int) * (max_iid + 1)); for (i = 0; i <= max_iid; i++) class->interface_offsets [i] = -1; @@ -1582,34 +1738,17 @@ setup_interface_offsets (MonoClass *class, int cur_slot) return cur_slot; } -static void -setup_generic_vtable (MonoClass *class) +/* + * Setup interface offsets for interfaces. Used by Ref.Emit. + */ +void +mono_class_setup_interface_offsets (MonoClass *class) { - MonoClass *gklass; - int i; - - gklass = class->generic_class->container_class; - - mono_class_init (gklass); - class->vtable_size = gklass->vtable_size; - - class->vtable = g_new0 (MonoMethod*, class->vtable_size); - memcpy (class->vtable, gklass->vtable, sizeof (MonoMethod*) * class->vtable_size); - - for (i = 0; i < class->vtable_size; i++) { - MonoMethod *m = class->vtable [i]; - - if (!m) - continue; + mono_loader_lock (); - m = mono_class_inflate_generic_method_full (m, class, class->generic_class->context); - class->vtable [i] = m; - } + setup_interface_offsets (class, 0); - class->max_interface_id = gklass->max_interface_id; - class->interface_offsets = g_new0 (gint, gklass->max_interface_id + 1); - memcpy (class->interface_offsets, gklass->interface_offsets, - sizeof (gint) * (gklass->max_interface_id + 1)); + mono_loader_unlock (); } void @@ -1619,6 +1758,7 @@ mono_class_setup_vtable (MonoClass *class) MonoGenericContext *context; guint32 type_token; int onum = 0; + gboolean ok = TRUE; if (class->vtable) return; @@ -1635,13 +1775,9 @@ mono_class_setup_vtable (MonoClass *class) return; } - if (class->generic_class) { - if (class->generic_class->inst->is_open) { - setup_generic_vtable (class); - mono_loader_unlock (); - return; - } + mono_stats.generic_vtable_count ++; + if (class->generic_class) { context = class->generic_class->context; type_token = class->generic_class->container_class->type_token; } else { @@ -1651,13 +1787,19 @@ mono_class_setup_vtable (MonoClass *class) if (class->image->dynamic) mono_reflection_get_dynamic_overrides (class, &overrides, &onum); - else - mono_class_get_overrides_full (class->image, type_token, &overrides, &onum, context); + else { + /* The following call fails if there are missing methods in the type */ + ok = mono_class_get_overrides_full (class->image, type_token, &overrides, &onum, context); + } - mono_class_setup_vtable_general (class, overrides, onum); + if (ok) + mono_class_setup_vtable_general (class, overrides, onum); + g_free (overrides); mono_loader_unlock (); + + return; } /* @@ -1676,11 +1818,6 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o if (class->vtable) return; - if (class->generic_class && class->generic_class->inst->is_open) { - setup_generic_vtable (class); - return; - } - ifaces = mono_class_get_implemented_interfaces (class); if (ifaces) { for (i = 0; i < ifaces->len; i++) { @@ -1885,11 +2022,14 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o */ if (!(vtable [io + l])) { MonoClass *parent = class->parent; - - if ((ic->interface_id <= parent->max_interface_id) && - (parent->interface_offsets [ic->interface_id] != -1) && - parent->vtable) - vtable [io + l] = parent->vtable [parent->interface_offsets [ic->interface_id] + l]; + + for (; parent; parent = parent->parent) { + if ((ic->interface_id <= parent->max_interface_id) && + (parent->interface_offsets [ic->interface_id] != -1) && + parent->vtable) { + vtable [io + l] = parent->vtable [parent->interface_offsets [ic->interface_id] + l]; + } + } } if (!(vtable [io + l])) { @@ -1952,10 +2092,21 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o int j; for (j = 0; j < k->method.count; ++j) { MonoMethod *m1 = k->methods [j]; + MonoMethodSignature *cmsig, *m1sig; + if (!(m1->flags & METHOD_ATTRIBUTE_VIRTUAL)) continue; + + cmsig = mono_method_signature (cm); + m1sig = mono_method_signature (m1); + + if (!cmsig || !m1sig) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + return; + } + if (!strcmp(cm->name, m1->name) && - mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (m1))) { + mono_metadata_signature_equal (cmsig, m1sig)) { /* CAS - SecurityAction.InheritanceDemand */ if (security_enabled && (m1->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) { @@ -2021,8 +2172,13 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o } else class->vtable_size = cur_slot; - class->vtable = g_malloc0 (sizeof (gpointer) * class->vtable_size); - memcpy (class->vtable, vtable, sizeof (gpointer) * class->vtable_size); + /* Try to share the vtable with our parent. */ + if (class->parent && (class->parent->vtable_size == class->vtable_size) && (memcmp (class->parent->vtable, vtable, sizeof (gpointer) * class->vtable_size) == 0)) { + class->vtable = class->parent->vtable; + } else { + class->vtable = mono_mempool_alloc0 (class->image->mempool, sizeof (gpointer) * class->vtable_size); + memcpy (class->vtable, vtable, sizeof (gpointer) * class->vtable_size); + } if (mono_print_vtable) { int icount = 0; @@ -2068,6 +2224,86 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o } } +static MonoMethod *default_ghc = NULL; +static MonoMethod *default_finalize = NULL; +static int finalize_slot = -1; +static int ghc_slot = -1; + +static void +initialize_object_slots (MonoClass *class) +{ + int i; + if (default_ghc) + return; + if (class == mono_defaults.object_class) { + mono_class_setup_vtable (class); + for (i = 0; i < class->vtable_size; ++i) { + MonoMethod *cm = class->vtable [i]; + + if (!strcmp (cm->name, "GetHashCode")) + ghc_slot = i; + else if (!strcmp (cm->name, "Finalize")) + finalize_slot = i; + } + + g_assert (ghc_slot > 0); + default_ghc = class->vtable [ghc_slot]; + + g_assert (finalize_slot > 0); + default_finalize = class->vtable [finalize_slot]; + } +} + +static GList* +g_list_prepend_mempool (GList* l, MonoMemPool* mp, gpointer datum) +{ + GList* n = mono_mempool_alloc (mp, sizeof (GList)); + n->next = l; + n->prev = NULL; + n->data = datum; + return n; +} + +static void +setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos) +{ + MonoGenericContext *context; + int i; + + context = g_new0 (MonoGenericContext, 1); + context->container = iface->generic_class->context->container; + context->gmethod = g_new0 (MonoGenericMethod, 1); + context->gmethod->generic_class = iface->generic_class; + context->gmethod->inst = iface->generic_class->inst; + + for (i = 0; i < class->parent->method.count; i++) { + MonoMethod *m = class->parent->methods [i]; + MonoMethod *inflated; + const char *mname, *iname; + gchar *name; + + if (!strncmp (m->name, "InternalArray__ICollection_", 27)) { + iname = "System.Collections.Generic.ICollection`1."; + mname = m->name + 27; + } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) { + iname = "System.Collections.Generic.IEnumerable`1."; + mname = m->name + 27; + } else if (!strncmp (m->name, "InternalArray__", 15)) { + iname = "System.Collections.Generic.IList`1."; + mname = m->name + 15; + } else { + continue; + } + + name = mono_mempool_alloc (class->image->mempool, strlen (iname) + strlen (mname) + 1); + strcpy (name, iname); + strcpy (name + strlen (iname), mname); + + inflated = mono_class_inflate_generic_method (m, context); + class->methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, name, inflated); + } +} + /** * mono_class_init: * @class: the class to initialize @@ -2075,23 +2311,23 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o * compute the instance_size, class_size and other infos that cannot be * computed at mono_class_get() time. Also compute a generic vtable and * the method slot numbers. We use this infos later to create a domain - * specific vtable. + * specific vtable. + * + * Returns TRUE on success or FALSE if there was a problem in loading + * the type (incorrect assemblies, missing assemblies, methods, etc). */ -void +gboolean mono_class_init (MonoClass *class) { int i; - static MonoMethod *default_ghc = NULL; - static MonoMethod *default_finalize = NULL; - static int finalize_slot = -1; - static int ghc_slot = -1; MonoCachedClassInfo cached_info; gboolean has_cached_info; - + int class_init_ok = TRUE; + g_assert (class); if (class->inited) - return; + return TRUE; /*g_print ("Init class %s\n", class->name);*/ @@ -2101,7 +2337,7 @@ mono_class_init (MonoClass *class) if (class->inited) { mono_loader_unlock (); /* Somebody might have gotten in before us */ - return; + return TRUE; } if (class->init_pending) { @@ -2184,7 +2420,7 @@ mono_class_init (MonoClass *class) guint32 cols [MONO_NESTED_CLASS_SIZE]; mono_metadata_decode_row (&class->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE); nclass = mono_class_create_from_typedef (class->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]); - class->nested_classes = g_list_prepend (class->nested_classes, nclass); + class->nested_classes = g_list_prepend_mempool (class->nested_classes, class->image->mempool, nclass); i = mono_metadata_nesting_typedef (class->image, class->type_token, i + 1); } @@ -2195,36 +2431,56 @@ mono_class_init (MonoClass *class) */ if (has_cached_info) { class->instance_size = cached_info.instance_size; - class->class_size = cached_info.class_size; + class->sizes.class_size = cached_info.class_size; class->packing_size = cached_info.packing_size; class->min_align = cached_info.min_align; class->blittable = cached_info.blittable; class->has_references = cached_info.has_references; class->has_static_refs = cached_info.has_static_refs; + class->no_special_static_fields = cached_info.no_special_static_fields; } else - if (!class->size_inited) + if (!class->size_inited){ mono_class_setup_fields (class); + if (class->exception_type || mono_loader_get_last_error ()){ + class_init_ok = FALSE; + goto leave; + } + } + /* initialize method pointers */ if (class->rank) { MonoMethod *ctor; MonoMethodSignature *sig; - class->method.count = class->rank > 1? 2: 1; + int count_generic = 0, first_generic = 0; + + class->method.count = (class->rank > 1? 2: 1); + + if (class->interface_count) { + for (i = 0; i < class->parent->method.count; i++) { + MonoMethod *m = class->parent->methods [i]; + if (!strncmp (m->name, "InternalArray__", 15)) + count_generic++; + } + first_generic = class->method.count; + class->method.count += class->interface_count * count_generic; + } + sig = mono_metadata_signature_alloc (class->image, class->rank); sig->ret = &mono_defaults.void_class->byval_arg; sig->pinvoke = TRUE; for (i = 0; i < class->rank; ++i) sig->params [i] = &mono_defaults.int32_class->byval_arg; - ctor = (MonoMethod *) g_new0 (MonoMethodPInvoke, 1); + ctor = (MonoMethod *) mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethodPInvoke)); ctor->klass = class; ctor->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME; ctor->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL; ctor->signature = sig; ctor->name = ".ctor"; ctor->slot = -1; - class->methods = g_new (MonoMethod*, class->method.count); + class->methods = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethod*) * class->method.count); class->methods [0] = ctor; if (class->rank > 1) { sig = mono_metadata_signature_alloc (class->image, class->rank * 2); @@ -2233,7 +2489,7 @@ mono_class_init (MonoClass *class) for (i = 0; i < class->rank * 2; ++i) sig->params [i] = &mono_defaults.int32_class->byval_arg; - ctor = (MonoMethod *) g_new0 (MonoMethodPInvoke, 1); + ctor = (MonoMethod *) mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethodPInvoke)); ctor->klass = class; ctor->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME; ctor->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL; @@ -2242,45 +2498,15 @@ mono_class_init (MonoClass *class) ctor->slot = -1; class->methods [1] = ctor; } - } - - mono_class_setup_supertypes (class); - - if (!default_ghc) { - if (class == mono_defaults.object_class) { - mono_class_setup_vtable (class); - for (i = 0; i < class->vtable_size; ++i) { - MonoMethod *cm = class->vtable [i]; - - if (!strcmp (cm->name, "GetHashCode")) { - ghc_slot = i; - break; - } - } - - g_assert (ghc_slot > 0); - default_ghc = class->vtable [ghc_slot]; - } + for (i = 0; i < class->interface_count; i++) + setup_generic_array_ifaces (class, class->interfaces [i], first_generic + i * count_generic); } - if (!default_finalize) { - if (class == mono_defaults.object_class) { - mono_class_setup_vtable (class); - for (i = 0; i < class->vtable_size; ++i) { - MonoMethod *cm = class->vtable [i]; - - if (!strcmp (cm->name, "Finalize")) { - finalize_slot = i; - break; - } - } - - g_assert (finalize_slot > 0); + mono_class_setup_supertypes (class); - default_finalize = class->vtable [finalize_slot]; - } - } + if (!default_ghc) + initialize_object_slots (class); /* * If possible, avoid the creation of the generic vtable by requesting @@ -2303,7 +2529,12 @@ mono_class_init (MonoClass *class) } else { mono_class_setup_vtable (class); - + + if (class->exception_type || mono_loader_get_last_error ()){ + class_init_ok = FALSE; + goto leave; + } + class->ghcimpl = 1; if (class->parent) { MonoMethod *cmethod = class->vtable [ghc_slot]; @@ -2335,11 +2566,6 @@ mono_class_init (MonoClass *class) } } - class->inited = 1; - class->init_pending = 0; - - mono_loader_unlock (); - if (MONO_CLASS_IS_INTERFACE (class)) { /* * class->interface_offsets is needed for the castclass/isinst code, so @@ -2348,8 +2574,16 @@ mono_class_init (MonoClass *class) setup_interface_offsets (class, 0); } + leave: + class->inited = 1; + class->init_pending = 0; + + mono_loader_unlock (); + if (mono_debugger_class_init_func) mono_debugger_class_init_func (class); + + return class_init_ok; } /* @@ -2498,8 +2732,14 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) } if (!MONO_CLASS_IS_INTERFACE (class)) { + /* Imported COM Objects always derive from __ComObject. */ + if (MONO_CLASS_IS_IMPORT (class)) { + if (parent == mono_defaults.object_class) + parent = mono_defaults.com_object_class; + } class->parent = parent; + if (!parent) g_assert_not_reached (); /* FIXME */ @@ -2515,6 +2755,10 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) class->marshalbyref = parent->marshalbyref; class->contextbound = parent->contextbound; class->delegate = parent->delegate; + if (MONO_CLASS_IS_IMPORT (class)) + class->is_com_object = 1; + else + class->is_com_object = parent->is_com_object; if (system_namespace) { if (*class->name == 'M' && !strcmp (class->name, "MarshalByRefObject")) @@ -2542,6 +2786,16 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) } /* + * mono_class_setup_supertypes: + * @class: a class + * + * Build the data structure needed to make fast type checks work. + * This currently sets two fields in @class: + * - idepth: distance between @class and System.Object in the type + * hierarchy + 1 + * - supertypes: array of classes: each element has a class in the hierarchy + * starting from @class up to System.Object + * * LOCKING: this assumes the loader lock is held */ void @@ -2560,7 +2814,7 @@ mono_class_setup_supertypes (MonoClass *class) class->idepth = 1; ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth); - class->supertypes = g_new0 (MonoClass *, ms); + class->supertypes = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClass *) * ms); if (class->parent) { class->supertypes [class->idepth - 1] = class; @@ -2634,8 +2888,12 @@ mono_get_shared_generic_class (MonoGenericContainer *container, gboolean is_dyna } /** - * @image: context where the image is created + * mono_class_create_from_typedef: + * @image: image where the token is valid * @type_token: typedef token + * + * Create the MonoClass* representing the specified type token. + * @type_token must be a TypeDef token. */ static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token) @@ -2666,7 +2924,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); - class = g_malloc0 (sizeof (MonoClass)); + class = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass)); class->name = name; class->name_space = nspace; @@ -2691,6 +2949,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) if (cols [MONO_TYPEDEF_EXTENDS]) { parent = mono_class_get_full ( image, mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]), context); + if (parent == NULL){ + g_hash_table_remove (image->class_cache, GUINT_TO_POINTER (type_token)); + mono_loader_unlock (); + return NULL; + } } /* do this early so it's available for interfaces in setup_mono_type () */ @@ -2699,10 +2962,15 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) mono_class_setup_parent (class, parent); + /* uses ->valuetype, which is initialized by mono_class_setup_parent above */ mono_class_setup_mono_type (class); if (!class->enumtype) { - mono_metadata_interfaces_from_typedef_full (image, type_token, &interfaces, &icount, context); + if (!mono_metadata_interfaces_from_typedef_full ( + image, type_token, &interfaces, &icount, context)){ + mono_loader_unlock (); + return NULL; + } class->interfaces = interfaces; class->interface_count = icount; @@ -2710,10 +2978,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS) class->unicode = 1; - /* fixme: maybe we must set this on windows + +#if PLATFORM_WIN32 if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS) class->unicode = 1; - */ +#endif class->cast_class = class->element_class = class; @@ -2797,9 +3066,11 @@ mono_class_create_generic (MonoInflatedGenericClass *gclass) MonoClass *klass, *gklass; int i; - if (gclass->is_initialized) + mono_loader_lock (); + if (gclass->is_initialized) { + mono_loader_unlock (); return; - gclass->is_initialized = TRUE; + } if (!gclass->klass) gclass->klass = g_malloc0 (sizeof (MonoClass)); @@ -2807,7 +3078,16 @@ mono_class_create_generic (MonoInflatedGenericClass *gclass) gklass = gclass->generic_class.container_class; - klass->nested_in = gklass->nested_in; + if (gklass->nested_in) { + /* + * FIXME: the nested type context should include everything the + * nesting context should have, but it may also have additional + * generic parameters... + */ + MonoType *inflated = mono_class_inflate_generic_type ( + &gklass->nested_in->byval_arg, gclass->generic_class.context); + klass->nested_in = mono_class_from_mono_type (inflated); + } klass->name = gklass->name; klass->name_space = gklass->name_space; @@ -2828,7 +3108,7 @@ mono_class_create_generic (MonoInflatedGenericClass *gclass) if (gclass->generic_class.is_dynamic) { klass->instance_size = gklass->instance_size; - klass->class_size = gklass->class_size; + klass->sizes.class_size = gklass->sizes.class_size; klass->size_inited = 1; klass->inited = 1; @@ -2857,12 +3137,7 @@ mono_class_create_generic (MonoInflatedGenericClass *gclass) i = mono_metadata_nesting_typedef (klass->image, gklass->type_token, i + 1); } - if (gclass->generic_class.is_dynamic) { - MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass *) gclass; - - if (dgclass->parent) - klass->parent = mono_class_from_mono_type (dgclass->parent); - } else if (gklass->parent) { + if (gklass->parent) { MonoType *inflated = mono_class_inflate_generic_type ( &gklass->parent->byval_arg, gclass->generic_class.context); @@ -2874,6 +3149,8 @@ mono_class_create_generic (MonoInflatedGenericClass *gclass) if (MONO_CLASS_IS_INTERFACE (klass)) setup_interface_offsets (klass, 0); + gclass->is_initialized = TRUE; + mono_loader_unlock (); } MonoClass * @@ -2941,22 +3218,28 @@ mono_ptr_class_get (MonoType *type) { MonoClass *result; MonoClass *el_class; - static GHashTable *ptr_hash = NULL; + MonoImage *image; + char *name; + + el_class = mono_class_from_mono_type (type); + image = el_class->image; mono_loader_lock (); - if (!ptr_hash) - ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); - el_class = mono_class_from_mono_type (type); - if ((result = g_hash_table_lookup (ptr_hash, el_class))) { + if (!image->ptr_cache) + image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + + if ((result = g_hash_table_lookup (image->ptr_cache, el_class))) { mono_loader_unlock (); return result; } - result = g_new0 (MonoClass, 1); + result = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass)); result->parent = NULL; /* no parent for PTR types */ result->name_space = el_class->name_space; - result->name = g_strdup_printf ("%s*", el_class->name); + name = g_strdup_printf ("%s*", el_class->name); + result->name = mono_mempool_strdup (image->mempool, name); + g_free (name); result->image = el_class->image; result->inited = TRUE; result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); @@ -2972,7 +3255,7 @@ mono_ptr_class_get (MonoType *type) mono_class_setup_supertypes (result); - g_hash_table_insert (ptr_hash, el_class, result); + g_hash_table_insert (image->ptr_cache, el_class, result); mono_loader_unlock (); @@ -2985,6 +3268,8 @@ mono_fnptr_class_get (MonoMethodSignature *sig) MonoClass *result; static GHashTable *ptr_hash = NULL; + /* FIXME: These should be allocate from a mempool as well, but which one ? */ + mono_loader_lock (); if (!ptr_hash) @@ -2999,7 +3284,7 @@ mono_fnptr_class_get (MonoMethodSignature *sig) result->parent = NULL; /* no parent for PTR types */ result->name_space = "System"; result->name = "MonoFNPtrFakeClass"; - result->image = NULL; /* need to fix... */ + result->image = mono_defaults.corlib; /* need to fix... */ result->inited = TRUE; result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */ /* Can pointers get boxed? */ @@ -3094,11 +3379,20 @@ mono_class_from_mono_type (MonoType *type) /** * @image: context where the image is created * @type_spec: typespec token + * @context: the generic context used to evaluate generic instantiations in */ static MonoClass * -mono_class_create_from_typespec (MonoImage *image, guint32 type_spec) +mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context) { - return mono_class_from_mono_type (mono_type_create_from_typespec (image, type_spec)); + MonoType *t = mono_type_create_from_typespec (image, type_spec); + if (!t) + return NULL; + if (context && (context->gclass || context->gmethod)) { + MonoType *inflated = inflate_generic_type (t, context); + if (inflated) + t = inflated; + } + return mono_class_from_mono_type (t); } /** @@ -3131,10 +3425,13 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) mono_loader_lock (); + if (!image->array_cache) + image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + if ((rootlist = list = g_hash_table_lookup (image->array_cache, eclass))) { for (; list; list = list->next) { class = list->data; - if ((class->rank == rank) && (class->byval_arg.type == (bounded ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) { + if ((class->rank == rank) && (class->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) { mono_loader_unlock (); return class; } @@ -3145,25 +3442,13 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) if (image->assembly && image->assembly->dynamic && image->assembly_name && strcmp (image->assembly_name, "mscorlib") == 0) { parent = mono_class_from_name (image, "System", "Array"); corlib_type = TRUE; - } else if (mono_defaults.generic_array_class) { - MonoType *inflated, **args; - - args = g_new0 (MonoType *, 1); - args [0] = &eclass->byval_arg; - - inflated = mono_class_bind_generic_parameters ( - &mono_defaults.generic_array_class->byval_arg, 1, args); - parent = mono_class_from_mono_type (inflated); - - if (!parent->inited) - mono_class_init (parent); } else { parent = mono_defaults.array_class; if (!parent->inited) mono_class_init (parent); } - class = g_malloc0 (sizeof (MonoClass)); + class = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass)); class->image = image; class->name_space = eclass->name_space; @@ -3175,15 +3460,78 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) memset (name + nsize + 1, ',', rank - 1); name [nsize + rank] = ']'; name [nsize + rank + 1] = 0; - class->name = name; + class->name = mono_mempool_strdup (image->mempool, name); + g_free (name); class->type_token = 0; /* all arrays are marked serializable and sealed, bug #42779 */ class->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | (eclass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); class->parent = parent; class->instance_size = mono_class_instance_size (class->parent); - class->class_size = 0; + class->sizes.element_size = mono_class_array_element_size (eclass); mono_class_setup_supertypes (class); + + if (mono_defaults.generic_ilist_class) { + MonoClass *fclass = NULL; + int i; + + if (eclass->valuetype) { + if (eclass == mono_defaults.int16_class) + fclass = mono_defaults.uint16_class; + if (eclass == mono_defaults.uint16_class) + fclass = mono_defaults.int16_class; + if (eclass == mono_defaults.int32_class) + fclass = mono_defaults.uint32_class; + if (eclass == mono_defaults.uint32_class) + fclass = mono_defaults.int32_class; + if (eclass == mono_defaults.int64_class) + fclass = mono_defaults.uint64_class; + if (eclass == mono_defaults.uint64_class) + fclass = mono_defaults.int64_class; + if (eclass == mono_defaults.byte_class) + fclass = mono_defaults.sbyte_class; + if (eclass == mono_defaults.sbyte_class) + fclass = mono_defaults.byte_class; + + class->interface_count = fclass ? 2 : 1; + } else if (MONO_CLASS_IS_INTERFACE (eclass)) { + class->interface_count = 2 + eclass->interface_count; + } else { + class->interface_count = eclass->idepth + eclass->interface_count; + } + + class->interfaces = g_new0 (MonoClass *, class->interface_count); + + for (i = 0; i < class->interface_count; i++) { + MonoType *inflated, **args; + MonoClass *iface; + + if (eclass->valuetype) + iface = (i == 0) ? eclass : fclass; + else if (MONO_CLASS_IS_INTERFACE (eclass)) { + if (i == 0) + iface = mono_defaults.object_class; + else if (i == 1) + iface = eclass; + else + iface = eclass->interfaces [i - 2]; + } else { + if (i < eclass->idepth) + iface = eclass->supertypes [i]; + else + iface = eclass->interfaces [i - eclass->idepth]; + } + + args = g_new0 (MonoType *, 1); + args [0] = &iface->byval_arg; + + inflated = mono_class_bind_generic_parameters ( + &mono_defaults.generic_ilist_class->byval_arg, 1, args); + + class->interfaces [i] = mono_class_from_mono_type (inflated); + } + } + if (eclass->generic_class) mono_class_init (eclass); if (!eclass->size_inited) @@ -3200,7 +3548,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) class->element_class = eclass; if ((rank > 1) || bounded) { - MonoArrayType *at = g_new0 (MonoArrayType, 1); + MonoArrayType *at = mono_mempool_alloc0 (image->mempool, sizeof (MonoArrayType)); class->byval_arg.type = MONO_TYPE_ARRAY; class->byval_arg.data.array = at; at->eklass = eclass; @@ -3309,7 +3657,12 @@ mono_class_data_size (MonoClass *klass) if (!klass->inited) mono_class_init (klass); - return klass->class_size; + /* in arrays, sizes.class_size is unioned with element_size + * and arrays have no static fields + */ + if (klass->rank) + return 0; + return klass->sizes.class_size; } /* @@ -3423,12 +3776,6 @@ mono_class_get_event_token (MonoEvent *event) return 0; } -void * -mono_vtable_get_static_field_data (MonoVTable *vt) -{ - return vt->data; -} - MonoProperty* mono_class_get_property_from_name (MonoClass *klass, const char *name) { @@ -3557,14 +3904,15 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token) } /** - * mono_class_get: + * mono_class_get_full: * @image: the image where the class resides * @type_token: the token for the class + * @context: the generic context used to evaluate generic instantiations in * * Returns: the MonoClass that represents @type_token in @image */ MonoClass * -mono_class_get (MonoImage *image, guint32 type_token) +mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context) { MonoClass *class = NULL; @@ -3579,7 +3927,7 @@ mono_class_get (MonoImage *image, guint32 type_token) class = mono_class_from_typeref (image, type_token); break; case MONO_TOKEN_TYPE_SPEC: - class = mono_class_create_from_typespec (image, type_token); + class = mono_class_create_from_typespec (image, type_token, context); break; default: g_warning ("unknown token type %x", type_token & 0xff000000); @@ -3596,15 +3944,108 @@ mono_class_get (MonoImage *image, guint32 type_token) } MonoClass * -mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context) +mono_class_get (MonoImage *image, guint32 type_token) { - MonoClass *class = mono_class_get (image, type_token); - if (class && context && (context->gclass || context->gmethod)) { - MonoType *inflated = inflate_generic_type (&class->byval_arg, context); - if (inflated) - class = mono_class_from_mono_type (inflated); + return mono_class_get_full (image, type_token, NULL); +} + +/** + * mono_image_init_name_cache: + * + * Initializes the class name cache stored in image->name_cache. + * + * LOCKING: Acquires the loader lock. + */ +void +mono_image_init_name_cache (MonoImage *image) +{ + MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF]; + guint32 cols [MONO_TYPEDEF_SIZE]; + const char *name; + const char *nspace; + guint32 i, visib, nspace_index; + GHashTable *name_cache2, *nspace_table; + + mono_loader_lock (); + + image->name_cache = g_hash_table_new (g_str_hash, g_str_equal); + + if (image->dynamic) { + mono_loader_unlock (); + return; } - return class; + + /* Temporary hash table to avoid lookups in the nspace_table */ + name_cache2 = g_hash_table_new (NULL, NULL); + + for (i = 1; i <= t->rows; ++i) { + mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE); + /* nested types are accessed from the nesting name */ + visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK; + if (visib > TYPE_ATTRIBUTE_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_ASSEMBLY) + continue; + name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); + nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); + + nspace_index = cols [MONO_TYPEDEF_NAMESPACE]; + nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index)); + if (!nspace_table) { + nspace_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table); + g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index), + nspace_table); + } + g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i)); + } + + /* Load type names from EXPORTEDTYPES table */ + { + MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE]; + guint32 cols [MONO_EXP_TYPE_SIZE]; + int i; + + for (i = 0; i < t->rows; ++i) { + mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE); + name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]); + nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]); + + nspace_index = cols [MONO_EXP_TYPE_NAMESPACE]; + nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index)); + if (!nspace_table) { + nspace_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table); + g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index), + nspace_table); + } + g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1))); + } + } + + g_hash_table_destroy (name_cache2); + + mono_loader_unlock (); +} + +void +mono_image_add_to_name_cache (MonoImage *image, const char *nspace, + const char *name, guint32 index) +{ + GHashTable *nspace_table; + GHashTable *name_cache; + + mono_loader_lock (); + + if (!image->name_cache) + mono_image_init_name_cache (image); + + name_cache = image->name_cache; + if (!(nspace_table = g_hash_table_lookup (name_cache, nspace))) { + nspace_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table); + } + g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index)); + + mono_loader_unlock (); } typedef struct { @@ -3631,12 +4072,6 @@ find_nocase (gpointer key, gpointer value, gpointer user_data) * Obtains a MonoClass with a given namespace and a given name which * is located in the given MonoImage. The namespace and name * lookups are case insensitive. - * - * You can also pass @NULL to the image, and that will lookup for - * a type with the given namespace and name in all of the loaded - * assemblies: notice that since there might be a name clash in this - * case, passing @NULL is not encouraged if you need a precise type. - * */ MonoClass * mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name) @@ -3653,6 +4088,9 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char mono_loader_lock (); + if (!image->name_cache) + mono_image_init_name_cache (image); + user_data.key = name_space; user_data.value = NULL; g_hash_table_foreach (image->name_cache, find_nocase, &user_data); @@ -3723,12 +4161,6 @@ return_nested_in (MonoClass *class, char *nested) { * * Obtains a MonoClass with a given namespace and a given name which * is located in the given MonoImage. - * - * You can also pass `NULL' to the image, and that will lookup for - * a type with the given namespace and name in all of the loaded - * assemblies: notice that since there might be a name clash in this - * case, passing NULL is not encouraged if you need a precise type. - * */ MonoClass * mono_class_from_name (MonoImage *image, const char* name_space, const char *name) @@ -3751,8 +4183,21 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name name = buf; } + if (get_class_from_name) { + gboolean res = get_class_from_name (image, name_space, name, &class); + if (res) { + if (nested) + return class ? return_nested_in (class, nested) : NULL; + else + return class; + } + } + mono_loader_lock (); + if (!image->name_cache) + mono_image_init_name_cache (image); + nspace_table = g_hash_table_lookup (image->name_cache, name_space); if (nspace_table) @@ -3781,6 +4226,17 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name if (nested) return return_nested_in (class, nested); return class; + } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) { + MonoAssembly **references = image->references; + if (!references [idx - 1]) + mono_assembly_load_reference (image, idx - 1); + g_assert (references == image->references); + g_assert (references [idx - 1]); + if (references [idx - 1] == (gpointer)-1) + return NULL; + else + /* FIXME: Cycle detection */ + return mono_class_from_name (references [idx - 1]->image, name_space, name); } else { g_error ("not yet implemented"); } @@ -3798,7 +4254,6 @@ gboolean mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc, gboolean check_interfaces) { - again: g_assert (klassc->idepth > 0); if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) { if ((klassc->interface_id <= klass->max_interface_id) && @@ -3824,18 +4279,6 @@ mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc, if (klassc == mono_defaults.object_class) return TRUE; - if (klass->generic_class && klass->generic_class->is_dynamic) { - MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass *) klass->generic_class; - - if (!dgclass->parent) - return FALSE; - - if (mono_metadata_type_equal (dgclass->parent, &klassc->byval_arg)) - return TRUE; - klass = mono_class_from_mono_type (dgclass->parent); - goto again; - } - return FALSE; } @@ -3925,22 +4368,9 @@ MonoMethod* mono_class_get_finalizer (MonoClass *klass) { MonoCachedClassInfo cached_info; - static int finalize_slot = -1; - - if (finalize_slot < 0) { - int i; - MonoClass* obj_class = mono_get_object_class (); - mono_class_setup_vtable (obj_class); - for (i = 0; i < obj_class->vtable_size; ++i) { - MonoMethod *cm = obj_class->vtable [i]; - - if (!strcmp (mono_method_get_name (cm), "Finalize")) { - finalize_slot = i; - break; - } - } - } + if (!klass->inited) + mono_class_init (klass); if (!klass->has_finalize) return NULL; @@ -4036,7 +4466,8 @@ handle_enum: gint32 mono_array_element_size (MonoClass *ac) { - return mono_class_array_element_size (ac->element_class); + g_assert (ac->rank); + return ac->sizes.element_size; } gpointer @@ -4160,6 +4591,12 @@ mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res) return get_cached_class_info (klass, res); } +void +mono_install_get_class_from_name (MonoGetClassFromName func) +{ + get_class_from_name = func; +} + MonoImage* mono_class_get_image (MonoClass *klass) { @@ -4304,6 +4741,20 @@ mono_class_get_type (MonoClass *klass) return &klass->byval_arg; } +/** + * mono_class_get_type_token + * @klass: the MonoClass to act on + * + * This method returns type token for the class. + * + * Returns: the type token for the class. + */ +guint32 +mono_class_get_type_token (MonoClass *klass) +{ + return klass->type_token; +} + /** * mono_class_get_byref_type: * @klass: the MonoClass to act on @@ -4649,6 +5100,19 @@ mono_field_get_flags (MonoClassField *field) return field->type->attrs; } +/** + * mono_field_get_data; + * @field: the MonoClassField to act on + * + * Returns: pointer to the metadata constant value or to the field + * data if it has an RVA flag. + */ +const char * +mono_field_get_data (MonoClassField *field) +{ + return field->data; +} + /** * mono_property_get_name: * @prop: the MonoProperty to act on @@ -4874,6 +5338,37 @@ mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data) return TRUE; } +/** + * mono_classes_init: + * + * Initialize the resources used by this module. + */ +void +mono_classes_init (void) +{ +} + +/** + * mono_classes_cleanup: + * + * Free the resources used by this module. + */ +void +mono_classes_cleanup (void) +{ + IOffsetInfo *cached_info, *next; + + if (global_interface_bitset) + mono_bitset_free (global_interface_bitset); + + for (cached_info = cached_offset_info; cached_info;) { + next = cached_info->next; + + g_free (cached_info); + cached_info = next; + } +} + /** * mono_class_get_exception_for_failure: * @klass: class in which the failure was detected @@ -4904,8 +5399,19 @@ mono_class_get_exception_for_failure (MonoClass *klass) } case MONO_EXCEPTION_TYPE_LOAD: return mono_exception_from_name (mono_defaults.corlib, "System", "TypeLoadException"); - /* TODO - handle other class related failures */ - default: + + default: { + MonoLoaderError *error; + MonoException *ex; + + error = mono_loader_get_last_error (); + if (error != NULL){ + ex = mono_loader_error_prepare_exception (error); + return ex; + } + + /* TODO - handle other class related failures */ return NULL; } + } }