MonoStats mono_stats;
gboolean mono_print_vtable = FALSE;
+gboolean mono_align_small_structs = FALSE;
/* Statistics */
guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
The defacto behavior is that it's just a typedef in disguise.
*/
/* a typedef in disguise */
- res = mono_class_from_name (image, nspace, name); /*FIXME proper error handling*/
+ res = mono_class_from_name_checked (image, nspace, name, error);
goto done;
case MONO_RESOLUTION_SCOPE_MODULEREF:
module = mono_image_load_module (image, idx);
if (module)
- res = mono_class_from_name (module, nspace, name); /*FIXME proper error handling*/
+ res = mono_class_from_name_checked (module, nspace, name, error);
goto done;
case MONO_RESOLUTION_SCOPE_TYPEREF: {
return NULL;
}
- /* FIXME this leaks loader errors */
- res = mono_class_from_name (image->references [idx - 1]->image, nspace, name);
+ res = mono_class_from_name_checked (image->references [idx - 1]->image, nspace, name, error);
done:
/* Generic case, should be avoided for when a better error is possible. */
return;
}
- if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (class->image) && !strcmp (class->name_space, "System") && !strcmp (class->name, "ValueType")))
blittable = FALSE;
/* Prevent infinite loops if the class references itself */
{
/* When we do generic sharing we let type variables stand for reference/primitive types. */
if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) &&
- (!type->data.generic_param->gshared_constraint || type->data.generic_param->gshared_constraint == MONO_TYPE_OBJECT))
+ (!type->data.generic_param->gshared_constraint || type->data.generic_param->gshared_constraint->type == MONO_TYPE_OBJECT))
return &mono_defaults.object_class->byval_arg;
return type;
}
+static gboolean
+type_has_references (MonoClass *klass, MonoType *ftype)
+{
+ if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ return TRUE;
+ if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
+ MonoGenericParam *gparam = ftype->data.generic_param;
+
+ if (gparam->gshared_constraint)
+ return mono_class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
+ }
+ return FALSE;
+}
+
/*
* mono_class_layout_fields:
* @class: a class
if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ if (type_has_references (class, ftype))
class->has_references = TRUE;
}
}
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ if (type_has_references (class, ftype))
class->has_static_refs = TRUE;
}
}
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
+ if (type_has_references (class, ftype)) {
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
class->has_static_refs = TRUE;
else
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
if (gc_aware_layout) {
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
+ if (type_has_references (class, ftype)) {
if (pass == 1)
continue;
} else {
/* if the field has managed references, we need to force-align it
* see bug #77788
*/
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ if (type_has_references (class, ftype))
align = MAX (align, sizeof (gpointer));
class->min_align = MAX (align, class->min_align);
field->offset += sizeof (MonoObject);
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
- if (MONO_TYPE_IS_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
+ if (type_has_references (class, ftype)) {
if (field->offset % sizeof (gpointer)) {
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
}
if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
/*
+ * This leads to all kinds of problems with nested structs, so only
+ * enable it when a MONO_DEBUG property is set.
+ *
* For small structs, set min_align to at least the struct size to improve
* performance, and since the JIT memset/memcpy code assumes this and generates
* unaligned accesses otherwise. See #78990 for a testcase.
*/
- if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
- class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject));
+ if (mono_align_small_structs) {
+ if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
+ class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject));
+ }
}
mono_memory_barrier ();
* 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 && !overwrite) {
- g_assert (class->interface_offsets_count == interface_offsets_count);
+ if (class->interfaces_packed) {
+ if (!overwrite)
+ g_assert (class->interface_offsets_count == interface_offsets_count);
} else {
uint8_t *bitmap;
int bsize;
}
static gboolean
-check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty, gboolean security_enabled) {
+check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
+{
MonoMethodSignature *cmsig, *imsig;
if (strcmp (im->name, cm->name) == 0) {
if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
return FALSE;
}
TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
- /* CAS - SecurityAction.InheritanceDemand on interface */
- if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_method (cm, im);
- }
-
if (mono_security_core_clr_enabled ())
mono_security_core_clr_check_override (class, cm, im);
}
TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
- /* CAS - SecurityAction.InheritanceDemand on interface */
- if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_method (cm, im);
- }
-
if (mono_security_core_clr_enabled ())
mono_security_core_clr_check_override (class, cm, im);
int i, max_vtsize = 0, max_iid, cur_slot = 0;
GPtrArray *ifaces = NULL;
GHashTable *override_map = NULL;
- gboolean security_enabled = mono_security_enabled ();
MonoMethod *cm;
#if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
int first_non_interface_slot;
for (l = virt_methods; l; l = l->next) {
cm = l->data;
TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
- if (check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
+ if (check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
vtable [im_slot] = cm;
/* Why do we need this? */
MonoMethod *cm = parent->vtable [cm_index];
TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
- if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
+ if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE)) {
TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
vtable [im_slot] = cm;
/* Why do we need this? */
if (!strcmp(cm->name, m1->name) &&
mono_metadata_signature_equal (cmsig, m1sig)) {
- /* CAS - SecurityAction.InheritanceDemand */
- if (security_enabled && (m1->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_method (cm, m1);
- }
-
if (mono_security_core_clr_enabled ())
mono_security_core_clr_check_override (class, cm, m1);
MonoClass *gklass;
int i;
+ if (!method->klass->generic_class) {
+ g_assert (method->is_inflated);
+ return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
+ }
+
/* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
g_assert (method->klass->generic_class);
gklass = method->klass->generic_class->container_class;
}
}
- /* CAS - SecurityAction.InheritanceDemand */
- if (mono_security_enabled () && class->parent && (class->parent->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_class (class, class->parent);
- }
-
mono_stats.initialized_class_count++;
if (class->generic_class && !class->generic_class->is_dynamic) {
mono_generic_class_setup_parent (klass, gklass);
if (gclass->is_dynamic) {
- klass->inited = 1;
+ /*
+ * We don't need to do any init workf with unbaked typebuilders. Generic instances created at this point will be later unregistered and/or fixed.
+ * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
+ * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
+ */
+ if (!gklass->wastypebuilder)
+ klass->inited = 1;
mono_class_setup_supertypes (klass);
static MonoClass *
get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, gboolean take_lock)
{
- int n = mono_generic_param_num (param) | ((guint32)param->gshared_constraint << 16);
+ int n = mono_generic_param_num (param);
MonoImage *image = param->image;
+ MonoClass *klass = NULL;
GHashTable *ht;
g_assert (image);
+ if (param->gshared_constraint) {
+ ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
+ if (ht) {
+ if (take_lock)
+ mono_image_lock (image);
+ klass = g_hash_table_lookup (ht, param);
+ if (take_lock)
+ mono_image_unlock (image);
+ }
+ return klass;
+ }
+
if (n < FAST_CACHE_SIZE) {
if (is_mvar)
return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
else
return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
} else {
- MonoClass *klass = NULL;
ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
if (ht) {
if (take_lock)
static void
set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
{
- int n = mono_generic_param_num (param) | ((guint32)param->gshared_constraint << 16);
+ int n = mono_generic_param_num (param);
MonoImage *image = param->image;
g_assert (image);
- if (n < FAST_CACHE_SIZE) {
+ if (param->gshared_constraint) {
+ GHashTable *ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
+ if (!ht) {
+ ht = g_hash_table_new ((GHashFunc)mono_metadata_generic_param_hash, (GEqualFunc)mono_metadata_generic_param_equal);
+ mono_memory_barrier ();
+ if (is_mvar)
+ image->mvar_cache_constrained = ht;
+ else
+ image->var_cache_constrained = ht;
+ }
+ g_hash_table_insert (ht, param, klass);
+ } else if (n < FAST_CACHE_SIZE) {
if (is_mvar) {
/* Requires locking to avoid droping an already published class */
if (!image->mvar_cache_fast)
return NULL;
}
-/**
- * mono_class_from_name:
- * @image: The MonoImage where the type is looked up in
- * @name_space: the type namespace
- * @name: the type short name.
- *
- * Obtains a MonoClass with a given namespace and a given name which
- * is located in the given MonoImage.
- *
- * To reference nested classes, use the "/" character as a separator.
- * For example use "Foo/Bar" to reference the class Bar that is nested
- * inside Foo, like this: "class Foo { class Bar {} }".
- */
MonoClass *
-mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
+mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
{
- MonoError error;
GHashTable *nspace_table;
MonoImage *loaded_image;
guint32 token = 0;
char *nested;
char buf [1024];
+ mono_error_init (error);
+
if ((nested = strchr (name, '/'))) {
int pos = nested - name;
int len = strlen (name);
token = MONO_TOKEN_TYPE_DEF | token;
- class = mono_class_get_checked (image, token, &error);
+ class = mono_class_get_checked (image, token, error);
+ if (nested)
+ return return_nested_in (class, nested);
+ return class;
+}
+
+/**
+ * mono_class_from_name:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * Obtains a MonoClass with a given namespace and a given name which
+ * is located in the given MonoImage.
+ *
+ * To reference nested classes, use the "/" character as a separator.
+ * For example use "Foo/Bar" to reference the class Bar that is nested
+ * inside Foo, like this: "class Foo { class Bar {} }".
+ */
+MonoClass *
+mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
+{
+ MonoError error;
+ MonoClass *klass;
+
+ klass = mono_class_from_name_checked (image, name_space, name, &error);
if (!mono_error_ok (&error)) {
mono_loader_set_error_from_mono_error (&error);
mono_error_cleanup (&error); /* FIXME Don't swallow the error */
}
- if (nested)
- return return_nested_in (class, nested);
- return class;
+ return klass;
}
/**
gpointer exception_data = mono_class_get_exception_data (klass);
switch (klass->exception_type) {
-#ifndef DISABLE_SECURITY
- case MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND: {
- MonoDomain *domain = mono_domain_get ();
- MonoSecurityManager* secman = mono_security_manager_get_methods ();
- MonoMethod *method = exception_data;
- guint32 error = (method) ? MONO_METADATA_INHERITANCEDEMAND_METHOD : MONO_METADATA_INHERITANCEDEMAND_CLASS;
- MonoObject *exc = NULL;
- gpointer args [4];
-
- args [0] = &error;
- args [1] = mono_assembly_get_object (domain, mono_image_get_assembly (klass->image));
- args [2] = mono_type_get_object (domain, &klass->byval_arg);
- args [3] = (method) ? mono_method_get_object (domain, method, NULL) : NULL;
-
- mono_runtime_invoke (secman->inheritsecurityexception, NULL, args, &exc);
- return (MonoException*) exc;
- }
-#endif
case MONO_EXCEPTION_TYPE_LOAD: {
MonoString *name;
MonoException *ex;