#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_type_get_name:
* \param type a type
- *
* \returns The string representation for type as it would be represented in IL code.
*/
char*
return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
}
-/*
+/**
* mono_type_get_underlying_type:
- * @type: a type
- *
- * Returns: The MonoType for the underlying integer type if @type
+ * \param type a type
+ * \returns The \c MonoType for the underlying integer type if \p type
* is an enum and byref is false, otherwise the type itself.
*/
MonoType*
}
}
- mono_stats.inflated_type_count++;
+ UnlockedIncrement (&mono_stats.inflated_type_count);
return inflated;
}
-/*
+/**
* mono_class_inflate_generic_type:
- * @type: a type
- * @context: a generics context
+ * \param type a type
+ * \param context a generics context
+ * \deprecated Please use \c mono_class_inflate_generic_type_checked instead
*
- * If @type is a generic type and @context is not NULL, instantiate it using the
- * generics context @context.
+ * If \p type is a generic type and \p context is not NULL, instantiate it using the
+ * generics context \p context.
*
- * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
+ * \returns The instantiated type or a copy of \p type. The returned \c MonoType is allocated
* on the heap and is owned by the caller. Returns NULL on error.
- *
- * @deprecated Please use mono_class_inflate_generic_type_checked instead
*/
MonoType*
mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
if (!inflated)
return type;
- mono_stats.inflated_type_count++;
+ UnlockedIncrement (&mono_stats.inflated_type_count);
return inflated;
}
return res;
}
-/*
+/**
* mono_class_inflate_generic_method:
- * @method: a generic method
- * @context: a generics context
+ * \param method a generic method
+ * \param context a generics context
*
- * Instantiate the generic method @method using the generics context @context.
+ * Instantiate the generic method \p method using the generics context \p context.
*
- * Returns: The new instantiated method
+ * \returns The new instantiated method
*/
MonoMethod *
mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
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
*
g_assert (field->type);
}
+ if (!mono_type_get_underlying_type (field->type)) {
+ mono_class_set_type_load_failure (klass, "Field '%s' is an enum type with a bad underlying type", field->name);
+ break;
+ }
+
if (mono_field_is_deleted (field))
continue;
if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
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)) {
static gboolean disabled;
static gboolean inited = FALSE;
if (!inited) {
- disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
+ disabled = g_hasenv ("MONO_DISABLE_WCF_HACK");
inited = TRUE;
}
return disabled;
return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg);
}
+static int
+apply_override (MonoClass *klass, MonoMethod **vtable, MonoMethod *decl, MonoMethod *override)
+{
+ int dslot;
+ dslot = mono_method_get_vtable_slot (decl);
+ if (dslot == -1) {
+ mono_class_set_type_load_failure (klass, "");
+ return FALSE;
+ }
+
+ dslot += mono_class_interface_offset (klass, decl->klass);
+ vtable [dslot] = override;
+ if (!MONO_CLASS_IS_INTERFACE (override->klass)) {
+ /*
+ * If override from an interface, then it is an override of a default interface method,
+ * don't override its slot.
+ */
+ vtable [dslot]->slot = dslot;
+ }
+
+ if (mono_security_core_clr_enabled ())
+ mono_security_core_clr_check_override (klass, vtable [dslot], decl);
+
+ return TRUE;
+}
+
/*
* LOCKING: this is supposed to be called with the loader lock held.
*/
}
TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
+
+ /* Process overrides from interface default methods */
+ // FIXME: Ordering between interfaces
+ for (int ifindex = 0; ifindex < klass->interface_offsets_count; ifindex++) {
+ ic = klass->interfaces_packed [ifindex];
+
+ mono_class_setup_methods (ic);
+ if (mono_class_has_failure (ic))
+ goto fail;
+
+ MonoMethod **iface_overrides;
+ int iface_onum;
+ gboolean ok = mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic));
+ if (ok) {
+ for (int i = 0; i < iface_onum; i++) {
+ MonoMethod *decl = iface_overrides [i*2];
+ MonoMethod *override = iface_overrides [i*2 + 1];
+ if (!apply_override (klass, vtable, decl, override))
+ goto fail;
+
+ if (!override_map)
+ override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ g_hash_table_insert (override_map, decl, override);
+ }
+ g_free (iface_overrides);
+ }
+ }
+
/* override interface methods */
for (i = 0; i < onum; i++) {
MonoMethod *decl = overrides [i*2];
+ MonoMethod *override = overrides [i*2 + 1];
if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
- int dslot;
- dslot = mono_method_get_vtable_slot (decl);
- if (dslot == -1) {
- mono_class_set_type_load_failure (klass, "");
+ if (!apply_override (klass, vtable, decl, override))
goto fail;
- }
- dslot += mono_class_interface_offset (klass, decl->klass);
- vtable [dslot] = overrides [i*2 + 1];
- vtable [dslot]->slot = dslot;
if (!override_map)
override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
-
- g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
-
- if (mono_security_core_clr_enabled ())
- mono_security_core_clr_check_override (klass, vtable [dslot], decl);
+ g_hash_table_insert (override_map, decl, override);
}
}
+
TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
}
}
+
+ if (vtable [im_slot] == NULL) {
+ if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
+ TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im, 1)));
+ vtable [im_slot] = im;
+ }
+ }
} else {
g_assert (vtable [im_slot] == override_im);
}
/**
* mono_class_init:
- * \param klass: the class to initialize
+ * \param klass the class to initialize
*
- * Compute the instance_size, class_size and other infos that cannot be
- * computed at mono_class_get() time. Also compute vtable_size if possible.
- * Returns TRUE on success or FALSE if there was a problem in loading
- * the type (incorrect assemblies, missing assemblies, methods, etc).
- * Initializes the following fields in \param klass:
- * - all the fields initialized by mono_class_init_sizes ()
+ * Compute the \c instance_size, \c class_size and other infos that cannot be
+ * computed at \c mono_class_get time. Also compute vtable_size if possible.
+ * Initializes the following fields in \p klass:
+ * - all the fields initialized by \c mono_class_init_sizes
* - has_cctor
* - ghcimpl
* - inited
*
* LOCKING: Acquires the loader lock.
+ *
+ * \returns TRUE on success or FALSE if there was a problem in loading
+ * the type (incorrect assemblies, missing assemblies, methods, etc).
*/
gboolean
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);
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;
generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
context = &generic_container->context;
mono_class_set_generic_container (klass, generic_container);
+ MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
+ canonical_inst->type = MONO_TYPE_GENERICINST;
+ canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
enable_gclass_recording ();
}
/*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;
}
return mono_class_from_generic_parameter_internal (param);
}
+/**
+ * mono_ptr_class_get:
+ */
MonoClass *
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 */
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;
}
/**
* mono_class_from_mono_type:
* \param type describes the type to return
- *
- * \returns a MonoClass for the specified MonoType, the value is never NULL.
+ * \returns a \c MonoClass for the specified \c MonoType, the value is never NULL.
*/
MonoClass *
mono_class_from_mono_type (MonoType *type)
* \param element_class element class
* \param rank the dimension of the array class
* \param bounded whenever the array has non-zero bounds
- *
* \returns A class object describing the array with element type \p element_type and
* dimension \p rank.
*/
/* 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;
}
* mono_array_class_get:
* \param element_class element class
* \param rank the dimension of the array class
- *
* \returns A class object describing the array with element type \p element_type and
* dimension \p rank.
*/
/**
* mono_class_instance_size:
- * \param klass: a class
+ * \param klass a class
*
* Use to get the size of a class in bytes.
*
* \param class the class to lookup the field.
* \param field_token the field token
*
- * \returns A MonoClassField representing the type and offset of
+ * \returns A \c MonoClassField representing the type and offset of
* the field, or a NULL value if the field does not belong to this
* class.
*/
/**
* mono_class_get_field_from_name:
- * \param klass: the class to lookup the field.
- * \param name: the field name
+ * \param klass the class to lookup the field.
+ * \param name the field name
*
* Search the class \p klass and its parents for a field with the name \p name.
*
- * \returns The MonoClassField pointer of the named field or NULL
+ * \returns The \c MonoClassField pointer of the named field or NULL
*/
MonoClassField *
mono_class_get_field_from_name (MonoClass *klass, const char *name)
return (const char *)mono_metadata_blob_heap (klass->image, constant_cols [MONO_CONSTANT_VALUE]);
}
+/**
+ * mono_class_get_event_token:
+ */
guint32
mono_class_get_event_token (MonoEvent *event)
{
* \param name name of the property to lookup in the specified class
*
* Use this method to lookup a property in a class
- * \returns the MonoProperty with the given name, or NULL if the property
+ * \returns the \c MonoProperty with the given name, or NULL if the property
* does not exist on the \p klass.
*/
MonoProperty*
return 0;
}
+/**
+ * mono_class_name_from_token:
+ */
char *
mono_class_name_from_token (MonoImage *image, guint32 type_token)
{
* \param image the image where the class resides
* \param type_token the token for the class
* \param context the generic context used to evaluate generic instantiations in
- * \param deprecated Functions that expose MonoGenericContext are going away in mono 4.0
- *
- * \returns The MonoClass that represents \p type_token in \p image
+ * \deprecated Functions that expose \c MonoGenericContext are going away in mono 4.0
+ * \returns The \c MonoClass that represents \p type_token in \p image
*/
MonoClass *
mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
* mono_class_get:
* \param image image where the class token will be looked up.
* \param type_token a type token from the image
- *
- * \returns the MonoClass with the given \p type_token on the \p image
+ * \returns the \c MonoClass with the given \p type_token on the \p image
*/
MonoClass *
mono_class_get (MonoImage *image, guint32 type_token)
}
/*FIXME Only dynamic assemblies should allow this operation.*/
+/**
+ * mono_image_add_to_name_cache:
+ */
void
mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
const char *name, guint32 index)
* \param name the type short name.
* \deprecated use the mono_class_from_name_case_checked variant instead.
*
- * Obtains a MonoClass with a given namespace and a given name which
- * is located in the given MonoImage. The namespace and name
+ * Obtains a \c MonoClass with a given namespace and a given name which
+ * is located in the given \c MonoImage. The namespace and name
* lookups are case insensitive.
*/
MonoClass *
/**
* mono_class_from_name:
- * \param image The MonoImage where the type is looked up in
+ * \param image The \c MonoImage where the type is looked up in
* \param name_space the type namespace
* \param name the type short name.
*
- * Obtains a MonoClass with a given namespace and a given name which
- * is located in the given MonoImage.
+ * Obtains a \c MonoClass with a given namespace and a given name which
+ * is located in the given \c 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 {} }".
+ * For example use \c "Foo/Bar" to reference the class \c Bar that is nested
+ * inside \c Foo, like this: "class Foo { class Bar {} }".
*/
MonoClass *
mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
* this method return TRUE if the \p klass implements the interface or
* if \p klass is an interface, if one of its base classes is \p klass.
*
- * If \p check_interfaces is false then, then if \p klass is not an interface
- * then it returns TRUE if the \p klass is a subclass of \p klassc.
+ * If \p check_interfaces is false, then if \p klass is not an interface,
+ * it returns TRUE if the \p klass is a subclass of \p klassc.
*
- * if \p klass is an interface and \p klassc is System.Object, then this function
- * return true.
+ * if \p klass is an interface and \p klassc is \c System.Object, then this function
+ * returns TRUE.
*
*/
gboolean
* \param klass the class to be assigned to
* \param oklass the source class
*
- * \returns TRUE if an instance of object oklass can be assigned to an
- * instance of object \p klass
+ * \returns TRUE if an instance of class \p oklass can be assigned to an
+ * instance of class \p klass
*/
gboolean
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) {
/*
* mono_class_array_element_size:
* \param klass
*
- * \returns The number of bytes an element of type \p klass
- * uses when stored into an array.
+ * \returns The number of bytes an element of type \p klass uses when stored into an array.
*/
gint32
mono_class_array_element_size (MonoClass *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;
}
+/**
+ * mono_ldtoken:
+ */
gpointer
mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
MonoGenericContext *context)
/**
* mono_class_get_element_class:
- * \param klass the MonoClass to act on
+ * \param klass the \c MonoClass to act on
*
* Use this function to get the element class of an array.
*
* Use this method to determine if the provided \c MonoClass* represents a value type,
* or a reference type.
*
- * \returns TRUE if the MonoClass represents a ValueType, FALSE if it represents a reference type.
+ * \returns TRUE if the \c MonoClass represents a \c ValueType, FALSE if it represents a reference type.
*/
gboolean
mono_class_is_valuetype (MonoClass *klass)
/**
* mono_class_enum_basetype:
- * \param klass: the \c MonoClass to act on
+ * \param klass the \c MonoClass to act on
*
* Use this function to get the underlying type for an enumeration value.
*
* mono_class_get_type:
* \param klass the \c MonoClass to act on
*
- * This method returns the internal Type representation for the class.
+ * This method returns the internal \c MonoType representation for the class.
*
* \returns The \c MonoType from the class.
*/
*
* This routine is an iterator routine for retrieving the fields in a class.
*
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
* iterate over all of the elements. When no more values are
* available, the return value is NULL.
*
- * Returns: a \c MonoClassField* on each iteration, or NULL when no more fields are available.
+ * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
*/
MonoClassField*
mono_class_get_fields (MonoClass* klass, gpointer *iter)
}
/**
- * mono_class_get_methods
+ * mono_class_get_methods:
* \param klass the \c MonoClass to act on
*
* This routine is an iterator routine for retrieving the fields in a class.
*
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
* iterate over all of the elements. When no more values are
* available, the return value is NULL.
*
- * Returns: a MonoMethod on each iteration or NULL when no more methods are available.
+ * \returns a \c MonoMethod on each iteration or NULL when no more methods are available.
*/
MonoMethod*
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);
/*
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;
*
* This routine is an iterator routine for retrieving the properties in a class.
*
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
* iterate over all of the elements. When no more values are
* available, the return value is NULL.
*
*
* This routine is an iterator routine for retrieving the interfaces implemented by this class.
*
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
* iterate over all of the elements. When no more values are
* available, the return value is NULL.
*
- * \returns a \c Monoclass* on each invocation, or NULL when no more are available.
+ * \returns a \c MonoClass* on each invocation, or NULL when no more are available.
*/
MonoClass*
mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
* This routine is an iterator routine for retrieving the nested types of a class.
* This works only if \p klass is non-generic, or a generic type definition.
*
- * You must pass a gpointer that points to zero and is treated as an opaque handle to
+ * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
* iterate over all of the elements. When no more values are
* available, the return value is NULL.
*
/**
* mono_field_get_type:
* \param field the \c MonoClassField to act on
- *
* \returns \c MonoType of the field.
*/
MonoType*
/**
* mono_field_get_flags;
- * @field: the MonoClassField to act on
+ * \param field the \c MonoClassField to act on
*
* The metadata flags for a field are encoded using the
- * FIELD_ATTRIBUTE_* constants. See the tabledefs.h file for details.
+ * \c FIELD_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
*
- * Returns: The flags for the field.
+ * \returns The flags for the field.
*/
guint32
mono_field_get_flags (MonoClassField *field)
/**
* mono_property_get_name:
- * @prop: the MonoProperty to act on
- *
- * Returns: The name of the property
+ * \param prop the \c MonoProperty to act on
+ * \returns The name of the property
*/
const char*
mono_property_get_name (MonoProperty *prop)
/**
* mono_property_get_set_method
* \param prop the \c MonoProperty to act on.
- *
- * \returns The setter method of the property (A MonoMethod)
+ * \returns The setter method of the property, a \c MonoMethod.
*/
MonoMethod*
mono_property_get_set_method (MonoProperty *prop)
/**
* mono_property_get_get_method
* \param prop the MonoProperty to act on.
- *
- * \returns The setter method of the property (A \c MonoMethod)
+ * \returns The getter method of the property (A \c MonoMethod)
*/
MonoMethod*
mono_property_get_get_method (MonoProperty *prop)
/**
* mono_property_get_parent:
- * \param prop the MonoProperty to act on.
- *
+ * \param prop the \c MonoProperty to act on.
* \returns The \c MonoClass where the property was defined.
*/
MonoClass*
* \param prop the \c MonoProperty to act on.
*
* The metadata flags for a property are encoded using the
- * \c PROPERTY_ATTRIBUTE_* constants. See the tabledefs.h file for details.
+ * \c PROPERTY_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
*
* \returns The flags for the property.
*/
/**
* mono_event_get_name:
* \param event the MonoEvent to act on
- *
* \returns The name of the event.
*/
const char*
/**
* mono_event_get_add_method:
* \param event The \c MonoEvent to act on.
- *
- * \returns The \c add method for the event (a \c MonoMethod).
+ * \returns The \c add method for the event, a \c MonoMethod.
*/
MonoMethod*
mono_event_get_add_method (MonoEvent *event)
/**
* mono_event_get_remove_method:
* \param event The \c MonoEvent to act on.
- *
- * \returns The \c remove method for the event (a \c MonoMethod).
+ * \returns The \c remove method for the event, a \c MonoMethod.
*/
MonoMethod*
mono_event_get_remove_method (MonoEvent *event)
/**
* mono_event_get_raise_method:
* \param event The \c MonoEvent to act on.
- *
- * \returns The \c raise method for the event (a \c MonoMethod).
+ * \returns The \c raise method for the event, a \c MonoMethod.
*/
MonoMethod*
mono_event_get_raise_method (MonoEvent *event)
/**
* mono_event_get_parent:
- * @event: the MonoEvent to act on.
- *
- * Returns: The MonoClass where the event is defined.
+ * \param event the MonoEvent to act on.
+ * \returns The \c MonoClass where the event is defined.
*/
MonoClass*
mono_event_get_parent (MonoEvent *event)
/**
* mono_event_get_flags
- * @event: the MonoEvent to act on.
+ * \param event the \c MonoEvent to act on.
*
* The metadata flags for an event are encoded using the
- * EVENT_* constants. See the tabledefs.h file for details.
+ * \c EVENT_* constants. See the \c tabledefs.h file for details.
*
- * Returns: The flags for the event.
+ * \returns The flags for the event.
*/
guint32
mono_event_get_flags (MonoEvent *event)
/**
* mono_class_get_method_from_name:
- * @klass: where to look for the method
- * @name: name of the method
- * @param_count: number of parameters. -1 for any number.
+ * \param klass where to look for the method
+ * \param name name of the method
+ * \param param_count number of parameters. -1 for any number.
*
- * Obtains a MonoMethod with a given name and number of parameters.
+ * Obtains a \c MonoMethod with a given name and number of parameters.
* It only works if there are no multiple signatures for any given method name.
*/
MonoMethod *
/**
* mono_class_get_method_from_name_flags:
- * @klass: where to look for the method
- * @name_space: name of the method
- * @param_count: number of parameters. -1 for any number.
- * @flags: flags which must be set in the method
+ * \param klass where to look for the method
+ * \param name_space name of the method
+ * \param param_count number of parameters. -1 for any number.
+ * \param flags flags which must be set in the method
*
- * Obtains a MonoMethod with a given name and number of parameters.
+ * Obtains a \c MonoMethod with a given name and number of parameters.
* It only works if there are no multiple signatures for any given method name.
*/
MonoMethod *
/**
* mono_class_set_failure:
- * @klass: class in which the failure was detected
- * @ex_type: the kind of exception/error to be thrown (later)
- * @ex_data: exception data (specific to each type of exception/error)
+ * \param klass class in which the failure was detected
+ * \param ex_type the kind of exception/error to be thrown (later)
+ * \param ex_data exception data (specific to each type of exception/error)
*
* Keep a detected failure informations in the class for later processing.
* Note that only the first failure is kept.
/**
* mono_class_set_type_load_failure:
- * @klass: class in which the failure was detected
- * @fmt: Printf-style error message string.
+ * \param klass class in which the failure was detected
+ * \param fmt \c printf -style error message string.
*
* Collect detected failure informaion in the class for later processing.
- * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class ()
+ * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class()
* Note that only the first failure is kept.
*
- * Returns FALSE if a failure was already set on the class, or TRUE otherwise.
- *
* LOCKING: Acquires the loader lock.
+ *
+ * \returns FALSE if a failure was already set on the class, or TRUE otherwise.
*/
gboolean
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)
{
/**
* mono_class_get_exception_for_failure:
- * @klass: class in which the failure was detected
+ * \param klass class in which the failure was detected
*
- * Return a constructed MonoException than the caller can then throw
+ * \returns a constructed MonoException than the caller can then throw
* using mono_raise_exception - or NULL if no failure is present (or
* doesn't result in an exception).
*/
/* 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])
/**
* mono_method_can_access_field:
- * @method: Method that will attempt to access the field
- * @field: the field to access
+ * \param method Method that will attempt to access the field
+ * \param field the field to access
*
* Used to determine if a method is allowed to access the specified field.
*
- * Returns: TRUE if the given @method is allowed to access the @field while following
+ * \returns TRUE if the given \p method is allowed to access the \p field while following
* the accessibility rules of the CLI.
*/
gboolean
/**
* mono_method_can_access_method:
- * @method: Method that will attempt to access the other method
- * @called: the method that we want to probe for accessibility.
+ * \param method Method that will attempt to access the other method
+ * \param called the method that we want to probe for accessibility.
*
- * Used to determine if the @method is allowed to access the specified @called method.
+ * Used to determine if the \p method is allowed to access the specified \p called method.
*
- * Returns: TRUE if the given @method is allowed to invoke the @called while following
+ * \returns TRUE if the given \p method is allowed to invoke the \p called while following
* the accessibility rules of the CLI.
*/
gboolean
/**
* mono_type_is_valid_enum_basetype:
- * @type: The MonoType to check
- *
- * Returns: TRUE if the type can be used as the basetype of an enum
+ * \param type The MonoType to check
+ * \returns TRUE if the type can be used as the basetype of an enum
*/
gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
switch (type->type) {
/**
* mono_class_is_valid_enum:
- * @klass: An enum class to be validated
+ * \param klass An enum class to be validated
*
* This method verify the required properties an enum should have.
- *
- * Returns: TRUE if the informed enum class is valid
*
* FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
* FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
* FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
+ *
+ * \returns TRUE if the informed enum class is valid
*/
gboolean
mono_class_is_valid_enum (MonoClass *klass)
/**
* mono_class_get_fields_lazy:
- * @klass: the MonoClass to act on
+ * \param klass the MonoClass to act on
*
* This routine is an iterator routine for retrieving the fields in a class.
* Only minimal information about fields are loaded. Accessors must be used
* iterate over all of the elements. When no more values are
* available, the return value is NULL.
*
- * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
+ * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
*/
MonoClassField*
mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
/**
* mono_method_get_base_method:
- * @method: a method
- * @definition: if true, get the definition
- * @error: set on failure
+ * \param method a method
+ * \param definition if true, get the definition
+ * \param error set on failure
*
* Given a virtual method associated with a subclass, return the corresponding
- * method from an ancestor. If @definition is FALSE, returns the method in the
- * superclass of the given method. If @definition is TRUE, return the method
+ * method from an ancestor. If \p definition is FALSE, returns the method in the
+ * superclass of the given method. If \p definition is TRUE, return the method
* in the ancestor class where it was first declared. The type arguments will
* be inflated in the ancestor classes. If the method is not associated with a
* class, or isn't virtual, returns the method itself. On failure returns NULL
- * and sets @error.
+ * and sets \p error.
*/
MonoMethod*
mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error)