X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=b64c1086e039b0594608e7f2d1c64f9dbd82e47b;hb=17183a6fbf75a5ca960d7541676aea7fd7b09d21;hp=5479ca757f5b57933bd801171b7abfb8db300e30;hpb=46286930e77838bde181dff4d36ff01a10335b4d;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index 5479ca757f5..b64c1086e03 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -42,6 +42,8 @@ #include #include #include +#include + MonoStats mono_stats; gboolean mono_print_vtable = FALSE; @@ -69,7 +71,6 @@ static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL; -void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL; /* @@ -1426,6 +1427,52 @@ mono_class_setup_fields (MonoClass *class) MonoGenericContainer *container = NULL; MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL; + /* + * FIXME: We have a race condition here. It's possible that this function returns + * to its caller with `instance_size` set to `0` instead of the actual size. This + * is not a problem when the function is called recursively on the same class, + * because the size will be initialized by the outer invocation. What follows is a + * description of how it can occur in other cases, too. There it is a problem, + * because it can lead to the GC being asked to allocate an object of size `0`, + * which SGen chokes on. The race condition is triggered infrequently by + * `tests/sgen-suspend.cs`. + * + * This function is called for a class whenever one of its subclasses is inited. + * For example, it's called for every subclass of Object. What it does is this: + * + * if (class->setup_fields_called) + * return; + * ... + * class->instance_size = 0; + * ... + * class->setup_fields_called = 1; + * ... critical point + * class->instance_size = actual_instance_size; + * + * The last two steps are sometimes reversed, but that only changes the way in which + * the race condition works. + * + * Assume thread A goes through this function and makes it to the critical point. + * Now thread B runs the function and, since `setup_fields_called` is set, returns + * immediately, but `instance_size` is incorrect. + * + * The other case looks like this: + * + * if (class->setup_fields_called) + * return; + * ... critical point X + * class->instance_size = 0; + * ... critical point Y + * class->instance_size = actual_instance_size; + * ... + * class->setup_fields_called = 1; + * + * Assume thread A goes through the function and makes it to critical point X. Now + * thread B runs through the whole of the function, returning, assuming + * `instance_size` is set. At that point thread A gets to run and makes it to + * critical point Y, at which time `instance_size` is `0` again, invalidating thread + * B's assumption. + */ if (class->setup_fields_called) return; @@ -1503,6 +1550,7 @@ mono_class_setup_fields (MonoClass *class) mono_memory_barrier (); class->size_inited = 1; class->fields_inited = 1; + class->setup_fields_called = 1; return; } @@ -2120,9 +2168,6 @@ mono_class_setup_methods (MonoClass *class) class->methods = methods; - if (mono_debugger_class_loaded_methods_func) - mono_debugger_class_loaded_methods_func (class); - mono_loader_unlock (); } @@ -2645,7 +2690,7 @@ compare_interface_ids (const void *p_key, const void *p_element) { /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/ int mono_class_interface_offset (MonoClass *klass, MonoClass *itf) { - MonoClass **result = bsearch ( + MonoClass **result = mono_binary_search ( itf, klass->interfaces_packed, klass->interface_offsets_count, @@ -2874,9 +2919,12 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume * We collect the types needed to build the * instantiations in interfaces at intervals of 3/5, because 3/5 are * the generic interfaces needed to implement. + * + * On 4.5, as an optimization, we don't expand ref classes for the variant generic interfaces + * (IEnumerator, IReadOnlyList and IReadOnlyColleciton). The regular dispatch code can handle those cases. */ - nifaces = generic_ireadonlylist_class ? 5 : 3; if (eclass->valuetype) { + nifaces = generic_ireadonlylist_class ? 5 : 3; fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank); /* IList, ICollection, IEnumerable, IReadOnlyList`1 */ @@ -2898,6 +2946,7 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume int idepth = eclass->idepth; if (!internal_enumerator) idepth--; + nifaces = generic_ireadonlylist_class ? 2 : 3; // FIXME: This doesn't seem to work/required for generic params if (!(eclass->this_arg.type == MONO_TYPE_VAR || eclass->this_arg.type == MONO_TYPE_MVAR || (eclass->image->dynamic && !eclass->wastypebuilder))) @@ -2961,10 +3010,16 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume 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 (generic_ireadonlylist_class) { - interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface); - interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface); + + if (eclass->valuetype) { + interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface); + if (generic_ireadonlylist_class) { + interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface); + interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface); + } + } else { + if (!generic_ireadonlylist_class) + interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface); } } if (internal_enumerator) { @@ -3558,10 +3613,6 @@ mono_class_setup_vtable_full (MonoClass *class, GList *in_setup) if (class->vtable) return; - if (mono_debug_using_mono_debugger ()) - /* The debugger currently depends on this */ - mono_class_setup_methods (class); - if (MONO_CLASS_IS_INTERFACE (class)) { /* This sets method->slot for all methods if this is an interface */ mono_class_setup_methods (class); @@ -5311,7 +5362,7 @@ mono_class_setup_mono_type (MonoClass *class) #ifndef DISABLE_COM /* - * COM initialization (using mono_init_com_types) is delayed until needed. + * COM initialization is delayed until needed. * However when a [ComImport] attribute is present on a type it will trigger * the initialization. This is not a problem unless the BCL being executed * lacks the types that COM depends on (e.g. Variant on Silverlight). @@ -5332,7 +5383,6 @@ init_com_from_comimport (MonoClass *class) } /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */ - mono_init_com_types (); } #endif /*DISABLE_COM*/ @@ -5365,7 +5415,7 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) if (MONO_CLASS_IS_IMPORT (class)) { init_com_from_comimport (class); if (parent == mono_defaults.object_class) - parent = mono_defaults.com_object_class; + parent = mono_class_get_com_object_class (); } #endif if (!parent) { @@ -5436,7 +5486,7 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) * - supertypes: array of classes: each element has a class in the hierarchy * starting from @class up to System.Object * - * LOCKING: this assumes the loader lock is held + * LOCKING: This function is atomic, in case of contention we waste memory. */ void mono_class_setup_supertypes (MonoClass *class) @@ -5444,7 +5494,8 @@ mono_class_setup_supertypes (MonoClass *class) int ms; MonoClass **supertypes; - if (class->supertypes) + mono_atomic_load_acquire (supertypes, void*, &class->supertypes); + if (supertypes) return; if (class->parent && !class->parent->supertypes) @@ -5648,10 +5699,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError if (!class->enumtype) { if (!mono_metadata_interfaces_from_typedef_full ( image, type_token, &interfaces, &icount, FALSE, context)){ - mono_class_set_failure_and_error (class, error, g_strdup ("Could not load interfaces")); + mono_class_set_failure_from_loader_error (class, error, g_strdup ("Could not load interfaces")); mono_loader_unlock (); mono_profiler_class_loaded (class, MONO_PROFILE_FAILED); - g_assert (!mono_loader_get_last_error ()); return NULL; } @@ -6590,6 +6640,9 @@ mono_class_data_size (MonoClass *klass) { if (!klass->inited) mono_class_init (klass); + /* This can happen with dynamically created types */ + if (!klass->fields_inited) + mono_class_setup_fields_locking (klass); /* in arrays, sizes.class_size is unioned with element_size * and arrays have no static fields @@ -7399,7 +7452,11 @@ search_modules (MonoImage *image, const char *name_space, const char *name) * @name: the type short name. * * Obtains a MonoClass with a given namespace and a given name which - * is located in the given MonoImage. + * is located in the given MonoImage. + * + * To reference nested classes, use the "/" character as a separator. + * For example use "Foo/Bar" to reference the class Bar that is nested + * inside Foo, like this: "class Foo { class Bar {} }". */ MonoClass * mono_class_from_name (MonoImage *image, const char* name_space, const char *name) @@ -7511,11 +7568,31 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name return class; } -/*FIXME test for interfaces with variant generic arguments*/ +/** + * mono_class_is_subclass_of: + * @klass: class to probe if it is a subclass of another one + * @klassc: the class we suspect is the base class + * @check_interfaces: whether we should perform interface checks + * + * This method determines whether @klass is a subclass of @klassc. + * + * If the @check_interfaces flag is set, then if @klassc is an interface + * this method return true if the @klass implements the interface or + * if @klass is an interface, if one of its base classes is @klass. + * + * If @check_interfaces is false then, then if @klass is not an interface + * then it returns true if the @klass is a subclass of @klassc. + * + * if @klass is an interface and @klassc is System.Object, then this function + * return true. + * + */ gboolean mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc, gboolean check_interfaces) { +/*FIXME test for interfaces with variant generic arguments*/ + if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) { if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id)) return TRUE; @@ -8583,7 +8660,7 @@ 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 (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) { if (!*iter) { mono_class_setup_methods (klass); /* @@ -8830,6 +8907,32 @@ mono_class_get_nested_types (MonoClass* klass, gpointer *iter) return NULL; } + +/** + * mono_class_is_delegate + * @klass: the MonoClass to act on + * + * Returns: true if the MonoClass represents a System.Delegate. + */ +mono_bool +mono_class_is_delegate (MonoClass *klass) +{ + return klass->delegate; +} + +/** + * mono_class_implements_interface + * @klass: The MonoClass to act on + * @interface: The interface to check if @klass implements. + * + * Returns: true if @klass implements @interface. + */ +mono_bool +mono_class_implements_interface (MonoClass* klass, MonoClass* iface) +{ + return mono_class_is_assignable_from (iface, klass); +} + /** * mono_field_get_name: * @field: the MonoClassField to act on