#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>
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;
}
}
- mono_stats.inflated_type_count++;
+ UnlockedIncrement (&mono_stats.inflated_type_count);
return inflated;
}
if (!inflated)
return type;
- mono_stats.inflated_type_count++;
+ UnlockedIncrement (&mono_stats.inflated_type_count);
return inflated;
}
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) {
* 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
*
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;
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;
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) {
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 ();
*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);
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;
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)) {
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);
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;
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;
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 ();
* 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)
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;
/*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;
}
}
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_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);
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;
}
mono_loader_unlock ();
- mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+ MONO_PROFILER_RAISE (class_loaded, (klass));
return klass;
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;
}
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);
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);
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 );
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;
/* 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;
}
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 */
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;
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 {
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;
}
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;
}
/* 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);
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) {
mono_loader_unlock ();
- mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+ MONO_PROFILER_RAISE (class_loaded, (klass));
return klass;
}
* \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;
}
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);
/*
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;
}
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);
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;
* 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)
{
/* 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])