X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=610542424dd4de15256c21099970f34b6caf502e;hb=42a1173c3ffab9bbd5730ee8e7fcd7cdebafc28d;hp=c4d3a6862775ad7845f3618ea24b9712502fe4c0;hpb=be39e9eb1eb8ecfae38c9ad1cab7cdb8cb754ddf;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index c4d3a686277..610542424dd 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include MonoStats mono_stats; @@ -46,8 +46,8 @@ static MonoGetClassFromName get_class_from_name = NULL; static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token); static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res); -void (*mono_debugger_start_class_init_func) (MonoClass *klass) = NULL; void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL; +void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL; /* * mono_class_from_typeref: @@ -181,11 +181,12 @@ _mono_type_get_assembly_name (MonoClass *klass, GString *str) MonoAssembly *ta = klass->image->assembly; g_string_append_printf ( - str, ", %s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s", + str, ", %s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s", ta->aname.name, ta->aname.major, ta->aname.minor, ta->aname.build, ta->aname.revision, ta->aname.culture && *ta->aname.culture? ta->aname.culture: "neutral", - ta->aname.public_key_token [0] ? (char *)ta->aname.public_key_token : "null"); + ta->aname.public_key_token [0] ? (char *)ta->aname.public_key_token : "null", + (ta->aname.flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : ""); } static inline void @@ -632,6 +633,7 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin MonoMethodInflated *iresult, *cached; MonoMethodSignature *sig; MonoGenericContext tmp_context; + gboolean is_mb_open = FALSE; /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */ while (method->is_inflated) { @@ -650,10 +652,25 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin if (!method->generic_container && !method->klass->generic_container) return method; + /* + * The reason for this hack is to fix the behavior of inflating generic methods that come from a MethodBuilder. + * What happens is that instantiating a generic MethodBuilder with its own arguments should create a diferent object. + * This is opposite to the way non-SRE MethodInfos behave. + * + * FIXME: express this better, somehow! + */ + is_mb_open = method->generic_container && + method->klass->image->dynamic && !method->klass->wastypebuilder && + context->method_inst == method->generic_container->context.method_inst; + mono_stats.inflated_method_count++; iresult = g_new0 (MonoMethodInflated, 1); iresult->context = *context; iresult->declaring = method; + iresult->is_mb_open = is_mb_open; + + if (!context->method_inst && method->generic_container) + iresult->context.method_inst = method->generic_container->context.method_inst; mono_loader_lock (); cached = mono_method_inflated_lookup (iresult, FALSE); @@ -665,17 +682,21 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin sig = mono_method_signature (method); if (sig->pinvoke) { - iresult->method.pinvoke = *(MonoMethodPInvoke*)method; + memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke)); } else { - iresult->method.normal = *(MonoMethodNormal*)method; + memcpy (&iresult->method.normal, method, sizeof (MonoMethodNormal)); iresult->method.normal.header = NULL; } result = (MonoMethod *) iresult; result->is_inflated = 1; - /* result->generic_container = NULL; */ result->signature = NULL; + if (context->method_inst) + result->generic_container = NULL; + + /* Due to the memcpy above, !context->method_inst => result->generic_container == method->generic_container */ + if (!klass_hint || !klass_hint->generic_class || klass_hint->generic_class->container_class != method->klass || klass_hint->generic_class->context.class_inst != context->class_inst) @@ -691,11 +712,6 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin mono_metadata_free_type (inflated); } - if (context->method_inst) - result->generic_container = NULL; - else if (method->generic_container) - iresult->context.method_inst = method->generic_container->context.method_inst; - mono_method_inflated_lookup (iresult, TRUE); mono_loader_unlock (); return result; @@ -805,6 +821,7 @@ mono_class_setup_fields (MonoClass *class) MonoClass *gklass = class->generic_class->container_class; mono_class_setup_fields (gklass); top = gklass->field.count; + class->field.count = gklass->field.count; } class->instance_size = 0; @@ -1000,8 +1017,15 @@ mono_class_has_references (MonoClass *klass) #define IS_GC_REFERENCE(t) ((t)->type == MONO_TYPE_U && class->image == mono_defaults.corlib) #endif -static MonoType* -mono_get_basic_type_from_generic (MonoType *type) +/* + * mono_type_get_basic_type_from_generic: + * @type: a type + * + * Returns a closed type corresponding to the possibly open type + * passed to it. + */ +MonoType* +mono_type_get_basic_type_from_generic (MonoType *type) { /* When we do generic sharing we let type variables stand for reference types. */ if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) @@ -1071,7 +1095,7 @@ mono_class_layout_fields (MonoClass *class) if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { ftype = mono_type_get_underlying_type (field->type); - ftype = mono_get_basic_type_from_generic (ftype); + ftype = mono_type_get_basic_type_from_generic (ftype); if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) class->has_references = TRUE; } @@ -1084,7 +1108,7 @@ mono_class_layout_fields (MonoClass *class) if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) { ftype = mono_type_get_underlying_type (field->type); - ftype = mono_get_basic_type_from_generic (ftype); + ftype = mono_type_get_basic_type_from_generic (ftype); if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) class->has_static_refs = TRUE; } @@ -1096,7 +1120,7 @@ mono_class_layout_fields (MonoClass *class) field = &class->fields [i]; ftype = mono_type_get_underlying_type (field->type); - ftype = mono_get_basic_type_from_generic (ftype); + ftype = mono_type_get_basic_type_from_generic (ftype); if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) { if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) class->has_static_refs = TRUE; @@ -1140,7 +1164,7 @@ mono_class_layout_fields (MonoClass *class) continue; ftype = mono_type_get_underlying_type (field->type); - ftype = mono_get_basic_type_from_generic (ftype); + ftype = mono_type_get_basic_type_from_generic (ftype); if (gc_aware_layout) { if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) { if (pass == 1) @@ -1202,7 +1226,8 @@ mono_class_layout_fields (MonoClass *class) continue; size = mono_type_size (field->type, &align); - + class->min_align = MAX (align, class->min_align); + /* * When we get here, field->offset is already set by the * loader (for either runtime fields or fields loaded from metadata). @@ -1211,7 +1236,7 @@ mono_class_layout_fields (MonoClass *class) */ field->offset += sizeof (MonoObject); ftype = mono_type_get_underlying_type (field->type); - ftype = mono_get_basic_type_from_generic (ftype); + ftype = mono_type_get_basic_type_from_generic (ftype); if (MONO_TYPE_IS_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) { if (field->offset % sizeof (gpointer)) { mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); @@ -1309,8 +1334,6 @@ mono_class_setup_methods (MonoClass *class) for (i = 0; i < class->method.count; ++i) { int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1); methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class); - if (class->valuetype && methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !(methods [i]->flags & MONO_METHOD_ATTR_STATIC)) - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); } } @@ -1321,6 +1344,9 @@ mono_class_setup_methods (MonoClass *class) /* Leave this assignment as the last op in this function */ class->methods = methods; + if (mono_debugger_class_loaded_methods_func) + mono_debugger_class_loaded_methods_func (class); + mono_loader_unlock (); } @@ -1747,9 +1773,11 @@ print_implemented_interfaces (MonoClass *klass) { printf ("Packed interface table for class %s has size %d\n", klass->name, klass->interface_offsets_count); for (i = 0; i < klass->interface_offsets_count; i++) - printf (" [%d][UUID %d][SLOT %d] interface %s\n", i, + printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i, klass->interfaces_packed [i]->interface_id, klass->interface_offsets_packed [i], + klass->interfaces_packed [i]->method.count, + klass->interfaces_packed [i]->name_space, klass->interfaces_packed [i]->name ); printf ("Interface flags: "); for (i = 0; i <= klass->max_interface_id; i++) @@ -1769,6 +1797,12 @@ print_implemented_interfaces (MonoClass *klass) { for (i = 0; i < ifaces->len; i++) { MonoClass *ic = g_ptr_array_index (ifaces, i); printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name); + printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i, + ic->interface_id, + mono_class_interface_offset (klass, ic), + ic->method.count, + ic->name_space, + ic->name ); } g_ptr_array_free (ifaces, TRUE); } @@ -1885,7 +1919,7 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume interface_count *= 3; real_count = interface_count; if (internal_enumerator) - real_count += idepth; + real_count += idepth + eclass->interface_offsets_count; interfaces = g_malloc0 (sizeof (MonoClass*) * real_count); if (MONO_CLASS_IS_INTERFACE (eclass)) { interfaces [0] = mono_defaults.object_class; @@ -1951,6 +1985,15 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/ 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));*/ + j ++; + } } } *num = real_count; @@ -2225,6 +2268,267 @@ 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 + +#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE) +#define DEBUG_INTERFACE_VTABLE(stmt) do {\ + stmt;\ +} while (0) +#else +#define DEBUG_INTERFACE_VTABLE(stmt) +#endif + +#if TRACE_INTERFACE_VTABLE_CODE +#define TRACE_INTERFACE_VTABLE(stmt) do {\ + stmt;\ +} while (0) +#else +#define TRACE_INTERFACE_VTABLE(stmt) +#endif + + +#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE) +static char* +mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace) +{ + int i; + char *result; + GString *res = g_string_new (""); + + g_string_append_c (res, '('); + for (i = 0; i < sig->param_count; ++i) { + if (i > 0) + g_string_append_c (res, ','); + mono_type_get_desc (res, sig->params [i], include_namespace); + } + g_string_append (res, ")=>"); + if (sig->ret != NULL) { + mono_type_get_desc (res, sig->ret, include_namespace); + } else { + g_string_append (res, "NULL"); + } + result = res->str; + g_string_free (res, FALSE); + return result; +} +static void +print_method_signatures (MonoMethod *im, MonoMethod *cm) { + char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE); + char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE); + printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig); + g_free (im_sig); + g_free (cm_sig); + +} + +#endif +static gboolean +check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty, gboolean security_enabled) { + if (strcmp (im->name, cm->name) == 0) { + if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) { + TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]")); + return FALSE; + } + if (! slot_is_empty) { + if (require_newslot) { + if (! interface_is_explicitly_implemented_by_class) { + TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]")); + return FALSE; + } + if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) { + TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]")); + return FALSE; + } + } else { + TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]")); + } + } + if (! mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) { + TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED ")); + TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm)); + TRACE_INTERFACE_VTABLE (printf ("]")); + return FALSE; + } + TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]")); + /* 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); + TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]")); + return TRUE; + } else { + MonoClass *ic = im->klass; + const char *ic_name_space = ic->name_space; + const char *ic_name = ic->name; + char *subname; + + if (! require_newslot) { + TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]")); + return FALSE; + } + if (cm->klass->rank == 0) { + TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]")); + return FALSE; + } + if (! mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) { + TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED ")); + TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm)); + TRACE_INTERFACE_VTABLE (printf ("]")); + return FALSE; + } + if (mono_class_get_image (ic) != mono_defaults.corlib) { + TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]")); + return FALSE; + } + if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) { + TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]")); + return FALSE; + } + if ((ic_name == NULL) || ((strcmp (ic_name, "IEnumerable`1") != 0) && (strcmp (ic_name, "ICollection`1") != 0) && (strcmp (ic_name, "IList`1") != 0))) { + TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]")); + return FALSE; + } + + subname = strstr (cm->name, ic_name_space); + if (subname != cm->name) { + TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]")); + return FALSE; + } + subname += strlen (ic_name_space); + if (subname [0] != '.') { + TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]")); + return FALSE; + } + subname ++; + if (strstr (subname, ic_name) != subname) { + TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]")); + return FALSE; + } + subname += strlen (ic_name); + if (subname [0] != '.') { + TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]")); + return FALSE; + } + subname ++; + if (strcmp (subname, im->name) != 0) { + TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]")); + return FALSE; + } + + TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]")); + /* 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); + + TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]")); + return TRUE; + } +} + +#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE) +static void +foreach_override (gpointer key, gpointer value, gpointer user_data) { + MonoMethod *method = key; + MonoMethod *override = value; + MonoClass *method_class = mono_method_get_class (method); + MonoClass *override_class = mono_method_get_class (override); + + printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n", + mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method), + mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override)); +} +static void +print_overrides (GHashTable *override_map, const char *message) { + if (override_map) { + printf ("Override map \"%s\" START:\n", message); + g_hash_table_foreach (override_map, foreach_override, NULL); + printf ("Override map \"%s\" END.\n", message); + } else { + printf ("Override map \"%s\" EMPTY.\n", message); + } +} +static void +print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) { + char *full_name = mono_type_full_name (&class->byval_arg); + int i; + int parent_size; + + printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size); + + if (print_interfaces) { + print_implemented_interfaces (class); + printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size); + } + + if (class->parent) { + parent_size = class->parent->vtable_size; + } else { + parent_size = 0; + } + for (i = 0; i < size; ++i) { + MonoMethod *cm = vtable [i]; + if (cm) { + char *cm_name = mono_method_full_name (cm, TRUE); + char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N'); + printf (" [%c][%03d][INDEX %03d] %s\n", newness, i, cm->slot, cm_name); + g_free (cm_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; + char *method_signature; + + for (index = 0; index < onum; ++index) { + g_print (" at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name, + overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot); + } + method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE); + 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); + for (index = 0; index < class->method.count; ++index) { + MonoMethod *cm = class->methods [index]; + method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE); + + printf ("METHOD %s(%s)\n", cm->name, method_signature); + g_free (method_signature); + } +} + /* * LOCKING: this is supposed to be called with the loader lock held. */ @@ -2237,6 +2541,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o GPtrArray *ifaces, *pifaces = NULL; GHashTable *override_map = NULL; gboolean security_enabled = mono_is_security_manager_active (); +#if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE) + int first_non_interface_slot; +#endif if (class->vtable) return; @@ -2248,6 +2555,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o max_vtsize += ic->method.count; } g_ptr_array_free (ifaces, TRUE); + ifaces = NULL; } if (class->parent) { @@ -2266,10 +2574,45 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o cur_slot = setup_interface_offsets (class, cur_slot); max_iid = class->max_interface_id; + DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot); - if (class->parent && class->parent->vtable_size) - memcpy (vtable, class->parent->vtable, sizeof (gpointer) * class->parent->vtable_size); + 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); + + // 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; + + 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)); /* override interface methods */ for (i = 0; i < onum; i++) { MonoMethod *decl = overrides [i*2]; @@ -2289,231 +2632,361 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o check_core_clr_override_method (class, vtable [dslot], decl); } } + 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)); - 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); + 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); - g_assert (io + l <= max_vtsize); - vtable [io + l] = cm; - } + 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 { - /* already implemented */ - if (io >= k->vtable_size) - continue; + interface_is_explicitly_implemented_by_class = TRUE; } - - // 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; + + // 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 (vtable [io + l]) + if (im->flags & METHOD_ATTRIBUTE_STATIC) continue; - if (pic) { - the_cname = mono_type_get_name_full (&pic->byval_arg, MONO_TYPE_NAME_FORMAT_IL); - cname = the_cname; + // 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]; + + 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")); + 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 ((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")); + } + } } else { - the_cname = NULL; - cname = (char*)ic->name; + 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); + + for (im_index = 0; im_index < ic->method.count; im_index++) { + MonoMethod *im = ic->methods [im_index]; + int im_slot = ic_offset + im->slot; - 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; + if (im->flags & METHOD_ATTRIBUTE_STATIC) + continue; - for (k1 = class; k1; k1 = k1->parent) { - for (j = 0; j < k1->method.count; ++j) { - MonoMethod *cm = k1->methods [j]; + 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; - if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL)) - continue; + 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); - 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))) { + g_assert (io >= 0); + g_assert (io <= max_vtsize); - /* CAS - SecurityAction.InheritanceDemand on interface */ - if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) { - mono_secman_inheritancedemand_method (cm, im); - } + if (k == class) { + mono_class_setup_methods (ic); + for (l = 0; l < ic->method.count; l++) { + MonoMethod *im = ic->methods [l]; - if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) - check_core_clr_override_method (class, cm, im); + if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT)) + continue; - g_assert (io + l <= max_vtsize); - vtable [io + l] = cm; - break; + 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; } - 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; + // 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; - for (k1 = class; k1; k1 = k1->parent) { - for (j = 0; j < k1->method.count; ++j) { - MonoMethod *cm = k1->methods [j]; + if (vtable [io + l]) + continue; - if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) || - !(cm->flags & METHOD_ATTRIBUTE_PUBLIC)) - 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; + } - 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); + 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; } - - 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; - break; } - } - g_assert (io + l <= max_vtsize); - if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT)) - break; + g_free (the_cname); + g_free (qname); + g_free (fqname); } - } - if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) { + // Override methods with the same name for (l = 0; l < ic->method.count; l++) { - char *msig; - MonoMethod *im = ic->methods [l]; - if (im->flags & METHOD_ATTRIBUTE_STATIC) - continue; + MonoMethod *im = ic->methods [l]; + MonoClass *k1; + 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; + if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT)) + continue; - 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]; + 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 (!(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); + 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; - printf ("METHOD %s(%s)\n", cm->name, msig); - g_free (msig); + 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)); + } + } } - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + 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); + } - if (ifaces) - g_ptr_array_free (ifaces, TRUE); - if (override_map) - g_hash_table_destroy (override_map); + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); - return; + if (ifaces) + g_ptr_array_free (ifaces, TRUE); + if (override_map) + g_hash_table_destroy (override_map); + + 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 (); */ + + 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 (); */ + } } } } - } - if (ifaces) - g_ptr_array_free (ifaces, TRUE); - } + 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; @@ -2630,6 +3103,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o memcpy (class->vtable, vtable, sizeof (gpointer) * class->vtable_size); } + DEBUG_INTERFACE_VTABLE (print_vtable_full (class, class->vtable, class->vtable_size, first_non_interface_slot, "FINALLY", FALSE)); if (mono_print_vtable) { int icount = 0; @@ -2731,6 +3205,7 @@ generic_array_methods (MonoClass *class) GList *list = NULL, *tmp; if (generic_array_method_num) return generic_array_method_num; + mono_class_setup_methods (class->parent); for (i = 0; i < class->parent->method.count; i++) { MonoMethod *m = class->parent->methods [i]; if (!strncmp (m->name, "InternalArray__", 15)) { @@ -2866,6 +3341,10 @@ set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error) break; } + case MONO_EXCEPTION_BAD_IMAGE: + class->exception_data = error->msg; + break; + default : g_assert_not_reached (); } @@ -2941,9 +3420,6 @@ mono_class_init (MonoClass *class) if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) check_core_clr_inheritance (class); - if (mono_debugger_start_class_init_func) - mono_debugger_start_class_init_func (class); - mono_stats.initialized_class_count++; if (class->generic_class && !class->generic_class->is_dynamic) { @@ -3619,6 +4095,9 @@ mono_generic_class_get_class (MonoGenericClass *gclass) klass->name = gklass->name; klass->name_space = gklass->name_space; + + mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); + klass->image = gklass->image; klass->flags = gklass->flags; klass->type_token = gklass->type_token; @@ -3689,6 +4168,8 @@ mono_generic_class_get_class (MonoGenericClass *gclass) if (MONO_CLASS_IS_INTERFACE (klass)) setup_interface_offsets (klass, 0); + mono_profiler_class_loaded (klass, MONO_PROFILE_OK); + mono_loader_unlock (); return klass; @@ -4327,6 +4808,33 @@ mono_class_get_field_token (MonoClassField *field) return 0; } +/* + * mono_class_get_field_default_value: + * + * Return the default value of the field as a pointer into the metadata blob. + */ +const char* +mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type) +{ + guint32 cindex; + guint32 constant_cols [MONO_CONSTANT_SIZE]; + + g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT); + + if (!field->data) { + cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), cindex + 1); + 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]); + } + + *def_type = field->def_type; + return field->data; +} + guint32 mono_class_get_event_token (MonoEvent *event) { @@ -4485,8 +4993,15 @@ mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *c { MonoClass *class = NULL; - if (image->dynamic) + if (image->dynamic) { + int table = mono_metadata_token_table (type_token); + + if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) { + mono_loader_set_error_bad_image (g_strdup ("Bad type token.")); + return NULL; + } return mono_lookup_dynamic_token (image, type_token, context); + } switch (type_token & 0xff000000){ case MONO_TOKEN_TYPE_DEF: @@ -4674,7 +5189,7 @@ find_nocase (gpointer key, gpointer value, gpointer user_data) /** * mono_class_from_name_case: - * @image: The MonoImage where the type is looked up in, or NULL for looking up in all loaded assemblies + * @image: The MonoImage where the type is looked up in * @name_space: the type namespace * @name: the type short name. * @@ -4767,7 +5282,7 @@ return_nested_in (MonoClass *class, char *nested) { /** * mono_class_from_name: - * @image: The MonoImage where the type is looked up in, or NULL for looking up in all loaded assemblies + * @image: The MonoImage where the type is looked up in * @name_space: the type namespace * @name: the type short name. * @@ -4923,6 +5438,14 @@ mono_class_has_variant_generic_params (MonoClass *klass) return FALSE; } +/** + * mono_class_is_assignable_from: + * @klass: the class to be assigned to + * @oklass: the source class + * + * Return: true if an instance of object oklass can be assigned to an + * instance of object @klass + */ gboolean mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) { @@ -5029,10 +5552,11 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) return mono_class_has_parent (oklass, klass); } -/* +/** * mono_class_get_cctor: + * @klass: A MonoClass pointer * - * Returns the static constructor of @klass if it exists, NULL otherwise. + * Returns: the static constructor of @klass if it exists, NULL otherwise. */ MonoMethod* mono_class_get_cctor (MonoClass *klass) @@ -5048,10 +5572,11 @@ mono_class_get_cctor (MonoClass *klass) return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME); } -/* +/** * mono_class_get_finalizer: + * @klass: The MonoClass pointer * - * Returns the finalizer method of @klass if it exists, NULL otherwise. + * Returns: the finalizer method of @klass if it exists, NULL otherwise. */ MonoMethod* mono_class_get_finalizer (MonoClass *klass) @@ -5071,10 +5596,12 @@ mono_class_get_finalizer (MonoClass *klass) } } -/* +/** * mono_class_needs_cctor_run: + * @klass: the MonoClass pointer + * @caller: a MonoMethod describing the caller * - * Determines whenever the class has a static constructor and whenever it + * Determines whenever the class has a static constructor and whenever it * needs to be called when executing CALLER. */ gboolean @@ -5165,7 +5692,7 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class, { if (image->dynamic) { MonoClass *tmp_handle_class; - gpointer obj = mono_lookup_dynamic_token_class (image, token, &tmp_handle_class, context); + gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context); g_assert (tmp_handle_class); if (handle_class) @@ -5255,13 +5782,13 @@ mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext * { MonoClass *handle_class; - return lookup_dynamic (image, token, &handle_class, context); + return lookup_dynamic (image, token, TRUE, &handle_class, context); } gpointer -mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class, MonoGenericContext *context) +mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context) { - return lookup_dynamic (image, token, handle_class, context); + return lookup_dynamic (image, token, valid_token, handle_class, context); } static MonoGetCachedClassInfo get_cached_class_info = NULL; @@ -5791,6 +6318,18 @@ mono_field_get_flags (MonoClassField *field) return field->type->attrs; } +/** + * mono_field_get_offset; + * @field: the MonoClassField to act on + * + * Returns: the field offset. + */ +guint32 +mono_field_get_offset (MonoClassField *field) +{ + return field->offset; +} + /** * mono_field_get_data; * @field: the MonoClassField to act on @@ -6124,6 +6663,9 @@ mono_class_get_exception_for_failure (MonoClass *klass) return ex; } + case MONO_EXCEPTION_BAD_IMAGE: { + return mono_get_exception_bad_image_format (klass->exception_data); + } default: { MonoLoaderError *error; MonoException *ex; @@ -6187,10 +6729,17 @@ static gboolean can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level) { MonoClass *member_generic_def; - if (access_klass->generic_class && access_klass->generic_class->container_class && + if (((access_klass->generic_class && access_klass->generic_class->container_class) || + access_klass->generic_container) && (member_generic_def = get_generic_definition_class (member_klass))) { - if (can_access_member (access_klass->generic_class->container_class, - member_generic_def, access_level)) + MonoClass *access_container; + + if (access_klass->generic_container) + access_container = access_klass; + else + access_container = access_klass->generic_class->container_class; + + if (can_access_member (access_container, member_generic_def, access_level)) return TRUE; } @@ -6340,3 +6889,48 @@ mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass) { return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst; } + +/* + * mono_class_generic_sharing_enabled: + * @class: a class + * + * Returns whether generic sharing is enabled for class. + * + * This is a stop-gap measure to slowly introduce generic sharing + * until we have all the issues sorted out, at which time this + * function will disappear and generic sharing will always be enabled. + */ +gboolean +mono_class_generic_sharing_enabled (MonoClass *class) +{ + static int generic_sharing = MONO_GENERIC_SHARING_CORLIB; + static gboolean inited = FALSE; + + if (!inited) { + const char *option; + + if ((option = g_getenv ("MONO_GENERIC_SHARING"))) { + if (strcmp (option, "corlib") == 0) + generic_sharing = MONO_GENERIC_SHARING_CORLIB; + else if (strcmp (option, "all") == 0) + generic_sharing = MONO_GENERIC_SHARING_ALL; + else if (strcmp (option, "none") == 0) + generic_sharing = MONO_GENERIC_SHARING_NONE; + else + g_warning ("Unknown generic sharing option `%s'.", option); + } + + inited = TRUE; + } + + switch (generic_sharing) { + case MONO_GENERIC_SHARING_NONE: + return FALSE; + case MONO_GENERIC_SHARING_ALL: + return TRUE; + case MONO_GENERIC_SHARING_CORLIB : + return class->image == mono_defaults.corlib; + default: + g_assert_not_reached (); + } +}