Merge branch 'master' into msbuilddll2
[mono.git] / mono / metadata / class.c
index 5479ca757f5b57933bd801171b7abfb8db300e30..b64c1086e039b0594608e7f2d1c64f9dbd82e47b 100644 (file)
@@ -42,6 +42,8 @@
 #include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/atomic.h>
+#include <mono/utils/bsearch.h>
+
 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