*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
*/
#include <config.h>
#ifdef HAVE_ALLOCA_H
#include <mono/utils/mono-string.h>
#include <mono/utils/mono-error-internals.h>
#include <mono/utils/mono-logger-internal.h>
+#include <mono/utils/mono-memory-model.h>
MonoStats mono_stats;
gboolean mono_print_vtable = FALSE;
static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
-static gboolean mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass);
static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
static guint32 mono_field_resolve_flags (MonoClassField *field);
static void mono_class_setup_vtable_full (MonoClass *class, GList *in_setup);
method = imethod->declaring;
}
- if (!method->is_generic && !method->klass->generic_container)
+ /*
+ * A method only needs to be inflated if the context has argument for which it is
+ * parametric. Eg:
+ *
+ * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
+ * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
+ *
+ */
+ if (!((method->is_generic && context->method_inst) ||
+ (method->klass->generic_container && context->class_inst)))
return method;
/*
explicit_size = mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size);
if (explicit_size) {
- g_assert ((packing_size & 0xfffffff0) == 0);
+ if ((packing_size & 0xfffffff0) != 0) {
+ char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 16", class->name, packing_size);
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+ return;
+ }
class->packing_size = packing_size;
real_size += class->instance_size;
}
}
class->size_inited = 1;
class->blittable = blittable;
+ mono_memory_barrier ();
+ class->fields_inited = 1;
return;
}
/*valuetypes can't be neither bigger than 1Mb or empty. */
if (class->valuetype && (class->instance_size <= 0 || class->instance_size > (0x100000 + sizeof (MonoObject))))
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+
+ mono_memory_barrier ();
+ class->fields_inited = 1;
}
/**
* Initializes the class->fields array of fields.
* Aquires the loader lock.
*/
-static void
+void
mono_class_setup_fields_locking (MonoClass *class)
{
+ /* This can be checked without locks */
+ if (class->fields_inited)
+ return;
mono_loader_lock ();
mono_class_setup_fields (class);
mono_loader_unlock ();
*/
/* corlib is missing [StructLayout] directives in many places */
if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
- if (class->image != mono_defaults.corlib &&
- class->byval_arg.type != MONO_TYPE_VALUETYPE)
+ if (class->byval_arg.type != MONO_TYPE_VALUETYPE)
gc_aware_layout = TRUE;
- /* from System.dll, used in metadata/process.h */
- if (strcmp (class->name, "ProcessStartInfo") == 0)
- gc_aware_layout = FALSE;
}
/* Compute klass->has_references */
continue;
size = mono_type_size (field->type, &align);
+ align = class->packing_size ? MIN (class->packing_size, align): align;
class->min_align = MAX (align, class->min_align);
/*
real_size = MAX (real_size, size + field->offset);
}
class->instance_size = MAX (real_size, class->instance_size);
+ if (class->instance_size & (class->min_align - 1)) {
+ class->instance_size += class->min_align - 1;
+ class->instance_size &= ~(class->min_align - 1);
+ }
break;
}
void
mono_unload_interface_id (MonoClass *class)
{
- if (class->interface_id) {
+ if (global_interface_bitset && class->interface_id) {
mono_loader_lock ();
mono_bitset_clear (global_interface_bitset, class->interface_id);
mono_loader_unlock ();
return -1;
for (i = 0; i < klass->interface_offsets_count; i++) {
- if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i])) {
+ if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i], FALSE)) {
*non_exact_match = TRUE;
return klass->interface_offsets_packed [i];
}
*/
eclass = mono_class_from_mono_type (class->generic_class->context.class_inst->type_argv [0]);
original_rank = eclass->rank;
- eclass = eclass->element_class;
+ if (!eclass->rank)
+ eclass = eclass->element_class;
internal_enumerator = TRUE;
*is_enumerator = TRUE;
} else {
* Return -1 on failure and set exception_type
*/
static int
-setup_interface_offsets (MonoClass *class, int cur_slot)
+setup_interface_offsets (MonoClass *class, int cur_slot, gboolean overwrite)
{
MonoError error;
MonoClass *k, *ic;
}
/*
- * We might get called twice: once from mono_class_init () then once from
- * mono_class_setup_vtable ().
+ * We might get called multiple times:
+ * - mono_class_init ()
+ * - mono_class_setup_vtable ().
+ * - mono_class_setup_interface_offsets ().
+ * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
+ * means we have to overwrite those when called from other places (#4440).
*/
- if (class->interfaces_packed) {
+ if (class->interfaces_packed && !overwrite) {
g_assert (class->interface_offsets_count == interface_offsets_count);
} else {
uint8_t *bitmap;
{
mono_loader_lock ();
- setup_interface_offsets (class, 0);
+ setup_interface_offsets (class, 0, FALSE);
mono_loader_unlock ();
}
}
for (i = 0; i < size; ++i) {
MonoMethod *cm = vtable [i];
- if (cm) {
- char *cm_name = mono_method_full_name (cm, TRUE);
- char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
- printf (" [%c][%03d][INDEX %03d] %s\n", newness, i, cm->slot, cm_name);
- g_free (cm_name);
- }
+ char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
+ char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
+
+ printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
+ g_free (cm_name);
}
g_free (full_name);
/* printf ("METAINIT %s.%s\n", class->name_space, class->name); */
- cur_slot = setup_interface_offsets (class, cur_slot);
+ cur_slot = setup_interface_offsets (class, cur_slot, TRUE);
if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
return;
if (im->flags & METHOD_ATTRIBUTE_STATIC)
continue;
+ TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
+
// If there is an explicit implementation, just use it right away,
// otherwise look for a matching method
if (override_im == NULL) {
g_assert (cm->slot < max_vtsize);
if (!override_map)
override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
+ mono_method_full_name (m1, 1), m1,
+ mono_method_full_name (cm, 1), cm));
g_hash_table_insert (override_map, m1, cm);
break;
}
overrides [i * 2 + 1]->slot = decl->slot;
if (!override_map)
override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
+ mono_method_full_name (decl, 1), decl,
+ mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
* overriden, then change the other occurances too.
*/
if (override_map) {
+ MonoMethod *cm;
+
for (i = 0; i < max_vtsize; ++i)
if (vtable [i]) {
- MonoMethod *cm = g_hash_table_lookup (override_map, vtable [i]);
+ TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
+
+ cm = g_hash_table_lookup (override_map, vtable [i]);
if (cm)
vtable [i] = cm;
}
first_iface_slot = class->parent->vtable_size;
if (mono_class_need_stelemref_method (class))
++first_iface_slot;
- setup_interface_offsets (class, first_iface_slot);
+ setup_interface_offsets (class, first_iface_slot, TRUE);
} else {
- setup_interface_offsets (class, 0);
+ setup_interface_offsets (class, 0, TRUE);
}
if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
class->valuetype = class->enumtype = 1;
}
/*class->enumtype = class->parent->enumtype; */
- mono_class_setup_supertypes (class);
} else {
/* initialize com types if COM interfaces are present */
if (MONO_CLASS_IS_IMPORT (class))
mono_class_setup_supertypes (MonoClass *class)
{
int ms;
+ MonoClass **supertypes;
if (class->supertypes)
return;
class->idepth = 1;
ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth);
- class->supertypes = mono_class_alloc0 (class, sizeof (MonoClass *) * ms);
+ supertypes = mono_class_alloc0 (class, sizeof (MonoClass *) * ms);
if (class->parent) {
- class->supertypes [class->idepth - 1] = class;
- memcpy (class->supertypes, class->parent->supertypes, class->parent->idepth * sizeof (gpointer));
+ supertypes [class->idepth - 1] = class;
+ memcpy (supertypes, class->parent->supertypes, class->parent->idepth * sizeof (gpointer));
} else {
- class->supertypes [0] = class;
+ supertypes [0] = class;
}
+
+ mono_atomic_store_release (&class->supertypes, supertypes);
}
/**
if (klass->parent->exception_type)
mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
else
- setup_interface_offsets (klass, klass->parent->vtable_size);
+ setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
}
return klass;
static MonoClass *
get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
{
- int n = mono_generic_param_num (param);
+ int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
MonoImage *image = param->image;
GHashTable *ht;
static void
set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
{
- int n = mono_generic_param_num (param);
+ int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
MonoImage *image = param->image;
GHashTable *ht;
int i;
mono_class_setup_fields_locking (klass);
- if (klass->exception_type)
- return 0;
while (klass) {
+ if (!klass->fields)
+ return 0;
for (i = 0; i < klass->field.count; ++i) {
if (&klass->fields [i] == field) {
int idx = klass->field.first + i + 1;
if (!klass->ext->field_def_values [field_index].data) {
cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
- g_assert (cindex);
+ if (!cindex)
+ return NULL;
+
g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
gboolean check_interfaces)
{
- g_assert (klassc->idepth > 0);
if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
return TRUE;
return FALSE;
}
+static gboolean
+mono_type_is_generic_argument (MonoType *type)
+{
+ return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
+}
+
gboolean
mono_class_has_variant_generic_params (MonoClass *klass)
{
return FALSE;
}
+static gboolean
+mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
+{
+ if (target == candidate)
+ return TRUE;
+
+ if (check_for_reference_conv &&
+ mono_type_is_generic_argument (&target->byval_arg) &&
+ mono_type_is_generic_argument (&candidate->byval_arg)) {
+ MonoGenericParam *gparam = candidate->byval_arg.data.generic_param;
+ MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
+
+ if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
+ return FALSE;
+ }
+ if (!mono_class_is_assignable_from (target, candidate))
+ return FALSE;
+ return TRUE;
+}
+
/**
* @container the generic container from the GTD
* @klass: the class to be assigned to
* Both klass and oklass must be instances of the same generic interface.
* Return true if @klass can be assigned to a @klass variable
*/
-static gboolean
-mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass)
+gboolean
+mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
{
int j;
MonoType **klass_argv, **oklass_argv;
MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
MonoGenericContainer *container = klass_gtd->generic_container;
+ if (klass == oklass)
+ return TRUE;
+
/*Viable candidates are instances of the same generic interface*/
if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
return FALSE;
MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
- if (param1_class->valuetype != param2_class->valuetype)
+ if (param1_class->valuetype != param2_class->valuetype || (param1_class->valuetype && param1_class != param2_class))
return FALSE;
/*
*/
if (param1_class != param2_class) {
if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
- if (!mono_class_is_assignable_from (param1_class, param2_class))
+ if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
return FALSE;
} else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
- if (!mono_class_is_assignable_from (param2_class, param1_class))
+ if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
return FALSE;
} else
return FALSE;
return TRUE;
}
+static gboolean
+mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
+{
+ MonoGenericParam *gparam, *ogparam;
+ MonoGenericParamInfo *tinfo, *cinfo;
+ MonoClass **candidate_class;
+ gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
+ int tmask, cmask;
+
+ if (target == candidate)
+ return TRUE;
+ if (target->byval_arg.type != candidate->byval_arg.type)
+ return FALSE;
+
+ gparam = target->byval_arg.data.generic_param;
+ ogparam = candidate->byval_arg.data.generic_param;
+ tinfo = mono_generic_param_info (gparam);
+ cinfo = mono_generic_param_info (ogparam);
+
+ class_constraint_satisfied = FALSE;
+ valuetype_constraint_satisfied = FALSE;
+
+ /*candidate must have a super set of target's special constraints*/
+ tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
+ cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
+
+ if (cinfo->constraints) {
+ for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
+ MonoClass *cc = *candidate_class;
+
+ if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
+ class_constraint_satisfied = TRUE;
+ else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
+ valuetype_constraint_satisfied = TRUE;
+ }
+ }
+ class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
+ valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
+
+ if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
+ return FALSE;
+ if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
+ return FALSE;
+ if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
+ valuetype_constraint_satisfied)) {
+ return FALSE;
+ }
+
+
+ /*candidate type constraints must be a superset of target's*/
+ if (tinfo->constraints) {
+ MonoClass **target_class;
+ for (target_class = tinfo->constraints; *target_class; ++target_class) {
+ MonoClass *tc = *target_class;
+
+ /*
+ * A constraint from @target might inflate into @candidate itself and in that case we don't need
+ * check it's constraints since it satisfy the constraint by itself.
+ */
+ if (mono_metadata_type_equal (&tc->byval_arg, &candidate->byval_arg))
+ continue;
+
+ if (!cinfo->constraints)
+ return FALSE;
+
+ for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
+ MonoClass *cc = *candidate_class;
+
+ if (mono_class_is_assignable_from (tc, cc))
+ break;
+
+ /*
+ * This happens when we have the following:
+ *
+ * Bar<K> where K : IFace
+ * Foo<T, U> where T : U where U : IFace
+ * ...
+ * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
+ *
+ */
+ if (mono_type_is_generic_argument (&cc->byval_arg)) {
+ if (mono_gparam_is_assignable_from (target, cc))
+ break;
+ }
+ }
+ if (!*candidate_class)
+ return FALSE;
+ }
+ }
+
+ /*candidate itself must have a constraint that satisfy target*/
+ if (cinfo->constraints) {
+ for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
+ MonoClass *cc = *candidate_class;
+ if (mono_class_is_assignable_from (target, cc))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
/**
* mono_class_is_assignable_from:
* @klass: the class to be assigned to
if (klass->exception_type || oklass->exception_type)
return FALSE;
- if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
- return klass == oklass;
+ if (mono_type_is_generic_argument (&klass->byval_arg)) {
+ if (!mono_type_is_generic_argument (&oklass->byval_arg))
+ return FALSE;
+ 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))
+ 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;
+ }
+ }
+
return FALSE;
+ }
/* interface_offsets might not be set for dynamic classes */
if (oklass->ref_info_handle && !oklass->interface_bitmap)
for (i = 0; i < oklass->interface_offsets_count; ++i) {
MonoClass *iface = oklass->interfaces_packed [i];
- if (mono_class_is_variant_compatible (klass, iface))
+ if (mono_class_is_variant_compatible (klass, iface, FALSE))
return TRUE;
}
}
return FALSE;
} else if (klass->delegate) {
- if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass))
+ if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE))
return TRUE;
}else if (klass->rank) {
MonoClass *eclass, *eoclass;
if (target == mono_defaults.object_class)
return TRUE;
- /*setup_supertypes don't mono_class_init anything */
- mono_class_setup_supertypes (candidate);
- mono_class_setup_supertypes (target);
-
if (mono_class_has_parent (candidate, target))
return TRUE;
return mono_class_implement_interface_slow (target, candidate);
if (target->delegate && mono_class_has_variant_generic_params (target))
- return mono_class_is_variant_compatible (target, candidate);
+ return mono_class_is_variant_compatible (target, candidate, FALSE);
/*FIXME properly handle nullables and arrays */
-
+ /*FIXME properly handle (M)VAR */
return FALSE;
}
{
if (global_interface_bitset)
mono_bitset_free (global_interface_bitset);
+ global_interface_bitset = NULL;
}
/**
int i;
klass = mono_class_get_generic_type_definition (klass);
parent = mono_class_get_generic_type_definition (parent);
-
+ mono_class_setup_supertypes (klass);
+
for (i = 0; i < klass->idepth; ++i) {
if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
return TRUE;