X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=c96458b04a78f8bb95e70a53e8a1929e0a2fe831;hb=64e2556130a5220a09a770b85b442d0ff34bcbda;hp=4b725b759a12d3896649d2160efa3635b725f620;hpb=33028b1a2c0d0345efc3639f3b33d74dc96daf62;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index 4b725b759a1..c96458b04a7 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -4,10 +4,13 @@ * Author: * Miguel de Icaza (miguel@ximian.com) * - * (C) 2001-2006 Novell, Inc. - * + * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) + * Copyright 2004-2009 Novell, Inc (http://www.novell.com) */ #include +#ifdef HAVE_ALLOCA_H +#include +#endif #include #include #include @@ -35,6 +38,7 @@ #include #include #include +#include #include MonoStats mono_stats; @@ -58,6 +62,8 @@ static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, static int generic_array_methods (MonoClass *class); static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos); +static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter); + void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL; void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL; @@ -603,6 +609,8 @@ mono_class_get_context (MonoClass *class) * The same as mono_class_inflate_generic_type, but allocates the MonoType * from mempool if it is non-NULL. If it is NULL, the MonoType is * allocated on the heap and is owned by the caller. + * The returned type can potentially be the same as TYPE, so it should not be + * modified by the caller, and it should be freed using mono_metadata_free_type (). */ MonoType* mono_class_inflate_generic_type_with_mempool (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context) @@ -612,8 +620,15 @@ mono_class_inflate_generic_type_with_mempool (MonoMemPool *mempool, MonoType *ty if (context) inflated = inflate_generic_type (mempool, type, context); - if (!inflated) - return mono_metadata_type_dup (mempool, type); + if (!inflated) { + MonoType *shared = mono_metadata_get_shared_type (type); + + if (shared) { + return shared; + } else { + return mono_metadata_type_dup (mempool, type); + } + } mono_stats.inflated_type_count++; return inflated; @@ -636,6 +651,26 @@ mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context) return mono_class_inflate_generic_type_with_mempool (NULL, type, context); } +/* + * mono_class_inflate_generic_type_with_mempool_no_copy: + * + * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation + * was done. + */ +static MonoType* +mono_class_inflate_generic_type_with_mempool_no_copy (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context) +{ + MonoType *inflated = NULL; + + if (context) + inflated = inflate_generic_type (mempool, type, context); + + if (!inflated) + return type; + + mono_stats.inflated_type_count++; + return inflated; +} static MonoGenericContext inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with) @@ -983,6 +1018,9 @@ mono_class_setup_fields (MonoClass *class) class->min_align = 1; } + if (class->simd_type) + class->min_align = 16; + /* Get the real size */ explicit_size = mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size); @@ -1017,6 +1055,11 @@ mono_class_setup_fields (MonoClass *class) g_assert (container); mono_class_setup_fields (gklass); + + if (gklass->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + return; + } } /* @@ -1030,20 +1073,15 @@ mono_class_setup_fields (MonoClass *class) if (class->generic_class) { MonoClassField *gfield = &gklass->fields [i]; - MonoInflatedField *ifield = g_new0 (MonoInflatedField, 1); - ifield->generic_type = gfield->type; - field->name = gfield->name; - field->generic_info = ifield; + field->name = mono_field_get_name (gfield); /*This memory must come from the image mempool as we don't have a chance to free it.*/ - field->type = mono_class_inflate_generic_type_with_mempool (class->image->mempool, gfield->type, mono_class_get_context (class)); - field->type->attrs = gfield->type->attrs; + field->type = mono_class_inflate_generic_type_with_mempool_no_copy (class->image->mempool, gfield->type, mono_class_get_context (class)); + g_assert (field->type->attrs == gfield->type->attrs); if (mono_field_is_deleted (field)) continue; field->offset = gfield->offset; - field->data = gfield->data; } else { - guint32 rva; const char *sig; guint32 cols [MONO_FIELD_SIZE]; @@ -1068,14 +1106,7 @@ mono_class_setup_fields (MonoClass *class) 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); - } - - if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) { - mono_metadata_field_info (m, idx, NULL, &rva, NULL); - if (!rva) - g_warning ("field %s in %s should have RVA data, but hasn't", field->name, class->name); - field->data = mono_image_rva_map (class->image, rva); + class->name, mono_field_get_name (field)); } } @@ -1319,7 +1350,7 @@ mono_class_layout_fields (MonoClass *class) } if ((top == 1) && (class->instance_size == sizeof (MonoObject)) && - (strcmp (field->name, "$PRIVATE$") == 0)) { + (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) { /* This field is a hack inserted by MCS to empty structures */ continue; } @@ -1614,6 +1645,61 @@ mono_class_get_method_by_index (MonoClass *class, int index) } } +/* + * mono_class_get_inflated_method: + * + * Given an inflated class CLASS and a method METHOD which should be a method of + * CLASS's generic definition, return the inflated method corresponding to METHOD. + */ +MonoMethod* +mono_class_get_inflated_method (MonoClass *class, MonoMethod *method) +{ + MonoClass *gklass = class->generic_class->container_class; + int i; + + mono_class_setup_methods (gklass); + for (i = 0; i < gklass->method.count; ++i) { + if (gklass->methods [i] == method) { + if (class->methods) + return class->methods [i]; + else + return mono_class_inflate_generic_method_full (gklass->methods [i], class, mono_class_get_context (class)); + } + } + + return NULL; +} + +/* + * mono_class_get_vtable_entry: + * + * Returns class->vtable [offset], computing it if neccesary. + * LOCKING: Acquires the loader lock. + */ +MonoMethod* +mono_class_get_vtable_entry (MonoClass *class, int offset) +{ + if (class->generic_class) { + MonoClass *gklass = class->generic_class->container_class; + mono_class_setup_vtable (gklass); + if (gklass->vtable [offset]->wrapper_type != MONO_WRAPPER_STATIC_RGCTX_INVOKE) + return mono_class_inflate_generic_method_full (gklass->vtable [offset], class, mono_class_get_context (class)); + } + + if (class->rank == 1) { + /* + * szarrays do not overwrite any methods of Array, so we can avoid + * initializing their vtables in some cases. + */ + mono_class_setup_vtable (class->parent); + if (offset < class->parent->vtable_size) + return class->parent->vtable [offset]; + } + + mono_class_setup_vtable (class); + return class->vtable [offset]; +} + static void mono_class_setup_properties (MonoClass *class) { @@ -1636,11 +1722,11 @@ mono_class_setup_properties (MonoClass *class) if (class->generic_class) { MonoClass *gklass = class->generic_class->container_class; - class->property = gklass->property; - mono_class_init (gklass); mono_class_setup_properties (gklass); + class->property = gklass->property; + properties = g_new0 (MonoProperty, class->property.count + 1); for (i = 0; i < class->property.count; i++) { @@ -2012,9 +2098,57 @@ 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 *class, guint rank) +{ + return rank ? mono_array_class_get (class, rank) : class; +} + +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 && eclass->enum_basetype) + valuetype_types [1] = mono_class_from_mono_type (eclass->enum_basetype); +} + /* 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 compatbility. */ static MonoClass** get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enumerator) @@ -2023,9 +2157,9 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume static MonoClass* generic_icollection_class = NULL; static MonoClass* generic_ienumerable_class = NULL; static MonoClass* generic_ienumerator_class = NULL; - MonoClass *fclass = NULL; + MonoClass *valuetype_types[2] = { NULL, NULL }; MonoClass **interfaces = NULL; - int i, interface_count, real_count; + int i, interface_count, real_count, original_rank; int all_interfaces; gboolean internal_enumerator; gboolean eclass_is_valuetype; @@ -2036,12 +2170,14 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume } internal_enumerator = FALSE; eclass_is_valuetype = FALSE; + original_rank = eclass->rank; if (class->byval_arg.type != MONO_TYPE_SZARRAY) { if (class->generic_class && class->nested_in == mono_defaults.array_class && strcmp (class->name, "InternalEnumerator`1") == 0) { /* * For a Enumerator we need to get the list of interfaces for T. */ eclass = mono_class_from_mono_type (class->generic_class->context.class_inst->type_argv [0]); + original_rank = eclass->rank; eclass = eclass->element_class; internal_enumerator = TRUE; *is_enumerator = TRUE; @@ -2076,32 +2212,21 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume * the generic interfaces needed to implement. */ if (eclass->valuetype) { - if (eclass == mono_defaults.int16_class) - fclass = mono_defaults.uint16_class; - else if (eclass == mono_defaults.uint16_class) - fclass = mono_defaults.int16_class; - else if (eclass == mono_defaults.int32_class) - fclass = mono_defaults.uint32_class; - else if (eclass == mono_defaults.uint32_class) - fclass = mono_defaults.int32_class; - else if (eclass == mono_defaults.int64_class) - fclass = mono_defaults.uint64_class; - else if (eclass == mono_defaults.uint64_class) - fclass = mono_defaults.int64_class; - else if (eclass == mono_defaults.byte_class) - fclass = mono_defaults.sbyte_class; - else if (eclass == mono_defaults.sbyte_class) - fclass = mono_defaults.byte_class; - else { - /* No additional interfaces for other value types */ - *num = 0; - return NULL; - } + fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank); /* IList, ICollection, IEnumerable */ - real_count = interface_count = 3; - interfaces = g_malloc0 (sizeof (MonoClass*) * interface_count); - interfaces [0] = fclass; + real_count = interface_count = valuetype_types [1] ? 6 : 3; + if (internal_enumerator) { + ++real_count; + if (valuetype_types [1]) + ++real_count; + } + + interfaces = g_malloc0 (sizeof (MonoClass*) * real_count); + interfaces [0] = valuetype_types [0]; + if (valuetype_types [1]) + interfaces [3] = valuetype_types [1]; + eclass_is_valuetype = TRUE; } else { int j; @@ -2118,11 +2243,19 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume 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 */ interface_count *= 3; real_count = interface_count; - if (internal_enumerator) - real_count += idepth + eclass->interface_offsets_count; + if (internal_enumerator) { + real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count; + if (valuetype_types [1]) + ++real_count; + } interfaces = g_malloc0 (sizeof (MonoClass*) * real_count); if (MONO_CLASS_IS_INTERFACE (eclass)) { interfaces [0] = mono_defaults.object_class; @@ -2146,63 +2279,73 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume j += 3; } } + if (valuetype_types [1]) { + interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank); + j += 3; + } } /* instantiate the generic interfaces */ for (i = 0; i < interface_count; i += 3) { - MonoType *args [1]; MonoClass *iface = interfaces [i]; - args [0] = &iface->byval_arg; - interfaces [i] = mono_class_bind_generic_parameters ( - mono_defaults.generic_ilist_class, 1, args, FALSE); - //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0)); - args [0] = &iface->byval_arg; - interfaces [i + 1] = mono_class_bind_generic_parameters ( - generic_icollection_class, 1, args, FALSE); - args [0] = &iface->byval_arg; - interfaces [i + 2] = mono_class_bind_generic_parameters ( - generic_ienumerable_class, 1, args, FALSE); - //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i + 1]->byval_arg, 0)); - //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i + 2]->byval_arg, 0)); + interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface); + interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface); + 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++) { - MonoType *args [1]; - MonoClass *iface = interfaces [i]; - - args [0] = &iface->byval_arg; - interfaces [i] = mono_class_bind_generic_parameters ( - generic_ienumerator_class, 1, args, FALSE); - /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/ + interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]); } + j = interface_count; if (!eclass_is_valuetype) { - j = interface_count; - for (i = 0; i < eclass->idepth; i++) { - MonoType *args [1]; - args [0] = &eclass->supertypes [i]->byval_arg; - interfaces [j] = mono_class_bind_generic_parameters ( - generic_ienumerator_class, 1, args, FALSE); - /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/ + 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++) { - MonoClass *iface = eclass->interfaces_packed [i]; - MonoType *args [1]; - args [0] = &iface->byval_arg; - interfaces [j] = mono_class_bind_generic_parameters ( - generic_ienumerator_class, 1, args, FALSE); - /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/ + 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 (&class->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; +} + /* * LOCKING: this is supposed to be called with the loader lock held. */ @@ -2307,8 +2450,8 @@ setup_interface_offsets (MonoClass *class, int cur_slot) if (num_array_interfaces) { if (is_enumerator) { int ienumerator_offset; - g_assert (strcmp (class->interfaces [0]->name, "IEnumerator`1") == 0); - ienumerator_offset = interface_offsets_full [class->interfaces [0]->interface_id]; + int ienumerator_idx = find_array_interface (class, "IEnumerator`1"); + ienumerator_offset = interface_offsets_full [class->interfaces [ienumerator_idx]->interface_id]; for (i = 0; i < num_array_interfaces; ++i) { ic = array_interfaces [i]; interfaces_full [ic->interface_id] = ic; @@ -2320,12 +2463,12 @@ setup_interface_offsets (MonoClass *class, int cur_slot) } } else { int ilist_offset, icollection_offset, ienumerable_offset; - g_assert (strcmp (class->interfaces [0]->name, "IList`1") == 0); - g_assert (strcmp (class->interfaces [0]->interfaces [0]->name, "ICollection`1") == 0); - g_assert (strcmp (class->interfaces [0]->interfaces [1]->name, "IEnumerable`1") == 0); - ilist_offset = interface_offsets_full [class->interfaces [0]->interface_id]; - icollection_offset = interface_offsets_full [class->interfaces [0]->interfaces [0]->interface_id]; - ienumerable_offset = interface_offsets_full [class->interfaces [0]->interfaces [1]->interface_id]; + int ilist_iface_idx = find_array_interface (class, "IList`1"); + int icollection_iface_idx = find_array_interface (class->interfaces [ilist_iface_idx], "ICollection`1"); + int ienumerable_iface_idx = find_array_interface (class->interfaces [ilist_iface_idx], "IEnumerable`1"); + ilist_offset = interface_offsets_full [class->interfaces [ilist_iface_idx]->interface_id]; + icollection_offset = interface_offsets_full [class->interfaces [ilist_iface_idx]->interfaces [icollection_iface_idx]->interface_id]; + ienumerable_offset = interface_offsets_full [class->interfaces [ilist_iface_idx]->interfaces [ienumerable_iface_idx]->interface_id]; g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0); for (i = 0; i < num_array_interfaces; ++i) { ic = array_interfaces [i]; @@ -2420,11 +2563,15 @@ mono_class_setup_vtable (MonoClass *class) if (class->vtable) return; - /* This sets method->slot for all methods if this is an interface */ - mono_class_setup_methods (class); + if (mono_debug_using_mono_debugger ()) + /* The debugger currently depends on this */ + mono_class_setup_methods (class); - if (MONO_CLASS_IS_INTERFACE (class)) + if (MONO_CLASS_IS_INTERFACE (class)) { + /* This sets method->slot for all methods if this is an interface */ + mono_class_setup_methods (class); return; + } mono_loader_lock (); @@ -2492,27 +2639,9 @@ check_core_clr_override_method (MonoClass *class, MonoMethod *override, MonoMeth } -static int __use_new_interface_vtable_code = -1; -static gboolean -use_new_interface_vtable_code (void) { - if (__use_new_interface_vtable_code == -1) { - char *env_var = getenv ("MONO_USE_NEW_INTERFACE_VTABLE_CODE"); - if (env_var == NULL) { - __use_new_interface_vtable_code = TRUE; - } else { - if ((strcmp (env_var, "0") == 0) || (strcmp (env_var, "false") == 0) || (strcmp (env_var, "FALSE") == 0)) { - __use_new_interface_vtable_code = FALSE; - } else { - __use_new_interface_vtable_code = TRUE; - } - } - } - return __use_new_interface_vtable_code; -} - - #define DEBUG_INTERFACE_VTABLE_CODE 0 #define TRACE_INTERFACE_VTABLE_CODE 0 +#define VERIFY_INTERFACE_VTABLE_CODE 0 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE) #define DEBUG_INTERFACE_VTABLE(stmt) do {\ @@ -2530,6 +2659,14 @@ use_new_interface_vtable_code (void) { #define TRACE_INTERFACE_VTABLE(stmt) #endif +#if VERIFY_INTERFACE_VTABLE_CODE +#define VERIFY_INTERFACE_VTABLE(stmt) do {\ + stmt;\ +} while (0) +#else +#define VERIFY_INTERFACE_VTABLE(stmt) +#endif + #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE) static char* @@ -2730,6 +2867,60 @@ print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_no } #endif +#if VERIFY_INTERFACE_VTABLE_CODE +static int +mono_method_try_get_vtable_index (MonoMethod *method) +{ + if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) { + MonoMethodInflated *imethod = (MonoMethodInflated*)method; + if (imethod->declaring->is_generic) + return imethod->declaring->slot; + } + return method->slot; +} + +static void +mono_class_verify_vtable (MonoClass *class) +{ + int i; + char *full_name = mono_type_full_name (&class->byval_arg); + + printf ("*** Verifying VTable of class '%s' \n", full_name); + g_free (full_name); + full_name = NULL; + + if (!class->methods) + return; + + for (i = 0; i < class->method.count; ++i) { + MonoMethod *cm = class->methods [i]; + int slot; + + if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL)) + continue; + + g_free (full_name); + full_name = mono_method_full_name (cm, TRUE); + + slot = mono_method_try_get_vtable_index (cm); + if (slot >= 0) { + if (slot >= class->vtable_size) { + printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, class->vtable_size); + continue; + } + + if (slot >= 0 && class->vtable [slot] != cm && (class->vtable [slot] && class->vtable [slot]->wrapper_type != MONO_WRAPPER_STATIC_RGCTX_INVOKE)) { + char *other_name = class->vtable [slot] ? mono_method_full_name (class->vtable [slot], TRUE) : g_strdup ("[null value]"); + printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name); + g_free (other_name); + } + } else + printf ("\tVirtual method %s does n't have an assigned slot\n", full_name); + } + g_free (full_name); +} +#endif + static void print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) { int index; @@ -2743,6 +2934,7 @@ print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, Mono printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n", mono_type_get_name (&ic->byval_arg), im->name, method_signature, class->name_space, class->name); g_free (method_signature); + mono_class_setup_methods (class); for (index = 0; index < class->method.count; ++index) { MonoMethod *cm = class->methods [index]; method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE); @@ -2761,9 +2953,11 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o MonoClass *k, *ic; MonoMethod **vtable; int i, max_vtsize = 0, max_iid, cur_slot = 0; - GPtrArray *ifaces, *pifaces = NULL; + GPtrArray *ifaces = NULL; GHashTable *override_map = NULL; gboolean security_enabled = mono_is_security_manager_active (); + MonoMethod *cm; + gpointer class_iter; #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE) int first_non_interface_slot; #endif @@ -2799,40 +2993,65 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o max_iid = class->max_interface_id; DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot); - if (use_new_interface_vtable_code ()) { - if (class->parent && class->parent->vtable_size) { - MonoClass *parent = class->parent; - int i; - - memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size); + /* Optimized version for generic instances */ + if (class->generic_class) { + MonoClass *gklass = class->generic_class->container_class; + gboolean usable = TRUE; + + mono_class_setup_vtable (gklass); + for (i = 0; i < gklass->vtable_size; ++i) + if (gklass->vtable [i] && gklass->vtable [i]->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) + usable = FALSE; + + if (usable) { + MonoMethod **tmp = mono_image_alloc0 (class->image, sizeof (gpointer) * gklass->vtable_size); + class->vtable_size = gklass->vtable_size; + for (i = 0; i < gklass->vtable_size; ++i) + if (gklass->vtable [i]) + tmp [i] = mono_class_inflate_generic_method_full (gklass->vtable [i], class, mono_class_get_context (class)); + mono_memory_barrier (); + class->vtable = tmp; + + /* Have to set method->slot for abstract virtual methods */ + if (class->methods && gklass->methods) { + for (i = 0; i < class->method.count; ++i) + if (class->methods [i]->slot == -1) + class->methods [i]->slot = gklass->methods [i]->slot; + } + + return; + } + } + + if (class->parent && class->parent->vtable_size) { + MonoClass *parent = class->parent; + int i; + + memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size); + + // Also inherit parent interface vtables, just as a starting point. + // This is needed otherwise bug-77127.exe fails when the property methods + // have different names in the iterface and the class, because for child + // classes the ".override" information is not used anymore. + for (i = 0; i < parent->interface_offsets_count; i++) { + MonoClass *parent_interface = parent->interfaces_packed [i]; + int interface_offset = mono_class_interface_offset (class, parent_interface); - // Also inherit parent interface vtables, just as a starting point. - // This is needed otherwise bug-77127.exe fails when the property methods - // have different names in the iterface and the class, because for child - // classes the ".override" information is not used anymore. - for (i = 0; i < parent->interface_offsets_count; i++) { - MonoClass *parent_interface = parent->interfaces_packed [i]; - int interface_offset = mono_class_interface_offset (class, parent_interface); + if (interface_offset >= parent->vtable_size) { + int parent_interface_offset = mono_class_interface_offset (parent, parent_interface); + int j; - if (interface_offset >= parent->vtable_size) { - int parent_interface_offset = mono_class_interface_offset (parent, parent_interface); - int j; - - mono_class_setup_methods (parent_interface); - TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name)); - for (j = 0; j < parent_interface->method.count; 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, - interface_offset + j, interface_offset, j)); - } + mono_class_setup_methods (parent_interface); + TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name)); + for (j = 0; j < parent_interface->method.count; 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, + interface_offset + j, interface_offset, j)); } - } + } - } else { - if (class->parent && class->parent->vtable_size) - memcpy (vtable, class->parent->vtable, sizeof (gpointer) * class->parent->vtable_size); } TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE)); @@ -2841,9 +3060,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o MonoMethod *decl = overrides [i*2]; if (MONO_CLASS_IS_INTERFACE (decl->klass)) { int dslot; - mono_class_setup_methods (decl->klass); - g_assert (decl->slot != -1); - dslot = decl->slot + mono_class_interface_offset (class, decl->klass); + dslot = mono_method_get_vtable_slot (decl) + mono_class_interface_offset (class, decl->klass); vtable [dslot] = overrides [i*2 + 1]; vtable [dslot]->slot = dslot; if (!override_map) @@ -2858,370 +3075,125 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS")); TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE)); - if (use_new_interface_vtable_code ()) { - // Loop on all implemented interfaces... - for (i = 0; i < class->interface_offsets_count; i++) { - MonoClass *parent = class->parent; - int ic_offset; - gboolean interface_is_explicitly_implemented_by_class; - int im_index; - - ic = class->interfaces_packed [i]; - ic_offset = mono_class_interface_offset (class, ic); + // Loop on all implemented interfaces... + for (i = 0; i < class->interface_offsets_count; i++) { + MonoClass *parent = class->parent; + int ic_offset; + gboolean interface_is_explicitly_implemented_by_class; + int im_index; + + ic = class->interfaces_packed [i]; + ic_offset = mono_class_interface_offset (class, ic); - mono_class_setup_methods (ic); - - // Check if this interface is explicitly implemented (instead of just inherited) - if (parent != NULL) { - int implemented_interfaces_index; - interface_is_explicitly_implemented_by_class = FALSE; - for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) { - if (ic == class->interfaces [implemented_interfaces_index]) { - interface_is_explicitly_implemented_by_class = TRUE; - break; - } + mono_class_setup_methods (ic); + + // Check if this interface is explicitly implemented (instead of just inherited) + if (parent != NULL) { + int implemented_interfaces_index; + interface_is_explicitly_implemented_by_class = FALSE; + for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) { + if (ic == class->interfaces [implemented_interfaces_index]) { + interface_is_explicitly_implemented_by_class = TRUE; + break; } - } else { - interface_is_explicitly_implemented_by_class = TRUE; } + } else { + interface_is_explicitly_implemented_by_class = TRUE; + } + + // Loop on all interface methods... + for (im_index = 0; im_index < ic->method.count; im_index++) { + MonoMethod *im = ic->methods [im_index]; + int im_slot = ic_offset + im->slot; + MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL; - // Loop on all interface methods... - for (im_index = 0; im_index < ic->method.count; im_index++) { - MonoMethod *im = ic->methods [im_index]; - int im_slot = ic_offset + im->slot; - MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL; - - if (im->flags & METHOD_ATTRIBUTE_STATIC) - continue; + if (im->flags & METHOD_ATTRIBUTE_STATIC) + continue; - // If there is an explicit implementation, just use it right away, - // otherwise look for a matching method - if (override_im == NULL) { - int cm_index; - - // First look for a suitable method among the class methods - for (cm_index = 0; cm_index < class->method.count; cm_index++) { - MonoMethod *cm = class->methods [cm_index]; + // If there is an explicit implementation, just use it right away, + // otherwise look for a matching method + if (override_im == NULL) { + int cm_index; + gpointer iter; + MonoMethod *cm; + + // First look for a suitable method among the class methods + iter = NULL; + while ((cm = mono_class_get_virtual_methods (class, &iter))) { + TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))); + if (check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) { + TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING")); + vtable [im_slot] = cm; + /* Why do we need this? */ + if (cm->slot < 0) { + cm->slot = im_slot; + } + } + TRACE_INTERFACE_VTABLE (printf ("\n")); + } + + // If the slot is still empty, look in all the inherited virtual methods... + if ((vtable [im_slot] == NULL) && class->parent != NULL) { + MonoClass *parent = class->parent; + // Reverse order, so that last added methods are preferred + for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) { + MonoMethod *cm = parent->vtable [cm_index]; - TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))); - if ((cm->flags & METHOD_ATTRIBUTE_VIRTUAL) && check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) { - TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING")); + TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name)); + if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) { + TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING")); vtable [im_slot] = cm; /* Why do we need this? */ if (cm->slot < 0) { cm->slot = im_slot; } + break; } - TRACE_INTERFACE_VTABLE (printf ("\n")); - } - - // If the slot is still empty, look in all the inherited virtual methods... - if ((vtable [im_slot] == NULL) && class->parent != NULL) { - MonoClass *parent = class->parent; - // Reverse order, so that last added methods are preferred - for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) { - MonoMethod *cm = parent->vtable [cm_index]; - - TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name)); - if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) { - TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING")); - vtable [im_slot] = cm; - /* Why do we need this? */ - if (cm->slot < 0) { - cm->slot = im_slot; - } - break; - } - TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n")); - } + TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n")); } - } else { - g_assert (vtable [im_slot] == override_im); } + } else { + g_assert (vtable [im_slot] == override_im); } } - - // If the class is not abstract, check that all its interface slots are full. - // The check is done here and not directly at the end of the loop above because - // 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 (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) { - for (i = 0; i < class->interface_offsets_count; i++) { - int ic_offset; - int im_index; - - ic = class->interfaces_packed [i]; - ic_offset = mono_class_interface_offset (class, ic); + } + + // If the class is not abstract, check that all its interface slots are full. + // The check is done here and not directly at the end of the loop above because + // 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 (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) { + for (i = 0; i < class->interface_offsets_count; i++) { + int ic_offset; + int im_index; + + ic = class->interfaces_packed [i]; + ic_offset = mono_class_interface_offset (class, ic); + + for (im_index = 0; im_index < ic->method.count; im_index++) { + MonoMethod *im = ic->methods [im_index]; + int im_slot = ic_offset + im->slot; - for (im_index = 0; im_index < ic->method.count; im_index++) { - MonoMethod *im = ic->methods [im_index]; - int im_slot = ic_offset + im->slot; - - if (im->flags & METHOD_ATTRIBUTE_STATIC) - continue; - - TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n", - im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL))); - if (vtable [im_slot] == NULL) { - print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum); - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); - if (override_map) - g_hash_table_destroy (override_map); - return; - } - } - } - } - } else { - for (k = class; k ; k = k->parent) { - int nifaces = 0; - - ifaces = mono_class_get_implemented_interfaces (k); - if (ifaces) { - nifaces = ifaces->len; - if (k->generic_class) { - pifaces = mono_class_get_implemented_interfaces ( - k->generic_class->container_class); - g_assert (pifaces && (pifaces->len == nifaces)); - } - } - for (i = 0; i < nifaces; i++) { - MonoClass *pic = NULL; - int j, l, io; - - ic = g_ptr_array_index (ifaces, i); - if (pifaces) - pic = g_ptr_array_index (pifaces, i); - g_assert (ic->interface_id <= k->max_interface_id); - io = mono_class_interface_offset (k, ic); - - g_assert (io >= 0); - g_assert (io <= max_vtsize); - - if (k == class) { - mono_class_setup_methods (ic); - for (l = 0; l < ic->method.count; l++) { - MonoMethod *im = ic->methods [l]; - - if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT)) - continue; - - for (j = 0; j < class->method.count; ++j) { - MonoMethod *cm = class->methods [j]; - if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) || - !((cm->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) || - !(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) - continue; - if (!strcmp(cm->name, im->name) && - mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) { - - /* CAS - SecurityAction.InheritanceDemand on interface */ - if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) { - mono_secman_inheritancedemand_method (cm, im); - } - - if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) - check_core_clr_override_method (class, cm, im); - - g_assert (io + l <= max_vtsize); - vtable [io + l] = cm; - TRACE_INTERFACE_VTABLE (printf (" [NOA] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name)); - TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm)); - TRACE_INTERFACE_VTABLE (printf ("\n")); - } - } - } - } else { - /* already implemented */ - if (io >= k->vtable_size) - continue; - } - - // Override methods with the same fully qualified name - for (l = 0; l < ic->method.count; l++) { - MonoMethod *im = ic->methods [l]; - char *qname, *fqname, *cname, *the_cname; - MonoClass *k1; - - if (vtable [io + l]) - continue; - - if (pic) { - the_cname = mono_type_get_name_full (&pic->byval_arg, MONO_TYPE_NAME_FORMAT_IL); - cname = the_cname; - } else { - the_cname = NULL; - cname = (char*)ic->name; - } - - qname = g_strconcat (cname, ".", im->name, NULL); - if (ic->name_space && ic->name_space [0]) - fqname = g_strconcat (ic->name_space, ".", cname, ".", im->name, NULL); - else - fqname = NULL; - - for (k1 = class; k1; k1 = k1->parent) { - for (j = 0; j < k1->method.count; ++j) { - MonoMethod *cm = k1->methods [j]; - - if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL)) - continue; - - if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) && - mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im)) && - ((vtable [io + l] == NULL) || mono_class_is_subclass_of (cm->klass, vtable [io + l]->klass, FALSE))) { - - /* CAS - SecurityAction.InheritanceDemand on interface */ - if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) { - mono_secman_inheritancedemand_method (cm, im); - } - - if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) - check_core_clr_override_method (class, cm, im); - - g_assert (io + l <= max_vtsize); - vtable [io + l] = cm; - TRACE_INTERFACE_VTABLE (printf (" [FQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name)); - TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm)); - TRACE_INTERFACE_VTABLE (printf ("\n")); - break; - } - } - } - g_free (the_cname); - g_free (qname); - g_free (fqname); - } - - // Override methods with the same name - for (l = 0; l < ic->method.count; l++) { - MonoMethod *im = ic->methods [l]; - MonoClass *k1; - - g_assert (io + l <= max_vtsize); - - if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT)) - continue; - - for (k1 = class; k1; k1 = k1->parent) { - for (j = 0; j < k1->method.count; ++j) { - MonoMethod *cm = k1->methods [j]; - - if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) || - !(cm->flags & METHOD_ATTRIBUTE_PUBLIC)) - continue; - - if (!strcmp(cm->name, im->name) && - mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) { - - /* CAS - SecurityAction.InheritanceDemand on interface */ - if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) { - mono_secman_inheritancedemand_method (cm, im); - } - - if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) - check_core_clr_override_method (class, cm, im); - - g_assert (io + l <= max_vtsize); - vtable [io + l] = cm; - TRACE_INTERFACE_VTABLE (printf (" [SQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name)); - TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm)); - TRACE_INTERFACE_VTABLE (printf ("\n")); - break; - } - - } - g_assert (io + l <= max_vtsize); - if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT)) - break; - } - } - - if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) { - for (l = 0; l < ic->method.count; l++) { - char *msig; - MonoMethod *im = ic->methods [l]; - if (im->flags & METHOD_ATTRIBUTE_STATIC) - continue; - g_assert (io + l <= max_vtsize); - - /* - * If one of our parents already implements this interface - * we can inherit the implementation. - */ - if (!(vtable [io + l])) { - MonoClass *parent = class->parent; - - for (; parent; parent = parent->parent) { - if (MONO_CLASS_IMPLEMENTS_INTERFACE (parent, ic->interface_id) && - parent->vtable) { - vtable [io + l] = parent->vtable [mono_class_interface_offset (parent, ic) + l]; - TRACE_INTERFACE_VTABLE (printf (" [INH] Filling slot %d (%d+%d) with method '%s'.'%s':'%s'\n", io + l, io, l, vtable [io + l]->klass->name_space, vtable [io + l]->klass->name, vtable [io + l]->name)); - } - } - } - - if (!(vtable [io + l])) { - for (j = 0; j < onum; ++j) { - g_print (" at slot %d: %s (%d) overrides %s (%d)\n", io+l, overrides [j*2+1]->name, - overrides [j*2+1]->slot, overrides [j*2]->name, overrides [j*2]->slot); - } - msig = mono_signature_get_desc (mono_method_signature (im), FALSE); - printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n", - mono_type_get_name (&ic->byval_arg), im->name, msig, class->name_space, class->name); - g_free (msig); - for (j = 0; j < class->method.count; ++j) { - MonoMethod *cm = class->methods [j]; - msig = mono_signature_get_desc (mono_method_signature (cm), TRUE); - - printf ("METHOD %s(%s)\n", cm->name, msig); - g_free (msig); - } - - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); - - if (ifaces) - g_ptr_array_free (ifaces, TRUE); - if (override_map) - g_hash_table_destroy (override_map); + if (im->flags & METHOD_ATTRIBUTE_STATIC) + continue; - return; - } - } - } - - for (l = 0; l < ic->method.count; l++) { - MonoMethod *im = vtable [io + l]; - - if (im) { - g_assert (io + l <= max_vtsize); - if (im->slot < 0) { - /* FIXME: why do we need this ? */ - im->slot = io + l; - /* g_assert_not_reached (); */ - } - } + TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n", + im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL))); + if (vtable [im_slot] == NULL) { + print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum); + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + if (override_map) + g_hash_table_destroy (override_map); + return; } } - if (ifaces) - g_ptr_array_free (ifaces, TRUE); - } + } } TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE)); - for (i = 0; i < class->method.count; ++i) { - MonoMethod *cm; - - cm = class->methods [i]; - - /* - * Non-virtual method have no place in the vtable. - * This also catches static methods (since they are not virtual). - */ - if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL)) - continue; - + class_iter = NULL; + while ((cm = mono_class_get_virtual_methods (class, &class_iter))) { /* * If the method is REUSE_SLOT, we must check in the * base class for a method to override. @@ -3229,13 +3201,12 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) { int slot = -1; for (k = class->parent; k ; k = k->parent) { - int j; - for (j = 0; j < k->method.count; ++j) { - MonoMethod *m1 = k->methods [j]; - MonoMethodSignature *cmsig, *m1sig; + gpointer k_iter; + MonoMethod *m1; - if (!(m1->flags & METHOD_ATTRIBUTE_VIRTUAL)) - continue; + k_iter = NULL; + while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) { + MonoMethodSignature *cmsig, *m1sig; cmsig = mono_method_signature (cm); m1sig = mono_method_signature (m1); @@ -3256,7 +3227,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) check_core_clr_override_method (class, cm, m1); - slot = k->methods [j]->slot; + slot = mono_method_get_vtable_slot (m1); g_assert (cm->slot < max_vtsize); if (!override_map) override_map = g_hash_table_new (mono_aligned_addr_hash, NULL); @@ -3387,6 +3358,43 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o } } } + + VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (class)); +} + +/* + * mono_method_get_vtable_slot: + * + * Returns method->slot, computing it if neccesary. + * LOCKING: Acquires the loader lock. + */ +int +mono_method_get_vtable_slot (MonoMethod *method) +{ + if (method->slot == -1) { + mono_class_setup_vtable (method->klass); + g_assert (method->slot != -1); + } + return method->slot; +} + +/** + * mono_method_get_vtable_index: + * @method: a method + * + * Returns the index into the runtime vtable to access the method or, + * in the case of a virtual generic method, the virtual generic method + * thunk. + */ +int +mono_method_get_vtable_index (MonoMethod *method) +{ + if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) { + MonoMethodInflated *imethod = (MonoMethodInflated*)method; + if (imethod->declaring->is_generic) + return mono_method_get_vtable_slot (imethod->declaring); + } + return mono_method_get_vtable_slot (method); } static MonoMethod *default_ghc = NULL; @@ -3482,6 +3490,7 @@ generic_array_methods (MonoClass *class) /*g_print ("array generic methods: %d\n", count_generic);*/ generic_array_method_num = count_generic; + g_list_free (list); return generic_array_method_num; } @@ -3649,8 +3658,8 @@ mono_class_init (MonoClass *class) class->field = gklass->field; mono_class_init (gklass); + // FIXME: Why is this needed ? mono_class_setup_methods (gklass); - mono_class_setup_properties (gklass); if (MONO_CLASS_IS_INTERFACE (class)) class->interface_id = mono_get_unique_iid (class); @@ -3756,29 +3765,33 @@ mono_class_init (MonoClass *class) if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) { MonoMethod *cmethod = NULL; - if (class->type_token) { - cmethod = find_method_in_metadata (class, "Finalize", 0, METHOD_ATTRIBUTE_VIRTUAL); - } else if (class->parent) { - /* FIXME: Optimize this */ - mono_class_setup_vtable (class); - if (class->exception_type || mono_loader_get_last_error ()) - goto fail; - cmethod = class->vtable [finalize_slot]; - } + if (class->parent && class->parent->has_finalize) { + class->has_finalize = 1; + } else { + if (class->type_token) { + cmethod = find_method_in_metadata (class, "Finalize", 0, METHOD_ATTRIBUTE_VIRTUAL); + } else if (class->parent) { + /* FIXME: Optimize this */ + mono_class_setup_vtable (class); + if (class->exception_type || mono_loader_get_last_error ()) + goto fail; + cmethod = class->vtable [finalize_slot]; + } - if (cmethod) { - /* Check that this is really the finalizer method */ - mono_class_setup_vtable (class); - if (class->exception_type || mono_loader_get_last_error ()) + if (cmethod) { + /* Check that this is really the finalizer method */ + mono_class_setup_vtable (class); + if (class->exception_type || mono_loader_get_last_error ()) goto fail; - class->has_finalize = 0; - if (class->parent) { - cmethod = class->vtable [finalize_slot]; - if (cmethod->is_inflated) - cmethod = ((MonoMethodInflated*)cmethod)->declaring; - if (cmethod != default_finalize) { - class->has_finalize = 1; + class->has_finalize = 0; + if (class->parent) { + cmethod = class->vtable [finalize_slot]; + if (cmethod->is_inflated) + cmethod = ((MonoMethodInflated*)cmethod)->declaring; + if (cmethod != default_finalize) { + class->has_finalize = 1; + } } } } @@ -4279,6 +4292,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) mono_metadata_load_generic_param_constraints ( image, type_token, class->generic_container); + if (class->image->assembly_name && !strcmp (class->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) { + if (!strncmp (name, "Vector", 6)) + class->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"); + } + mono_loader_unlock (); mono_profiler_class_loaded (class, MONO_PROFILE_OK); @@ -4415,6 +4433,9 @@ mono_generic_class_get_class (MonoGenericClass *gclass) return klass; } +/* + * LOCKING: Acquires the loader lock. + */ MonoClass * mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar) { @@ -4443,7 +4464,7 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb /* FIXME: */ image = mono_defaults.corlib; - klass = param->pklass = mono_image_alloc0 (image, sizeof (MonoClass)); + klass = mono_image_alloc0 (image, sizeof (MonoClass)); if (param->name) klass->name = param->name; @@ -4514,6 +4535,10 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb mono_class_setup_supertypes (klass); + mono_memory_barrier (); + + param->pklass = klass; + mono_loader_unlock (); mono_profiler_class_loaded (klass, MONO_PROFILE_OK); @@ -4990,7 +5015,7 @@ mono_class_get_field_idx (MonoClass *class, int idx) int i; for (i = 0; i < class->field.count; ++i) - if (class->fields [i].name == name) + if (mono_field_get_name (&class->fields [i]) == name) return &class->fields [i]; g_assert_not_reached (); } else { @@ -5041,7 +5066,7 @@ mono_class_get_field_from_name (MonoClass *klass, const char *name) mono_class_setup_fields_locking (klass); while (klass) { for (i = 0; i < klass->field.count; ++i) { - if (strcmp (name, klass->fields [i].name) == 0) + if (strcmp (name, mono_field_get_name (&klass->fields [i])) == 0) return &klass->fields [i]; } klass = klass->parent; @@ -5082,6 +5107,16 @@ mono_class_get_field_token (MonoClassField *field) return 0; } +static int +mono_field_get_index (MonoClassField *field) +{ + int index = field - field->parent->fields; + + g_assert (index >= 0 && index < field->parent->field.count); + + return index; +} + /* * mono_class_get_field_default_value: * @@ -5092,21 +5127,32 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ { guint32 cindex; guint32 constant_cols [MONO_CONSTANT_SIZE]; + int field_index; + MonoClass *klass = field->parent; g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT); - if (!field->data) { + if (!klass->field_def_values) { + mono_loader_lock (); + if (!klass->field_def_values) + klass->field_def_values = mono_image_alloc0 (klass->image, sizeof (MonoFieldDefaultValue) * klass->field.count); + mono_loader_unlock (); + } + + field_index = mono_field_get_index (field); + + if (!klass->field_def_values [field_index].data) { cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0); g_assert (cindex); 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); - field->def_type = constant_cols [MONO_CONSTANT_TYPE]; - field->data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]); + klass->field_def_values [field_index].def_type = constant_cols [MONO_CONSTANT_TYPE]; + klass->field_def_values [field_index].data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]); } - *def_type = field->def_type; - return field->data; + *def_type = klass->field_def_values [field_index].def_type; + return klass->field_def_values [field_index].data; } guint32 @@ -5914,6 +5960,9 @@ mono_class_get_cctor (MonoClass *klass) if (mono_class_get_cached_class_info (klass, &cached_info)) return mono_get_method (klass->image, cached_info.cctor_token, klass); + if (klass->generic_class && !klass->methods) + return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class)); + return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME); } @@ -6401,6 +6450,8 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter) return NULL; if (!*iter) { mono_class_setup_fields_locking (klass); + if (klass->exception_type) + return NULL; /* start from the first */ if (klass->field.count) { return *iter = &klass->fields [0]; @@ -6457,6 +6508,71 @@ mono_class_get_methods (MonoClass* klass, gpointer *iter) return NULL; } +/* + * mono_class_get_virtual_methods: + * + * Iterate over the virtual methods of KLASS. + * + * LOCKING: Assumes the loader lock is held (because of the klass->methods check). + */ +static MonoMethod* +mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) +{ + MonoMethod** method; + if (!iter) + return NULL; + if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass) || mono_debug_using_mono_debugger ()) { + if (!*iter) { + mono_class_setup_methods (klass); + /* start from the first */ + method = &klass->methods [0]; + } else { + method = *iter; + method++; + } + while (method < &klass->methods [klass->method.count]) { + if (((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL)) + break; + method ++; + } + if (method < &klass->methods [klass->method.count]) { + *iter = method; + return *method; + } else { + return NULL; + } + } else { + /* Search directly in metadata to avoid calling setup_methods () */ + MonoMethod *res = NULL; + int i, start_index; + + if (!*iter) { + start_index = 0; + } else { + start_index = GPOINTER_TO_UINT (*iter); + } + + for (i = start_index; i < klass->method.count; ++i) { + guint32 cols [MONO_METHOD_SIZE]; + + /* class->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); + + if (cols [MONO_METHOD_FLAGS] & METHOD_ATTRIBUTE_VIRTUAL) + break; + } + + if (i < klass->method.count) { + res = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass); + /* Add 1 here so the if (*iter) check fails */ + *iter = GUINT_TO_POINTER (i + 1); + return res; + } else { + return NULL; + } + } +} + /** * mono_class_get_properties: * @klass: the MonoClass to act on @@ -6698,6 +6814,34 @@ mono_field_get_offset (MonoClassField *field) return field->offset; } +static const char * +mono_field_get_rva (MonoClassField *field) +{ + guint32 rva; + int field_index; + MonoClass *klass = field->parent; + + g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA); + + if (!klass->field_def_values) { + mono_loader_lock (); + if (!klass->field_def_values) + klass->field_def_values = mono_image_alloc0 (klass->image, sizeof (MonoFieldDefaultValue) * klass->field.count); + mono_loader_unlock (); + } + + field_index = mono_field_get_index (field); + + if (!klass->field_def_values [field_index].data && !klass->image->dynamic) { + mono_metadata_field_info (field->parent->image, klass->field.first + 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->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva); + } + + return klass->field_def_values [field_index].data; +} + /** * mono_field_get_data; * @field: the MonoClassField to act on @@ -6706,9 +6850,17 @@ mono_field_get_offset (MonoClassField *field) * data if it has an RVA flag. */ const char * -mono_field_get_data (MonoClassField *field) +mono_field_get_data (MonoClassField *field) { - return field->data; + if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) { + MonoTypeEnum def_type; + + return mono_class_get_field_default_value (field, &def_type); + } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) { + return mono_field_get_rva (field); + } else { + return NULL; + } } /** @@ -6908,7 +7060,7 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p mono_class_init (klass); - if (klass->methods || klass->generic_class) { + if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) { mono_class_setup_methods (klass); for (i = 0; i < klass->method.count; ++i) { MonoMethod *method = klass->methods [i]; @@ -7105,7 +7257,7 @@ mono_class_get_generic_type_definition (MonoClass *klass) * * Visibility checks ignoring generic instantiations. */ -static gboolean +gboolean mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent) { int i; @@ -7506,7 +7658,7 @@ mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass) gboolean mono_class_generic_sharing_enabled (MonoClass *class) { -#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__ppc__) || defined(__powerpc__) +#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__mono_ppc__) static gboolean supported = TRUE; #else /* Not supported by the JIT backends */ @@ -7559,3 +7711,19 @@ mono_class_generic_sharing_enabled (MonoClass *class) g_assert_not_reached (); } } + +/* + * mono_class_setup_interface_id: + * + * Initializes MonoClass::interface_id if required. + * + * LOCKING: Acquires the loader lock. + */ +void +mono_class_setup_interface_id (MonoClass *class) +{ + mono_loader_lock (); + if (MONO_CLASS_IS_INTERFACE (class) && !class->interface_id) + class->interface_id = mono_get_unique_iid (class); + mono_loader_unlock (); +}