#endif
#include <mono/metadata/image.h>
#include <mono/metadata/assembly.h>
-#include <mono/metadata/cil-coff.h>
#include <mono/metadata/metadata.h>
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/reflection.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/security-manager.h>
+#include <mono/metadata/security-core-clr.h>
+#include <mono/metadata/attrdefs.h>
#include <mono/os/gc_wrapper.h>
#include <mono/utils/mono-counters.h>
return mono_class_from_name (image->references [idx - 1]->image, nspace, name);
}
-static inline MonoType*
-dup_type (MonoType* t, const MonoType *original)
-{
- MonoType *r = g_new0 (MonoType, 1);
- *r = *t;
- r->attrs = original->attrs;
- r->byref = original->byref;
- if (t->type == MONO_TYPE_PTR)
- t->data.type = dup_type (t->data.type, original->data.type);
- else if (t->type == MONO_TYPE_ARRAY)
- t->data.array = mono_dup_array_type (t->data.array);
- else if (t->type == MONO_TYPE_FNPTR)
- t->data.method = mono_metadata_signature_deep_dup (t->data.method);
- mono_stats.generics_metadata_size += sizeof (MonoType);
- return r;
-}
-
/* Copy everything mono_metadata_free_array free. */
MonoArrayType *
mono_dup_array_type (MonoArrayType *a)
sig = mono_metadata_signature_dup (sig);
- sig->ret = dup_type (sig->ret, sig->ret);
+ sig->ret = mono_metadata_type_dup (NULL, sig->ret);
for (i = 0; i < sig->param_count; ++i)
- sig->params [i] = dup_type (sig->params [i], sig->params [i]);
+ sig->params [i] = mono_metadata_type_dup (NULL, sig->params [i]);
return sig;
}
ta->aname.public_key_token [0] ? (char *)ta->aname.public_key_token : "null");
}
+static inline void
+mono_type_name_check_byref (MonoType *type, GString *str)
+{
+ if (type->byref)
+ g_string_append_c (str, '&');
+}
+
static void
mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
MonoTypeNameFormat format)
for (i = 1; i < rank; i++)
g_string_append_c (str, ',');
g_string_append_c (str, ']');
+
+ mono_type_name_check_byref (type, str);
+
if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
_mono_type_get_assembly_name (type->data.array->eklass, str);
break;
mono_type_get_name_recurse (
&type->data.klass->byval_arg, str, FALSE, nested_format);
g_string_append (str, "[]");
+
+ mono_type_name_check_byref (type, str);
+
if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
_mono_type_get_assembly_name (type->data.klass, str);
break;
mono_type_get_name_recurse (
type->data.type, str, FALSE, nested_format);
g_string_append_c (str, '*');
+
+ mono_type_name_check_byref (type, str);
+
if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
_mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
break;
case MONO_TYPE_MVAR:
g_assert (type->data.generic_param->name);
g_string_append (str, type->data.generic_param->name);
+
+ mono_type_name_check_byref (type, str);
+
break;
default:
klass = mono_class_from_mono_type (type);
break;
if (klass->generic_class) {
MonoGenericClass *gclass = klass->generic_class;
+ MonoGenericInst *inst = gclass->context.class_inst;
MonoTypeNameFormat nested_format;
int i;
g_string_append_c (str, '<');
else
g_string_append_c (str, '[');
- for (i = 0; i < gclass->inst->type_argc; i++) {
- MonoType *t = gclass->inst->type_argv [i];
+ for (i = 0; i < inst->type_argc; i++) {
+ MonoType *t = inst->type_argv [i];
if (i)
g_string_append_c (str, ',');
if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
(t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
g_string_append_c (str, '[');
- mono_type_get_name_recurse (
- gclass->inst->type_argv [i], str, FALSE, nested_format);
+ mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
(t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
g_string_append_c (str, ']');
else
g_string_append_c (str, ']');
}
+
+ mono_type_name_check_byref (type, str);
+
if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
(type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
_mono_type_get_assembly_name (klass, str);
mono_type_get_name_recurse (type, result, FALSE, format);
- if (type->byref)
- g_string_append_c (result, '&');
-
return g_string_free (result, FALSE);
}
* mono_type_get_underlying_type:
* @type: a type
*
- * Returns: the MonoType for the underlying interger type if @type
+ * Returns: the MonoType for the underlying integer type if @type
* is an enum and byref is false, otherwise the type itself.
*/
MonoType*
return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg);
case MONO_TYPE_PTR:
return mono_class_is_open_constructed_type (t->data.type);
- case MONO_TYPE_GENERICINST: {
- MonoGenericClass *gclass = t->data.generic_class;
- int i;
-
- if (mono_class_is_open_constructed_type (&gclass->container_class->byval_arg))
- return TRUE;
- for (i = 0; i < gclass->inst->type_argc; i++)
- if (mono_class_is_open_constructed_type (gclass->inst->type_argv [i]))
- return TRUE;
- return FALSE;
- }
+ case MONO_TYPE_GENERICINST:
+ return t->data.generic_class->context.class_inst->is_open;
default:
return FALSE;
}
}
-static MonoGenericClass *
-inflate_generic_class (MonoGenericClass *ogclass, MonoGenericContext *context)
-{
- MonoGenericClass *ngclass, *cached;
- MonoGenericInst *ninst;
-
- ninst = mono_metadata_inflate_generic_inst (ogclass->inst, context);
- if (ninst == ogclass->inst)
- return ogclass;
-
- if (ogclass->is_dynamic) {
- MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
- ngclass = &dgclass->generic_class;
- ngclass->is_dynamic = 1;
- } else {
- ngclass = g_new0 (MonoGenericClass, 1);
- }
-
- ngclass->container_class = ogclass->container_class;
- ngclass->inst = ninst;
-
- mono_loader_lock ();
- cached = mono_metadata_lookup_generic_class (ngclass);
- mono_loader_unlock ();
- if (cached) {
- g_free (ngclass);
- return cached;
- }
-
- return ngclass;
-}
-
static MonoType*
inflate_generic_type (MonoType *type, MonoGenericContext *context)
{
switch (type->type) {
case MONO_TYPE_MVAR: {
+ MonoType *nt;
int num = type->data.generic_param->num;
- MonoGenericInst *inst = context->gmethod ? context->gmethod->inst : NULL;
+ MonoGenericInst *inst = context->method_inst;
if (!inst || !inst->type_argv)
return NULL;
if (num >= inst->type_argc)
g_error ("MVAR %d (%s) cannot be expanded in this context with %d instantiations", num, type->data.generic_param->name, inst->type_argc);
- return dup_type (inst->type_argv [num], type);
+
+ /*
+ * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
+ * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
+ * ->byref and ->attrs from @type are propagated to the returned type.
+ */
+ nt = mono_metadata_type_dup (NULL, inst->type_argv [num]);
+ nt->byref = type->byref;
+ nt->attrs = type->attrs;
+ return nt;
}
case MONO_TYPE_VAR: {
+ MonoType *nt;
int num = type->data.generic_param->num;
MonoGenericInst *inst = context->class_inst;
if (!inst)
return NULL;
if (num >= inst->type_argc)
g_error ("VAR %d (%s) cannot be expanded in this context with %d instantiations", num, type->data.generic_param->name, inst->type_argc);
- return dup_type (inst->type_argv [num], type);
+ nt = mono_metadata_type_dup (NULL, inst->type_argv [num]);
+ nt->byref = type->byref;
+ nt->attrs = type->attrs;
+ return nt;
}
case MONO_TYPE_SZARRAY: {
MonoClass *eclass = type->data.klass;
MonoType *nt, *inflated = inflate_generic_type (&eclass->byval_arg, context);
if (!inflated)
return NULL;
- nt = dup_type (type, type);
+ nt = mono_metadata_type_dup (NULL, type);
nt->data.klass = mono_class_from_mono_type (inflated);
return nt;
}
MonoType *nt, *inflated = inflate_generic_type (&eclass->byval_arg, context);
if (!inflated)
return NULL;
- nt = dup_type (type, type);
+ nt = mono_metadata_type_dup (NULL, type);
nt->data.array = g_memdup (nt->data.array, sizeof (MonoArrayType));
nt->data.array->eklass = mono_class_from_mono_type (inflated);
return nt;
}
case MONO_TYPE_GENERICINST: {
MonoGenericClass *gclass = type->data.generic_class;
+ MonoGenericInst *inst;
MonoType *nt;
- if (!gclass->inst->is_open)
+ if (!gclass->context.class_inst->is_open)
return NULL;
- gclass = inflate_generic_class (gclass, context);
+
+ inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context);
+ if (inst != gclass->context.class_inst)
+ gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
+
if (gclass == type->data.generic_class)
return NULL;
- nt = dup_type (type, type);
+
+ nt = mono_metadata_type_dup (NULL, type);
nt->data.generic_class = gclass;
return nt;
}
case MONO_TYPE_CLASS:
case MONO_TYPE_VALUETYPE: {
MonoClass *klass = type->data.klass;
- MonoGenericClass *gclass;
+ MonoGenericContainer *container = klass->generic_container;
+ MonoGenericInst *inst;
+ MonoGenericClass *gclass = NULL;
MonoType *nt;
- if (!klass->generic_container)
- return NULL;
- gclass = inflate_generic_class (mono_get_shared_generic_class (klass->generic_container, klass->image->dynamic), context);
- if (gclass->inst == klass->generic_container->context.class_inst)
+ if (!container)
return NULL;
- nt = dup_type (type, type);
+
+ /* We can't use context->class_inst directly, since it can have more elements */
+ inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context);
+ gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
+
+ nt = mono_metadata_type_dup (NULL, type);
nt->type = MONO_TYPE_GENERICINST;
nt->data.generic_class = gclass;
return nt;
MonoGenericContext *
mono_generic_class_get_context (MonoGenericClass *gclass)
{
- MonoGenericContext *context = gclass->cached_context;
- if (context) {
- g_assert (context->class_inst == gclass->inst);
- g_assert (!context->gmethod);
- return context;
- }
-
- context = g_new0 (MonoGenericContext, 1);
- context->class_inst = gclass->inst;
-
- if (InterlockedCompareExchangePointer ((gpointer *)&gclass->cached_context, context, NULL))
- g_free (context);
-
- return gclass->cached_context;
+ return &gclass->context;
}
MonoGenericContext *
MonoType *inflated = inflate_generic_type (type, context);
if (!inflated)
- return dup_type (type, type);
+ return mono_metadata_type_dup (NULL, type);
mono_stats.inflated_type_count++;
return inflated;
}
-static MonoGenericContext *
+static MonoGenericContext
inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with)
{
MonoGenericInst *class_inst = NULL;
- MonoGenericMethod *gmethod = NULL;
- MonoGenericContext *res;
+ MonoGenericInst *method_inst = NULL;
+ MonoGenericContext res;
if (context->class_inst)
class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with);
- if (context->gmethod) {
- MonoGenericInst *ninst = mono_metadata_inflate_generic_inst (context->gmethod->inst, inflate_with);
- if (class_inst == context->class_inst && ninst == context->gmethod->inst) {
- gmethod = context->gmethod;
- } else {
- gmethod = g_new0 (MonoGenericMethod, 1);
- gmethod->class_inst = class_inst;
- gmethod->container = context->gmethod->container;
- gmethod->inst = ninst;
- }
- }
+ if (context->method_inst)
+ method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with);
- if (class_inst == context->class_inst && gmethod == context->gmethod)
- return context;
-
- res = g_new0 (MonoGenericContext, 1);
- res->class_inst = class_inst;
- res->gmethod = gmethod;
+ res.class_inst = class_inst;
+ res.method_inst = method_inst;
return res;
}
*
* Instantiate method @method with the generic context @context.
* BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
- * Use mono_get_inflated_method (), mono_method_signature () and mono_method_get_header () to get the correct values.
+ * Use mono_method_signature () and mono_method_get_header () to get the correct values.
*/
MonoMethod*
mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
{
MonoMethod *result;
- MonoMethodInflated *iresult;
+ MonoMethodInflated *iresult, *cached;
MonoMethodSignature *sig;
+ MonoGenericContext tmp_context;
- /* The `method' has already been instantiated before -> we need to create a new context. */
+ /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
while (method->is_inflated) {
MonoGenericContext *method_context = mono_method_get_context (method);
MonoMethodInflated *imethod = (MonoMethodInflated *) method;
- context = inflate_generic_context (method_context, context);
- if (context == method_context)
+
+ tmp_context = inflate_generic_context (method_context, context);
+ context = &tmp_context;
+
+ if (mono_metadata_generic_context_equal (method_context, context))
return method;
+
method = imethod->declaring;
}
mono_stats.inflated_method_count++;
iresult = g_new0 (MonoMethodInflated, 1);
+ iresult->context = *context;
+ iresult->declaring = method;
+
+ mono_loader_lock ();
+ cached = mono_method_inflated_lookup (iresult, FALSE);
+ if (cached) {
+ mono_loader_unlock ();
+ g_free (iresult);
+ return (MonoMethod*)cached;
+ }
sig = mono_method_signature (method);
if (sig->pinvoke) {
result = (MonoMethod *) iresult;
result->is_inflated = 1;
+ /* result->generic_container = NULL; */
result->signature = NULL;
- iresult->context = context;
- iresult->declaring = method;
if (!klass_hint || !klass_hint->generic_class ||
klass_hint->generic_class->container_class != method->klass ||
- klass_hint->generic_class->inst != context->class_inst)
+ klass_hint->generic_class->context.class_inst != context->class_inst)
klass_hint = NULL;
if (method->klass->generic_container)
result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
}
- if (method->generic_container && !context->gmethod) {
- MonoGenericMethod *gmethod = g_memdup (method->generic_container->context.gmethod, sizeof (*gmethod));
- if (result->klass->generic_class)
- gmethod->class_inst = result->klass->generic_class->inst;
-
- context = g_new0 (MonoGenericContext, 1);
- context->gmethod = gmethod;
- context->class_inst = gmethod->class_inst;
- iresult->context = context;
- }
+ if (context->method_inst)
+ result->generic_container = NULL;
+ else if (method->generic_container)
+ iresult->context.method_inst = method->generic_container->context.method_inst;
+ mono_method_inflated_lookup (iresult, TRUE);
+ mono_loader_unlock ();
return result;
}
if (!method->is_inflated)
return NULL;
imethod = (MonoMethodInflated *) method;
- return imethod->context;
+ return &imethod->context;
}
/**
MonoClassField *field;
if (class->generic_container ||
- (class->generic_class && class->generic_class->inst->is_open))
+ (class->generic_class && class->generic_class->context.class_inst->is_open))
return;
/*
break;
}
+#if NO_UNALIGNED_ACCESS
if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
/*
* For small structs, set min_align to at least the struct size, since the
* JIT memset/memcpy code assumes this and generates unaligned accesses
* otherwise. See #78990 for a testcase.
+ * FIXME: Fix the memset/memcpy code instead.
*/
if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject));
}
+#endif
class->size_inited = 1;
if (mono_print_vtable) {
int generic_id;
char *type_name = mono_type_full_name (&class->byval_arg);
- if (class->generic_class && !class->generic_class->inst->is_open) {
- generic_id = class->generic_class->inst->id;
+ if (class->generic_class && !class->generic_class->context.class_inst->is_open) {
+ generic_id = class->generic_class->context.class_inst->id;
g_assert (generic_id != 0);
} else {
generic_id = 0;
}
int
-mono_class_interface_offset (MonoClass *klass, MonoClass *interface) {
+mono_class_interface_offset (MonoClass *klass, MonoClass *itf) {
MonoClass **result = bsearch (
- interface,
+ itf,
klass->interfaces_packed,
klass->interface_offsets_count,
sizeof (MonoClass *),
}
}
class->interface_offsets_count = interface_offsets_count;
- class->interfaces_packed = g_malloc (sizeof (MonoClass*) * interface_offsets_count);
- class->interface_offsets_packed = g_malloc (sizeof (int) * interface_offsets_count);
- class->interface_bitmap = g_malloc0 ((sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0));
+ class->interfaces_packed = mono_mempool_alloc (class->image->mempool, sizeof (MonoClass*) * interface_offsets_count);
+ class->interface_offsets_packed = mono_mempool_alloc (class->image->mempool, sizeof (int) * interface_offsets_count);
+ class->interface_bitmap = mono_mempool_alloc0 (class->image->mempool, (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0));
for (interface_offsets_count = 0, i = 0; i <= max_iid; i++) {
if (interface_offsets_full [i] != -1) {
class->interface_bitmap [i >> 3] |= (1 << (i & 7));
return;
}
+static void
+check_core_clr_override_method (MonoClass *class, MonoMethod *override, MonoMethod *base)
+{
+ MonoSecurityCoreCLRLevel override_level = mono_security_core_clr_method_level (override, FALSE);
+ MonoSecurityCoreCLRLevel base_level = mono_security_core_clr_method_level (base, FALSE);
+
+ if (override_level != base_level && base_level == MONO_SECURITY_CORE_CLR_CRITICAL) {
+ class->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+ class->exception_data = NULL;
+ }
+}
+
/*
* LOCKING: this is supposed to be called with the loader lock held.
*/
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_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, vtable [dslot], decl);
}
}
mono_secman_inheritancedemand_method (cm, im);
}
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
g_assert (io + l <= max_vtsize);
vtable [io + l] = cm;
}
continue;
if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
- mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+ mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im)) &&
+ ((vtable [io + l] == NULL) || mono_class_is_subclass_of (cm->klass, vtable [io + l]->klass, FALSE))) {
/* CAS - SecurityAction.InheritanceDemand on interface */
if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
mono_secman_inheritancedemand_method (cm, im);
}
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
g_assert (io + l <= max_vtsize);
vtable [io + l] = cm;
break;
mono_secman_inheritancedemand_method (cm, im);
}
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
g_assert (io + l <= max_vtsize);
vtable [io + l] = cm;
break;
printf ("METHOD %s(%s)\n", cm->name, msig);
g_free (msig);
}
- g_assert_not_reached ();
+
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+
+ if (ifaces)
+ g_ptr_array_free (ifaces, TRUE);
+ if (override_map)
+ g_hash_table_destroy (override_map);
+
+ return;
}
}
}
mono_secman_inheritancedemand_method (cm, m1);
}
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, m1);
+
slot = k->methods [j]->slot;
g_assert (cm->slot < max_vtsize);
if (!override_map)
if (!override_map)
override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, vtable [decl->slot], decl);
}
}
static void
setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos)
{
- MonoGenericContext *context;
+ MonoGenericContext tmp_context;
int i;
- context = g_new0 (MonoGenericContext, 1);
- context->gmethod = g_new0 (MonoGenericMethod, 1);
- context->gmethod->inst = iface->generic_class->inst;
+ tmp_context.class_inst = NULL;
+ tmp_context.method_inst = iface->generic_class->context.class_inst;
for (i = 0; i < class->parent->method.count; i++) {
MonoMethod *m = class->parent->methods [i];
strcpy (name, iname);
strcpy (name + strlen (iname), mname);
- inflated = mono_class_inflate_generic_method (m, context);
+ inflated = mono_class_inflate_generic_method (m, &tmp_context);
class->methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, name, inflated);
}
}
return method;
}
+static char*
+concat_two_strings_with_zero (MonoMemPool *pool, const char *s1, const char *s2)
+{
+ int len = strlen (s1) + strlen (s2) + 2;
+ char *s = mono_mempool_alloc (pool, len);
+ int result;
+
+ result = g_snprintf (s, len, "%s%c%s", s1, '\0', s2);
+ g_assert (result == len - 1);
+
+ return s;
+}
+
+static void
+set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
+{
+ class->exception_type = error->exception_type;
+
+ switch (error->exception_type) {
+ case MONO_EXCEPTION_TYPE_LOAD:
+ class->exception_data = concat_two_strings_with_zero (class->image->mempool, error->class_name, error->assembly_name);
+ break;
+
+ case MONO_EXCEPTION_MISSING_METHOD:
+ class->exception_data = concat_two_strings_with_zero (class->image->mempool, error->class_name, error->member_name);
+ break;
+
+ case MONO_EXCEPTION_MISSING_FIELD: {
+ const char *name_space = error->klass->name_space ? error->klass->name_space : NULL;
+ const char *class_name;
+
+ if (name_space)
+ class_name = g_strdup_printf ("%s.%s", name_space, error->klass->name);
+ else
+ class_name = error->klass->name;
+
+ class->exception_data = concat_two_strings_with_zero (class->image->mempool, class_name, error->member_name);
+
+ if (name_space)
+ g_free ((void*)class_name);
+ break;
+ }
+
+ case MONO_EXCEPTION_FILE_NOT_FOUND: {
+ const char *msg;
+
+ if (error->ref_only)
+ msg = "Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.";
+ else
+ msg = "Could not load file or assembly '%s' or one of its dependencies.";
+
+ class->exception_data = concat_two_strings_with_zero (class->image->mempool, msg, error->assembly_name);
+ break;
+ }
+
+ default :
+ g_assert_not_reached ();
+ }
+}
+
+static void
+check_core_clr_inheritance (MonoClass *class)
+{
+ MonoSecurityCoreCLRLevel class_level, parent_level;
+ MonoClass *parent = class->parent;
+
+ if (!parent)
+ return;
+
+ class_level = mono_security_core_clr_class_level (class);
+ parent_level = mono_security_core_clr_class_level (parent);
+
+ if (class_level < parent_level) {
+ class->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+ class->exception_data = NULL;
+ }
+}
+
/**
* mono_class_init:
* @class: the class to initialize
g_assert (class);
if (class->inited)
- return TRUE;
+ return class->exception_type == MONO_EXCEPTION_NONE;
/*g_print ("Init class %s\n", class->name);*/
if (class->inited) {
mono_loader_unlock ();
/* Somebody might have gotten in before us */
- return TRUE;
+ return class->exception_type == MONO_EXCEPTION_NONE;
}
if (class->init_pending) {
mono_secman_inheritancedemand_class (class, class->parent);
}
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_inheritance (class);
+
if (mono_debugger_start_class_init_func)
mono_debugger_start_class_init_func (class);
class->methods = g_new0 (MonoMethod *, class->method.count);
for (i = 0; i < class->method.count; i++) {
- MonoMethod *inflated = mono_class_inflate_generic_method_full (
+ class->methods [i] = mono_class_inflate_generic_method_full (
gklass->methods [i], class, mono_class_get_context (class));
-
- class->methods [i] = mono_get_inflated_method (inflated);
}
class->property = gklass->property;
has_cached_info = mono_class_get_cached_class_info (class, &cached_info);
- if (!class->generic_class && (!has_cached_info || (has_cached_info && cached_info.has_nested_classes))) {
+ if (!class->generic_class && !class->image->dynamic && (!has_cached_info || (has_cached_info && cached_info.has_nested_classes))) {
i = mono_metadata_nesting_typedef (class->image, class->type_token, 1);
while (i) {
MonoClass* nclass;
class->inited = 1;
class->init_pending = 0;
+ if (mono_loader_get_last_error ()) {
+ if (class->exception_type == MONO_EXCEPTION_NONE)
+ set_failure_from_loader_error (class, mono_loader_get_last_error ());
+
+ mono_loader_clear_error ();
+ }
+
mono_loader_unlock ();
if (mono_debugger_class_init_func)
} else {
class->supertypes [0] = class;
}
-}
-
-MonoGenericInst *
-mono_get_shared_generic_inst (MonoGenericContainer *container)
-{
- MonoGenericInst *nginst;
- int i;
-
- nginst = g_new0 (MonoGenericInst, 1);
- nginst->type_argc = container->type_argc;
- nginst->type_argv = g_new0 (MonoType *, nginst->type_argc);
- nginst->is_reference = 1;
- nginst->is_open = 1;
-
- for (i = 0; i < nginst->type_argc; i++) {
- MonoType *t = g_new0 (MonoType, 1);
-
- t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
- t->data.generic_param = &container->type_params [i];
-
- nginst->type_argv [i] = t;
- }
-
- return mono_metadata_lookup_generic_inst (nginst);
-}
-
-/*
- * In preparation for implementing shared code.
- */
-MonoGenericClass *
-mono_get_shared_generic_class (MonoGenericContainer *container, gboolean is_dynamic)
-{
- MonoGenericClass *gclass;
-
- g_assert (!container->is_method);
-
- if (is_dynamic) {
- MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
- gclass = &dgclass->generic_class;
- gclass->is_dynamic = 1;
- } else {
- gclass = g_new0 (MonoGenericClass, 1);
- }
-
- gclass->cached_context = &container->context;
- gclass->container_class = container->owner.klass;
- gclass->inst = mono_get_shared_generic_inst (container);
-
- if (!is_dynamic) {
- MonoGenericClass *cached = mono_metadata_lookup_generic_class (gclass);
-
- if (cached) {
- g_free (gclass);
- return cached;
- }
- }
-
- gclass->cached_class = container->owner.klass;
-
- return gclass;
}
/**
mono_loader_lock ();
- if ((class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token)))) {
+ if ((class = mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
mono_loader_unlock ();
return class;
}
class->type_token = type_token;
class->flags = cols [MONO_TYPEDEF_FLAGS];
- g_hash_table_insert (image->class_cache, GUINT_TO_POINTER (type_token), class);
+ mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), class);
/*
* Check whether we're a generic type definition.
if (class->generic_container) {
class->generic_container->owner.klass = class;
context = &class->generic_container->context;
-
- context->class_inst = mono_get_shared_generic_inst (class->generic_container);
}
if (cols [MONO_TYPEDEF_EXTENDS]) {
parent = mono_class_get_full (
image, mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]), context);
if (parent == NULL){
- g_hash_table_remove (image->class_cache, GUINT_TO_POINTER (type_token));
+ mono_internal_hash_table_remove (&image->class_cache, GUINT_TO_POINTER (type_token));
mono_loader_unlock ();
return NULL;
}
if (class->enumtype) {
class->enum_basetype = mono_class_find_enum_basetype (class);
+ if (!class->enum_basetype) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_loader_unlock ();
+ return NULL;
+ }
class->cast_class = class->element_class = mono_class_from_mono_type (class->enum_basetype);
}
mono_class_get_nullable_param (MonoClass *klass)
{
g_assert (mono_class_is_nullable (klass));
- return mono_class_from_mono_type (klass->generic_class->inst->type_argv [0]);
+ return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
}
/*
mono_loader_lock ();
if (gclass->cached_class) {
mono_loader_unlock ();
+ g_assert (!gclass->cached_class->generic_container);
return gclass->cached_class;
}
if (!image && param->owner) {
if (is_mvar) {
MonoMethod *method = param->owner->owner.method;
- image = method->klass ? method->klass->image : NULL;
+ image = (method && method->klass) ? method->klass->image : NULL;
} else {
MonoClass *klass = param->owner->owner.klass;
- image = klass->image;
+ // FIXME: 'klass' should not be null
+ // But, monodis creates GenericContainers without associating a owner to it
+ image = klass ? klass->image : NULL;
}
}
case MONO_TYPE_MVAR:
return mono_class_from_generic_parameter (type->data.generic_param, NULL, TRUE);
default:
- g_warning ("implement me 0x%02x\n", type->type);
+ g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
g_assert_not_reached ();
}
}
/**
+ * mono_type_retrieve_from_typespec
* @image: context where the image is created
* @type_spec: typespec token
* @context: the generic context used to evaluate generic instantiations in
*/
-static MonoClass *
-mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
+static MonoType *
+mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
{
MonoType *t = mono_type_create_from_typespec (image, type_spec);
if (!t)
return NULL;
- if (context && (context->class_inst || context->gmethod)) {
+ if (context && (context->class_inst || context->method_inst)) {
MonoType *inflated = inflate_generic_type (t, context);
if (inflated)
t = inflated;
}
+ return t;
+}
+
+/**
+ * mono_class_create_from_typespec
+ * @image: context where the image is created
+ * @type_spec: typespec token
+ * @context: the generic context used to evaluate generic instantiations in
+ */
+static MonoClass *
+mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
+{
+ MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context);
+ if (!t)
+ return NULL;
return mono_class_from_mono_type (t);
}
(eclass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
class->parent = parent;
class->instance_size = mono_class_instance_size (class->parent);
- class->sizes.element_size = mono_class_array_element_size (eclass);
+
+ if (eclass->enumtype && !eclass->enum_basetype) {
+ if (!eclass->reflection_info || eclass->wastypebuilder) {
+ g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
+ g_assert (eclass->reflection_info && !eclass->wastypebuilder);
+ }
+ /* element_size -1 is ok as this is not an instantitable type*/
+ class->sizes.element_size = -1;
+ } else
+ class->sizes.element_size = mono_class_array_element_size (eclass);
+
mono_class_setup_supertypes (class);
if (mono_defaults.generic_ilist_class) {
class->interface_count = eclass->idepth + eclass->interface_count;
}
- class->interfaces = g_new0 (MonoClass *, class->interface_count);
+ class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
for (i = 0; i < class->interface_count; i++) {
- MonoType *inflated, **args;
+ MonoType *args [1];
MonoClass *iface;
if (eclass->valuetype)
iface = eclass->interfaces [i - eclass->idepth];
}
- args = g_new0 (MonoType *, 1);
args [0] = &iface->byval_arg;
- inflated = mono_class_bind_generic_parameters (
- &mono_defaults.generic_ilist_class->byval_arg, 1, args);
-
- class->interfaces [i] = mono_class_from_mono_type (inflated);
+ class->interfaces [i] = mono_class_bind_generic_parameters (
+ mono_defaults.generic_ilist_class, 1, args, FALSE);
}
}
MonoClass *class = NULL;
if (image->dynamic)
- return mono_lookup_dynamic_token (image, type_token);
+ return mono_lookup_dynamic_token (image, type_token, context);
switch (type_token & 0xff000000){
case MONO_TOKEN_TYPE_DEF:
return class;
}
+
+/**
+ * mono_type_get_full:
+ * @image: the image where the type resides
+ * @type_token: the token for the type
+ * @context: the generic context used to evaluate generic instantiations in
+ *
+ * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
+ *
+ * Returns: the MonoType that represents @type_token in @image
+ */
+MonoType *
+mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
+{
+ MonoType *type = NULL;
+
+ //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
+ if (image->dynamic)
+ return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context));
+
+ if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
+ MonoClass *class = mono_class_get_full (image, type_token, context);
+ return class ? mono_class_get_type (class) : NULL;
+ }
+
+ type = mono_type_retrieve_from_typespec (image, type_token, context);
+
+ if (!type) {
+ char *name = mono_class_name_from_token (image, type_token);
+ char *assembly = mono_assembly_name_from_token (image, type_token);
+ mono_loader_set_error_type_load (name, assembly);
+ }
+
+ return type;
+}
+
+
MonoClass *
mono_class_get (MonoImage *image, guint32 type_token)
{
return FALSE;
}
+static gboolean
+mono_class_has_variant_generic_params (MonoClass *klass)
+{
+ int i;
+ MonoGenericContainer *container;
+
+ if (!klass->generic_class)
+ return FALSE;
+
+ container = klass->generic_class->container_class->generic_container;
+
+ for (i = 0; i < container->type_argc; ++i)
+ if (container->type_params [i].flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
+ return TRUE;
+
+ return FALSE;
+}
+
gboolean
mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
{
if (!oklass->inited)
mono_class_init (oklass);
+ if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
+ return klass == oklass;
+
if (MONO_CLASS_IS_INTERFACE (klass)) {
if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR))
return FALSE;
if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
return TRUE;
+
+ if (mono_class_has_variant_generic_params (klass)) {
+ if (oklass->generic_class) {
+ int i;
+ gboolean match = FALSE;
+ MonoClass *container_class1 = klass->generic_class->container_class;
+ MonoClass *container_class2 = oklass->generic_class->container_class;
+
+ /*
+ * Check whenever the generic definition of oklass implements the
+ * generic definition of klass. The IMPLEMENTS_INTERFACE stuff is not usable
+ * here since the relevant tables are not set up.
+ */
+ for (i = 0; i < container_class2->interface_offsets_count; ++i)
+ if ((container_class2->interfaces_packed [i] == container_class1) || (container_class2->interfaces_packed [i]->generic_class && (container_class2->interfaces_packed [i]->generic_class->container_class == container_class1)))
+ match = TRUE;
+
+ if (match) {
+ MonoGenericContainer *container;
+
+ container = klass->generic_class->container_class->generic_container;
+
+ match = TRUE;
+ for (i = 0; i < container->type_argc; ++i) {
+ MonoClass *param1_class = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [i]);
+ MonoClass *param2_class = mono_class_from_mono_type (oklass->generic_class->context.class_inst->type_argv [i]);
+
+ /*
+ * The _VARIANT and _COVARIANT constants should read _COVARIANT and
+ * _CONTRAVARIANT, but they are in a public header so we can't fix it.
+ */
+ if (param1_class != param2_class) {
+ if ((container->type_params [i].flags & MONO_GEN_PARAM_VARIANT) && mono_class_is_assignable_from (param1_class, param2_class))
+ ;
+ else if (((container->type_params [i].flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
+ ;
+ else
+ match = FALSE;
+ }
+ }
+
+ if (match)
+ return TRUE;
+ }
+ }
+ }
} else if (klass->rank) {
MonoClass *eclass, *eoclass;
{
if (image->dynamic) {
MonoClass *tmp_handle_class;
- gpointer obj = mono_lookup_dynamic_token_class (image, token, &tmp_handle_class);
+ gpointer obj = mono_lookup_dynamic_token_class (image, token, &tmp_handle_class, context);
g_assert (tmp_handle_class);
if (handle_class)
case MONO_TOKEN_TYPE_DEF:
case MONO_TOKEN_TYPE_REF:
case MONO_TOKEN_TYPE_SPEC: {
- MonoClass *class;
+ MonoType *type;
if (handle_class)
*handle_class = mono_defaults.typehandle_class;
- class = mono_class_get_full (image, token, context);
- if (!class)
+ type = mono_type_get_full (image, token, context);
+ if (!type)
return NULL;
- mono_class_init (class);
+ mono_class_init (mono_class_from_mono_type (type));
/* We return a MonoType* as handle */
- return &class->byval_arg;
+ return type;
}
case MONO_TOKEN_FIELD_DEF: {
MonoClass *class;
}
gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token)
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
{
MonoClass *handle_class;
- return lookup_dynamic (image, token, &handle_class);
+ return lookup_dynamic (image, token, &handle_class, context);
}
gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class, MonoGenericContext *context)
{
- return lookup_dynamic (image, token, handle_class);
+ return lookup_dynamic (image, token, handle_class, context);
}
static MonoGetCachedClassInfo get_cached_class_info = NULL;
g_free (astr);
return ex;
}
+ case MONO_EXCEPTION_MISSING_METHOD: {
+ char *class_name = klass->exception_data;
+ char *assembly_name = class_name + strlen (class_name) + 1;
+
+ return mono_get_exception_missing_method (class_name, assembly_name);
+ }
+ case MONO_EXCEPTION_MISSING_FIELD: {
+ char *class_name = klass->exception_data;
+ char *member_name = class_name + strlen (class_name) + 1;
+
+ return mono_get_exception_missing_field (class_name, member_name);
+ }
+ case MONO_EXCEPTION_FILE_NOT_FOUND: {
+ char *msg_format = klass->exception_data;
+ char *assembly_name = msg_format + strlen (msg_format) + 1;
+ char *msg = g_strdup_printf (msg_format, assembly_name);
+ MonoException *ex;
+
+ ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), assembly_name));
+
+ g_free (msg);
+
+ return ex;
+ }
default: {
MonoLoaderError *error;
MonoException *ex;
}
}
}
+
+static gboolean
+can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
+{
+ GSList *tmp;
+ if (accessing == accessed)
+ return TRUE;
+ if (!accessed || !accessing)
+ return FALSE;
+ for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
+ MonoAssemblyName *friend = tmp->data;
+ /* Be conservative with checks */
+ if (!friend->name)
+ continue;
+ if (strcmp (accessing->aname.name, friend->name))
+ continue;
+ if (friend->public_key_token [0]) {
+ if (!accessing->aname.public_key_token [0])
+ continue;
+ if (strcmp ((char*)friend->public_key_token, (char*)accessing->aname.public_key_token))
+ continue;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * If klass is a generic type or if it is derived from a generic type, return the
+ * MonoClass of the generic definition
+ * Returns NULL if not found
+ */
+static MonoClass*
+get_generic_definition_class (MonoClass *klass)
+{
+ while (klass) {
+ if (klass->generic_class && klass->generic_class->container_class)
+ return klass->generic_class->container_class;
+ klass = klass->parent;
+ }
+ return NULL;
+}
+
+/* FIXME: check visibility of type, too */
+static gboolean
+can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
+{
+ MonoClass *member_generic_def;
+ if (access_klass->generic_class && access_klass->generic_class->container_class &&
+ (member_generic_def = get_generic_definition_class (member_klass))) {
+ if (can_access_member (access_klass->generic_class->container_class,
+ member_generic_def, access_level))
+ return TRUE;
+ }
+
+ /* Partition I 8.5.3.2 */
+ /* the access level values are the same for fields and methods */
+ switch (access_level) {
+ case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
+ /* same compilation unit */
+ return access_klass->image == member_klass->image;
+ case FIELD_ATTRIBUTE_PRIVATE:
+ return access_klass == member_klass;
+ case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
+ if (mono_class_has_parent (access_klass, member_klass) &&
+ can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
+ return TRUE;
+ return FALSE;
+ case FIELD_ATTRIBUTE_ASSEMBLY:
+ return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+ case FIELD_ATTRIBUTE_FAMILY:
+ if (mono_class_has_parent (access_klass, member_klass))
+ return TRUE;
+ return FALSE;
+ case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
+ if (mono_class_has_parent (access_klass, member_klass))
+ return TRUE;
+ return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+ case FIELD_ATTRIBUTE_PUBLIC:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
+{
+ /* FIXME: check all overlapping fields */
+ int can = can_access_member (method->klass, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ if (!can) {
+ MonoClass *nested = method->klass->nested_in;
+ while (nested) {
+ can = can_access_member (nested, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ if (can)
+ return TRUE;
+ nested = nested->nested_in;
+ }
+ }
+ return can;
+}
+
+gboolean
+mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
+{
+ int can = can_access_member (method->klass, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ if (!can) {
+ MonoClass *nested = method->klass->nested_in;
+ while (nested) {
+ can = can_access_member (nested, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ if (can)
+ return TRUE;
+ nested = nested->nested_in;
+ }
+ }
+ /*
+ * FIXME:
+ * with generics calls to explicit interface implementations can be expressed
+ * directly: the method is private, but we must allow it. This may be opening
+ * a hole or the generics code should handle this differently.
+ * Maybe just ensure the interface type is public.
+ */
+ if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
+ return TRUE;
+ return can;
+}
+
+/**
+ * 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
+ */
+gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
+ switch (type->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * mono_class_is_valid_enum:
+ * @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)
+ */
+gboolean mono_class_is_valid_enum (MonoClass *klass) {
+ MonoClassField * field;
+ gpointer iter = NULL;
+ gboolean found_base_field = FALSE;
+
+ g_assert (klass->enumtype);
+ /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
+ if (!klass->parent || strcmp (klass->parent->name, "Enum") || strcmp (klass->parent->name_space, "System") ) {
+ return FALSE;
+ }
+
+ if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ return FALSE;
+
+ while ((field = mono_class_get_fields (klass, &iter))) {
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+ if (found_base_field)
+ return FALSE;
+ found_base_field = TRUE;
+ if (!mono_type_is_valid_enum_basetype (field->type))
+ return FALSE;
+ }
+ }
+
+ if (!found_base_field)
+ return FALSE;
+
+ if (klass->method.count > 0)
+ return FALSE;
+
+ return TRUE;
+}