[runtime] Synthesize IList and IReadOnlyList for the element type of enum errays...
[mono.git] / mono / metadata / class.c
index 648442e8058444418b6c902c80801e82a4917105..da8fc30585b67fb1fa23f44a182cb0ae2ea3ce3f 100644 (file)
@@ -46,6 +46,7 @@
 #include <mono/utils/mono-logger-internals.h>
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/atomic.h>
+#include <mono/utils/unlocked.h>
 #include <mono/utils/bsearch.h>
 #include <mono/utils/checked-build.h>
 
@@ -55,9 +56,9 @@ gboolean mono_print_vtable = FALSE;
 gboolean mono_align_small_structs = FALSE;
 
 /* Statistics */
-guint32 inflated_classes_size, inflated_methods_size;
-guint32 classes_size, class_ext_size, class_ext_count;
-guint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
+gint32 inflated_classes_size, inflated_methods_size;
+gint32 classes_size;
+gint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
 
 /* Low level lock which protects data structures in this module */
 static mono_mutex_t classes_mutex;
@@ -864,7 +865,7 @@ mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type,
                }
        }
 
-       mono_stats.inflated_type_count++;
+       UnlockedIncrement (&mono_stats.inflated_type_count);
        return inflated;
 }
 
@@ -928,7 +929,7 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG
        if (!inflated)
                return type;
 
-       mono_stats.inflated_type_count++;
+       UnlockedIncrement (&mono_stats.inflated_type_count);
        return inflated;
 }
 
@@ -1089,9 +1090,9 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
                return (MonoMethod*)cached;
        }
 
-       mono_stats.inflated_method_count++;
+       UnlockedIncrement (&mono_stats.inflated_method_count);
 
-       inflated_methods_size += sizeof (MonoMethodInflated);
+       UnlockedAdd (&inflated_methods_size,  sizeof (MonoMethodInflated));
 
        sig = mono_method_signature (method);
        if (!sig) {
@@ -1512,6 +1513,7 @@ mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoCla
  * Sets the following fields in \p klass:
  *  - all the fields initialized by mono_class_init_sizes ()
  *  - element_class/cast_class (for enums)
+ *  - sizes:element_size (for arrays)
  *  - field->type/offset for all fields
  *  - fields_inited
  *
@@ -1631,8 +1633,7 @@ mono_class_setup_fields (MonoClass *klass)
                        char *class_name = mono_type_get_full_name (klass);
                        char *type_name = mono_type_full_name (field->type);
 
-                       mono_class_set_type_load_failure (klass, "");
-                       g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
+                       mono_class_set_type_load_failure (klass, "Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
                        g_free (class_name);
                        g_free (type_name);
                        break;
@@ -1772,6 +1773,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
        MonoClassField *field;
        gboolean blittable;
        int instance_size = base_instance_size;
+       int element_size = -1;
        int class_size, min_align;
        int *field_offsets;
        gboolean *fields_has_references;
@@ -2101,6 +2103,9 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
        else if (klass->byval_arg.type == MONO_TYPE_PTR)
                instance_size = sizeof (MonoObject) + sizeof (gpointer);
 
+       if (klass->byval_arg.type == MONO_TYPE_SZARRAY || klass->byval_arg.type == MONO_TYPE_ARRAY)
+               element_size = mono_class_array_element_size (klass->element_class);
+
        /* Publish the data */
        mono_loader_lock ();
        if (klass->instance_size && !klass->image->dynamic) {
@@ -2131,6 +2136,9 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
                        klass->fields [i].offset = field_offsets [i];
        }
 
+       if (klass->byval_arg.type == MONO_TYPE_SZARRAY || klass->byval_arg.type == MONO_TYPE_ARRAY)
+               klass->sizes.element_size = element_size;
+
        mono_memory_barrier ();
        klass->size_inited = 1;
        mono_loader_unlock ();
@@ -2918,6 +2926,10 @@ collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, GHashTabl
                        *ifaces = g_hash_table_new (NULL, NULL);
                if (g_hash_table_lookup (*ifaces, ic))
                        continue;
+               /* A gparam is not an implemented interface for the purposes of
+                * mono_class_get_implemented_interfaces */
+               if (mono_class_is_gparam (ic))
+                       continue;
                g_ptr_array_add (*res, ic);
                g_hash_table_insert (*ifaces, ic, ic);
                mono_class_init (ic);
@@ -3308,7 +3320,9 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                for (i = 0; i < k->interface_count; i++) {
                        ic = k->interfaces [i];
 
-                       mono_class_init (ic);
+                       /* A gparam does not have any interface_id set. */
+                       if (! mono_class_is_gparam (ic))
+                               mono_class_init (ic);
 
                        if (max_iid < ic->interface_id)
                                max_iid = ic->interface_id;
@@ -3569,7 +3583,7 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
                return;
        }
 
-       mono_stats.generic_vtable_count ++;
+       UnlockedIncrement (&mono_stats.generic_vtable_count);
        in_setup = g_list_prepend (in_setup, klass);
 
        if (mono_class_is_ginst (klass)) {
@@ -4880,7 +4894,7 @@ mono_class_init (MonoClass *klass)
        GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
        if (g_slist_find (init_list, klass)) {
                mono_class_set_type_load_failure (klass, "Recursive type definition detected");
-               goto leave;
+               goto leave_no_init_pending;
        }
        init_list = g_slist_prepend (init_list, klass);
        mono_native_tls_set_value (init_pending_tls_id, init_list);
@@ -4903,7 +4917,7 @@ mono_class_init (MonoClass *klass)
                        goto leave;
        }
 
-       mono_stats.initialized_class_count++;
+       UnlockedIncrement (&mono_stats.initialized_class_count);
 
        if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
                MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
@@ -4941,12 +4955,19 @@ mono_class_init (MonoClass *klass)
                ghcimpl = cached_info.ghcimpl;
                has_cctor = cached_info.has_cctor;
        } else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
-               /* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
+               /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
                 * The first slot if for array with.
                 */
-               static int szarray_vtable_size[2] = { 0 };
+               static int szarray_vtable_size[3] = { 0 };
 
-               int slot = MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg) ? 0 : 1;
+               int slot;
+
+               if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg))
+                       slot = 0;
+               else if (klass->element_class->enumtype)
+                       slot = 1;
+               else
+                       slot = 2;
 
                /* SZARRAY case */
                if (!szarray_vtable_size [slot]) {
@@ -5048,10 +5069,10 @@ mono_class_init (MonoClass *klass)
                return !mono_class_has_failure (klass);
        }
 
-       mono_stats.initialized_class_count++;
+       UnlockedIncrement (&mono_stats.initialized_class_count);
 
        if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
-               mono_stats.generic_class_count++;
+               UnlockedIncrement (&mono_stats.generic_class_count);
 
        if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
                klass->nested_classes_inited = TRUE;
@@ -5079,10 +5100,12 @@ mono_class_init (MonoClass *klass)
 
        goto leave;
 
- leave:
+leave:
+       init_list = mono_native_tls_get_value (init_pending_tls_id);
        init_list = g_slist_remove (init_list, klass);
        mono_native_tls_set_value (init_pending_tls_id, init_list);
 
+leave_no_init_pending:
        if (locked)
                mono_loader_unlock ();
 
@@ -5511,7 +5534,7 @@ mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char
  * Create the MonoClass* representing the specified type token.
  * \p type_token must be a TypeDef token.
  *
- * FIXME: don't return NULL on failure, just the the caller figure it out.
+ * FIXME: don't return NULL on failure, just let the caller figure it out.
  */
 static MonoClass *
 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
@@ -5550,19 +5573,19 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        if (mono_metadata_has_generic_params (image, type_token)) {
                klass = mono_image_alloc0 (image, sizeof (MonoClassGtd));
                klass->class_kind = MONO_CLASS_GTD;
-               classes_size += sizeof (MonoClassGtd);
+               UnlockedAdd (&classes_size, sizeof (MonoClassGtd));
                ++class_gtd_count;
        } else {
                klass = mono_image_alloc0 (image, sizeof (MonoClassDef));
                klass->class_kind = MONO_CLASS_DEF;
-               classes_size += sizeof (MonoClassDef);
+               UnlockedAdd (&classes_size, sizeof (MonoClassDef));
                ++class_def_count;
        }
 
        klass->name = name;
        klass->name_space = nspace;
 
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (klass));
 
        klass->image = image;
        klass->type_token = type_token;
@@ -5636,7 +5659,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                        /*FIXME implement a mono_class_set_failure_from_mono_error */
                        mono_class_set_type_load_failure (klass, "%s",  mono_error_get_message (error));
                        mono_loader_unlock ();
-                       mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
+                       MONO_PROFILER_RAISE (class_failed, (klass));
                        return NULL;
                }
        }
@@ -5693,7 +5716,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 
                        mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        mono_loader_unlock ();
-                       mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
+                       MONO_PROFILER_RAISE (class_failed, (klass));
                        return NULL;
                }
 
@@ -5743,7 +5766,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                        klass->cast_class = klass->element_class = mono_defaults.int32_class;
                        mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        mono_loader_unlock ();
-                       mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
+                       MONO_PROFILER_RAISE (class_failed, (klass));
                        return NULL;
                }
                klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype);
@@ -5757,7 +5780,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
                mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
                mono_loader_unlock ();
-               mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
+               MONO_PROFILER_RAISE (class_failed, (klass));
                return NULL;
        }
 
@@ -5771,7 +5794,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 
        mono_loader_unlock ();
 
-       mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (klass));
 
        return klass;
 
@@ -5781,7 +5804,7 @@ parent_failure:
 
        mono_class_setup_mono_type (klass);
        mono_loader_unlock ();
-       mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
+       MONO_PROFILER_RAISE (class_failed, (klass));
        return NULL;
 }
 
@@ -5918,7 +5941,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        if (mono_class_is_nullable (klass))
                klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
 
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (klass));
 
        mono_generic_class_setup_parent (klass, gklass);
 
@@ -5928,7 +5951,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        mono_memory_barrier ();
        gclass->cached_class = klass;
 
-       mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (klass));
 
        ++class_ginst_count;
        inflated_classes_size += sizeof (MonoClassGenericInst);
@@ -5994,8 +6017,8 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
 
        klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
        klass->class_kind = MONO_CLASS_GPARAM;
-       classes_size += sizeof (MonoClassGenericParam);
-       ++class_gparam_count;
+       UnlockedAdd (&classes_size, sizeof (MonoClassGenericParam));
+       UnlockedIncrement (&class_gparam_count);
 
        if (pinfo) {
                CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
@@ -6014,7 +6037,7 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
                CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
        }
 
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (klass));
 
        // Count non-NULL items in pinfo->constraints
        count = 0;
@@ -6230,9 +6253,9 @@ mono_class_from_generic_parameter_internal (MonoGenericParam *param)
 
        /* FIXME: Should this go inside 'make_generic_param_klass'? */
        if (klass2)
-               mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED); // Alert profiler about botched class create
+               MONO_PROFILER_RAISE (class_failed, (klass2));
        else
-               mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+               MONO_PROFILER_RAISE (class_loaded, (klass));
 
        return klass;
 }
@@ -6274,7 +6297,7 @@ mono_ptr_class_get (MonoType *type)
        
        result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
 
-       classes_size += sizeof (MonoClassPointer);
+       UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
        ++class_pointer_count;
 
        result->parent = NULL; /* no parent for PTR types */
@@ -6284,7 +6307,7 @@ mono_ptr_class_get (MonoType *type)
        result->class_kind = MONO_CLASS_POINTER;
        g_free (name);
 
-       mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (result));
 
        result->image = el_class->image;
        result->inited = TRUE;
@@ -6304,7 +6327,7 @@ mono_ptr_class_get (MonoType *type)
                MonoClass *result2;
                if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
                        mono_image_unlock (image);
-                       mono_profiler_class_loaded (result, MONO_PROFILE_FAILED);
+                       MONO_PROFILER_RAISE (class_failed, (result));
                        return result2;
                }
        } else {
@@ -6313,7 +6336,7 @@ mono_ptr_class_get (MonoType *type)
        g_hash_table_insert (image->ptr_cache, el_class, result);
        mono_image_unlock (image);
 
-       mono_profiler_class_loaded (result, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (result));
 
        return result;
 }
@@ -6362,16 +6385,16 @@ mono_fnptr_class_get (MonoMethodSignature *sig)
                return cached;
        }
 
-       mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (result));
 
-       classes_size += sizeof (MonoClassPointer);
+       UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
        ++class_pointer_count;
 
        g_hash_table_insert (ptr_hash, sig, result);
 
        mono_loader_unlock ();
 
-       mono_profiler_class_loaded (result, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (result));
 
        return result;
 }
@@ -6596,7 +6619,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
                /* element_size -1 is ok as this is not an instantitable type*/
                klass->sizes.element_size = -1;
        } else
-               klass->sizes.element_size = mono_class_array_element_size (eclass);
+               klass->sizes.element_size = -1;
 
        mono_class_setup_supertypes (klass);
 
@@ -6690,9 +6713,9 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
                return cached;
        }
 
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (klass));
 
-       classes_size += sizeof (MonoClassArray);
+       UnlockedAdd (&classes_size, sizeof (MonoClassArray));
        ++class_array_count;
 
        if (rank == 1 && !bounded) {
@@ -6706,7 +6729,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        mono_loader_unlock ();
 
-       mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (klass));
 
        return klass;
 }
@@ -8210,22 +8233,31 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                return mono_gparam_is_assignable_from (klass, oklass);
        }
 
-       if (MONO_CLASS_IS_INTERFACE (klass)) {
-               if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
-                       MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
-                       MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
-                       int i;
+       /* This can happen if oklass is a tyvar that has a constraint which is another tyvar which in turn
+        * has a constraint which is a class type:
+        *
+        *  class Foo { }
+        *  class G<T1, T2> where T1 : T2 where T2 : Foo { }
+        *
+        * In this case, Foo is assignable from T1.
+        */
+       if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
+               MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
+               MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
+               int i;
 
-                       if (constraints) {
-                               for (i = 0; constraints [i]; ++i) {
-                                       if (mono_class_is_assignable_from (klass, constraints [i]))
-                                               return TRUE;
-                               }
+               if (constraints) {
+                       for (i = 0; constraints [i]; ++i) {
+                               if (mono_class_is_assignable_from (klass, constraints [i]))
+                                       return TRUE;
                        }
-
-                       return FALSE;
                }
 
+               return mono_class_has_parent (oklass, klass);
+       }
+
+       if (MONO_CLASS_IS_INTERFACE (klass)) {
+
                /* interface_offsets might not be set for dynamic classes */
                if (mono_class_get_ref_info_handle (oklass) && !oklass->interface_bitmap) {
                        /* 
@@ -8634,11 +8666,16 @@ handle_enum:
  * \param ac pointer to a \c MonoArrayClass
  *
  * \returns The size of single array element.
+ *
+ * LOCKING: Acquires the loader lock.
  */
 gint32
 mono_array_element_size (MonoClass *ac)
 {
        g_assert (ac->rank);
+       if (G_UNLIKELY (!ac->size_inited)) {
+               mono_class_setup_fields (ac);
+       }
        return ac->sizes.element_size;
 }
 
@@ -9107,10 +9144,25 @@ mono_class_get_methods (MonoClass* klass, gpointer *iter)
 static MonoMethod*
 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
 {
-       MonoMethod** method;
+       gboolean static_iter = FALSE;
+
        if (!iter)
                return NULL;
-       if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
+
+       /*
+        * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
+        * and the upper bits contain an index. Otherwise, the iterator is a pointer into
+        * klass->methods.
+        */
+       if ((gsize)(*iter) & 1)
+               static_iter = TRUE;
+       /* Use the static metadata only if klass->methods is not yet initialized */
+       if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)))
+               static_iter = TRUE;
+
+       if (!static_iter) {
+               MonoMethod** methodptr;
+
                if (!*iter) {
                        mono_class_setup_methods (klass);
                        /*
@@ -9120,20 +9172,22 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                        if (!klass->methods)
                                return NULL;
                        /* start from the first */
-                       method = &klass->methods [0];
+                       methodptr = &klass->methods [0];
                } else {
-                       method = (MonoMethod **)*iter;
-                       method++;
+                       methodptr = (MonoMethod **)*iter;
+                       methodptr++;
                }
+               if (*iter)
+                       g_assert ((guint64)(*iter) > 0x100);
                int mcount = mono_class_get_method_count (klass);
-               while (method < &klass->methods [mcount]) {
-                       if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
+               while (methodptr < &klass->methods [mcount]) {
+                       if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL))
                                break;
-                       method ++;
+                       methodptr ++;
                }
-               if (method < &klass->methods [mcount]) {
-                       *iter = method;
-                       return *method;
+               if (methodptr < &klass->methods [mcount]) {
+                       *iter = methodptr;
+                       return *methodptr;
                } else {
                        return NULL;
                }
@@ -9145,7 +9199,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                if (!*iter) {
                        start_index = 0;
                } else {
-                       start_index = GPOINTER_TO_UINT (*iter);
+                       start_index = GPOINTER_TO_UINT (*iter) >> 1;
                }
 
                int first_idx = mono_class_get_first_method_idx (klass);
@@ -9166,7 +9220,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                        mono_error_cleanup (&error); /* FIXME don't swallow the error */
 
                        /* Add 1 here so the if (*iter) check fails */
-                       *iter = GUINT_TO_POINTER (i + 1);
+                       *iter  = GUINT_TO_POINTER (((i + 1) << 1) | 1);
                        return res;
                } else {
                        return NULL;
@@ -9876,7 +9930,9 @@ mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
  * mono_classes_init:
  *
  * Initialize the resources used by this module.
+ * Known racy counters: `class_gparam_count`, `classes_size` and `inflated_methods_size`
  */
+MONO_NO_SANITIZE_THREAD
 void
 mono_classes_init (void)
 {
@@ -10033,7 +10089,7 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
                /* Be conservative with checks */
                if (!friend_->name)
                        continue;
-               if (strcmp (accessing->aname.name, friend_->name))
+               if (g_ascii_strcasecmp (accessing->aname.name, friend_->name))
                        continue;
                if (friend_->public_key_token [0]) {
                        if (!accessing->aname.public_key_token [0])
@@ -10491,8 +10547,8 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
        if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
                MonoType *args [1];
 
-               /* generic IList, ICollection, IEnumerable */
-               interface_count = 2;
+               /* IList and IReadOnlyList -> 2x if enum*/
+               interface_count = klass->element_class->enumtype ? 4 : 2;
                interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
 
                args [0] = &klass->element_class->byval_arg;
@@ -10500,6 +10556,13 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
                        mono_defaults.generic_ilist_class, 1, args, FALSE);
                interfaces [1] = mono_class_bind_generic_parameters (
                           mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
+               if (klass->element_class->enumtype) {
+                       args [0] = mono_class_enum_basetype (klass->element_class);
+                       interfaces [2] = mono_class_bind_generic_parameters (
+                               mono_defaults.generic_ilist_class, 1, args, FALSE);
+                       interfaces [3] = mono_class_bind_generic_parameters (
+                                  mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
+               }
        } else if (mono_class_is_ginst (klass)) {
                MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;