X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=4521e49c4aadaf0fbdc2b37e60662a806fff898e;hb=1f771d12ba9c7e4e50810b02d7cf1b466e7009d7;hp=41fc3291732d04d7596bc9b860e6585245d6aa7b;hpb=1c81b381f61515ed70ecb98cef71b15e228d9141;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index 41fc3291732..4521e49c4aa 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -39,6 +39,7 @@ #include #include #include +#include MonoStats mono_stats; @@ -1071,7 +1072,7 @@ mono_class_setup_fields (MonoClass *class) gboolean explicit_size; MonoClassField *field; MonoGenericContainer *container = NULL; - MonoClass *gklass = NULL; + MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL; if (class->size_inited) return; @@ -1086,12 +1087,16 @@ mono_class_setup_fields (MonoClass *class) return; } - if (class->generic_class) { - MonoClass *gklass = class->generic_class->container_class; - mono_class_setup_fields (gklass); - top = gklass->field.count; - class->field.first = gklass->field.first; - class->field.count = gklass->field.count; + if (gtd) { + mono_class_setup_fields (gtd); + if (gtd->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + return; + } + + top = gtd->field.count; + class->field.first = gtd->field.first; + class->field.count = gtd->field.count; } class->instance_size = 0; @@ -1149,17 +1154,9 @@ mono_class_setup_fields (MonoClass *class) if (class->generic_container) { container = class->generic_container; - } else if (class->generic_class) { - gklass = class->generic_class->container_class; - container = gklass->generic_container; + } else if (gtd) { + container = gtd->generic_container; g_assert (container); - - mono_class_setup_fields (gklass); - - if (gklass->exception_type) { - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); - return; - } } /* @@ -1171,8 +1168,8 @@ mono_class_setup_fields (MonoClass *class) field->parent = class; - if (class->generic_class) { - MonoClassField *gfield = &gklass->fields [i]; + if (gtd) { + MonoClassField *gfield = >d->fields [i]; 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.*/ @@ -2475,6 +2472,37 @@ find_array_interface (MonoClass *klass, const char *name) return -1; } +/* + * Return the number of virtual methods. + * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods. + * FIXME It would be nice if this information could be cached somewhere. + */ +static int +count_virtual_methods (MonoClass *class) +{ + int i, count = 0; + guint32 flags; + class = mono_class_get_generic_type_definition (class); /*We can find this information by looking at the GTD*/ + + if (class->methods || !MONO_CLASS_HAS_STATIC_METADATA (class)) { + mono_class_setup_methods (class); + + for (i = 0; i < class->method.count; ++i) { + flags = class->methods [i]->flags; + if (flags & METHOD_ATTRIBUTE_VIRTUAL) + ++count; + } + } else { + for (i = 0; i < class->method.count; ++i) { + flags = mono_metadata_decode_table_row_col (class->image, MONO_TABLE_METHOD, class->method.first + i, MONO_METHOD_FLAGS); + + if (flags & METHOD_ATTRIBUTE_VIRTUAL) + ++count; + } + } + return count; +} + /* * LOCKING: this is supposed to be called with the loader lock held. */ @@ -2541,6 +2569,24 @@ setup_interface_offsets (MonoClass *class, int cur_slot) interface_offsets_full [i] = -1; } + for (k = class->parent; k ; k = k->parent) { + ifaces = mono_class_get_implemented_interfaces (k); + if (ifaces) { + for (i = 0; i < ifaces->len; ++i) { + int io; + ic = g_ptr_array_index (ifaces, i); + + /*Force the sharing of interface offsets between parent and subtypes.*/ + io = mono_class_interface_offset (k, ic); + g_assert (io >= 0); + interfaces_full [ic->interface_id] = ic; + interface_offsets_full [ic->interface_id] = io; + } + g_ptr_array_free (ifaces, TRUE); + } + } + + ifaces = mono_class_get_implemented_interfaces (class); if (ifaces) { for (i = 0; i < ifaces->len; ++i) { @@ -2549,30 +2595,11 @@ setup_interface_offsets (MonoClass *class, int cur_slot) continue; interfaces_full [ic->interface_id] = ic; interface_offsets_full [ic->interface_id] = cur_slot; - cur_slot += ic->method.count; + cur_slot += count_virtual_methods (ic); } g_ptr_array_free (ifaces, TRUE); } - for (k = class->parent; k ; k = k->parent) { - ifaces = mono_class_get_implemented_interfaces (k); - if (ifaces) { - for (i = 0; i < ifaces->len; ++i) { - ic = g_ptr_array_index (ifaces, i); - - if (interface_offsets_full [ic->interface_id] == -1) { - int io = mono_class_interface_offset (k, ic); - - g_assert (io >= 0); - - interfaces_full [ic->interface_id] = ic; - interface_offsets_full [ic->interface_id] = io; - } - } - g_ptr_array_free (ifaces, TRUE); - } - } - if (MONO_CLASS_IS_INTERFACE (class)) { interfaces_full [class->interface_id] = class; interface_offsets_full [class->interface_id] = cur_slot; @@ -2768,9 +2795,11 @@ mono_class_setup_vtable (MonoClass *class) #define DEBUG_INTERFACE_VTABLE_CODE 0 #define TRACE_INTERFACE_VTABLE_CODE 0 #define VERIFY_INTERFACE_VTABLE_CODE 0 +#define VTABLE_SELECTOR (1) #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE) #define DEBUG_INTERFACE_VTABLE(stmt) do {\ + if (!(VTABLE_SELECTOR)) break; \ stmt;\ } while (0) #else @@ -2779,6 +2808,7 @@ mono_class_setup_vtable (MonoClass *class) #if TRACE_INTERFACE_VTABLE_CODE #define TRACE_INTERFACE_VTABLE(stmt) do {\ + if (!(VTABLE_SELECTOR)) break; \ stmt;\ } while (0) #else @@ -2787,6 +2817,7 @@ mono_class_setup_vtable (MonoClass *class) #if VERIFY_INTERFACE_VTABLE_CODE #define VERIFY_INTERFACE_VTABLE(stmt) do {\ + if (!(VTABLE_SELECTOR)) break; \ stmt;\ } while (0) #else @@ -3074,10 +3105,9 @@ print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, Mono } static gboolean -verify_class_overrides (MonoClass *class, GPtrArray *ifaces, MonoMethod **overrides, int onum) +verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum) { int i; - gboolean found; for (i = 0; i < onum; ++i) { MonoMethod *decl = overrides [i * 2]; @@ -3097,38 +3127,14 @@ verify_class_overrides (MonoClass *class, GPtrArray *ifaces, MonoMethod **overri } if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) { - if (body->flags & METHOD_ATTRIBUTE_STATIC) - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type")); - else - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type")); - return FALSE; - } - - found = FALSE; - /*We can't use mono_class_is_assignable_from since it requires the class to be fully initialized*/ - if (ifaces) { - int j; - for (j = 0; j < ifaces->len; j++) { - MonoClass *ic = g_ptr_array_index (ifaces, j); - if (decl->klass == ic) { - found = TRUE; - break; - } - } - } - - if (!found) { - MonoClass *parent = class; - while (parent) { - if (decl->klass == parent) { - found = TRUE; - break; - } - parent = parent->parent; - } + if (body->flags & METHOD_ATTRIBUTE_STATIC) + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type")); + else + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type")); + return FALSE; } - if (!found) { + if (!mono_class_is_assignable_from_slow (decl->klass, class)) { mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type")); return FALSE; } @@ -3156,13 +3162,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o if (class->vtable) return; - ifaces = mono_class_get_implemented_interfaces (class); - - if (overrides && !verify_class_overrides (class, ifaces, overrides, onum)) { - if (ifaces) - g_ptr_array_free (ifaces, TRUE); + if (overrides && !verify_class_overrides (class, overrides, onum)) return; - } + + ifaces = mono_class_get_implemented_interfaces (class); if (ifaces) { for (i = 0; i < ifaces->len; i++) { @@ -3441,6 +3444,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o cm->slot = slot; } + /*Non final newslot methods must be given a non-interface vtable slot*/ + if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0) + cm->slot = -1; + if (cm->slot < 0) cm->slot = cur_slot++; @@ -3817,6 +3824,16 @@ mono_class_init (MonoClass *class) class->init_pending = 1; + if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) { + MonoClass *element_class = class->element_class; + if (!element_class->inited) + mono_class_init (element_class); + if (element_class->exception_type != MONO_EXCEPTION_NONE) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + goto fail; + } + } + /* CAS - SecurityAction.InheritanceDemand */ if (mono_is_security_manager_active () && class->parent && (class->parent->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) { mono_secman_inheritancedemand_class (class, class->parent); @@ -3918,8 +3935,10 @@ mono_class_init (MonoClass *class) class->has_cctor = gklass->has_cctor; mono_class_setup_vtable (gklass); - if (gklass->exception_type) + if (gklass->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); goto fail; + } class->vtable_size = gklass->vtable_size; } else { @@ -4007,12 +4026,20 @@ mono_class_init (MonoClass *class) if (class->parent) { /* This will compute class->parent->vtable_size for some classes */ mono_class_init (class->parent); - if (class->parent->exception_type || mono_loader_get_last_error ()) + if (class->parent->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + goto fail; + } + if (mono_loader_get_last_error ()) goto fail; if (!class->parent->vtable_size) { /* FIXME: Get rid of this somehow */ mono_class_setup_vtable (class->parent); - if (class->parent->exception_type || mono_loader_get_last_error ()) + if (class->parent->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + goto fail; + } + if (mono_loader_get_last_error ()) goto fail; } setup_interface_offsets (class, class->parent->vtable_size); @@ -5662,9 +5689,8 @@ mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *co if (!type) { char *name = mono_class_name_from_token (image, type_token); char *assembly = mono_assembly_name_from_token (image, type_token); - if (inflated) - mono_metadata_free_type (type); mono_loader_set_error_type_load (name, assembly); + return NULL; } if (inflated) { @@ -5809,7 +5835,7 @@ find_nocase (gpointer key, gpointer value, gpointer user_data) char *name = (char*)key; FindUserData *data = (FindUserData*)user_data; - if (!data->value && (g_strcasecmp (name, (char*)data->key) == 0)) + if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0)) data->value = value; } @@ -5878,7 +5904,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char continue; n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); - if (g_strcasecmp (n, name) == 0 && g_strcasecmp (nspace, name_space) == 0) + if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0) return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i); } return NULL; @@ -6229,6 +6255,67 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) return mono_class_has_parent (oklass, klass); } +/*Check if @candidate implements the interface @target*/ +static gboolean +mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate) +{ + int i; + + do { + if (candidate == target) + return TRUE; + + /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/ + if (candidate->image->dynamic && !candidate->wastypebuilder) { + MonoReflectionTypeBuilder *tb = candidate->reflection_info; + int j; + if (tb->interfaces) { + for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) { + MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j); + MonoClass *iface_class = mono_class_from_mono_type (iface->type); + if (iface_class == target || mono_class_implement_interface_slow (target, iface_class)) + return TRUE; + } + } + } else { + /*setup_interfaces don't mono_class_init anything*/ + mono_class_setup_interfaces (candidate); + for (i = 0; i < candidate->interface_count; ++i) { + if (candidate->interfaces [i] == target || mono_class_implement_interface_slow (target, candidate->interfaces [i])) + return TRUE; + } + } + candidate = candidate->parent; + } while (candidate); + + return FALSE; +} + +/* + * Check if @oklass can be assigned to @klass. + * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context. + */ +gboolean +mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate) +{ + if (candidate == target) + return TRUE; + if (target == mono_defaults.object_class) + return TRUE; + + /*setup_supertypes don't mono_class_init anything */ + mono_class_setup_supertypes (candidate); + mono_class_setup_supertypes (target); + + if (mono_class_has_parent (candidate, target)) + return TRUE; + + /*If target is not an interface there is no need to check them.*/ + if (!MONO_CLASS_IS_INTERFACE (target)) + return FALSE; + return mono_class_implement_interface_slow (target, candidate); +} + /** * mono_class_get_cctor: * @klass: A MonoClass pointer @@ -7706,6 +7793,10 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass) if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in)) return FALSE; + /*Non nested type with nested visibility. We just fail it.*/ + if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL) + return FALSE; + switch (access_level) { case TYPE_ATTRIBUTE_NOT_PUBLIC: return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);