#include <mono/metadata/security-core-clr.h>
#include <mono/metadata/attrdefs.h>
#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/verify-internals.h>
#include <mono/utils/mono-counters.h>
MonoStats mono_stats;
gboolean mono_print_vtable = FALSE;
+/*
+ * Controls whenever mono_class_init () constructs a generic vtable. This is TRUE by
+ * default to avoid breaking embedding apps, but set to FALSE by the runtime executable
+ * startup code.
+ */
+gboolean mono_setup_vtable_in_class_init = TRUE;
+
/* Function supplied by the runtime to find classes by name using information from the AOT file */
static MonoGetClassFromName get_class_from_name = NULL;
static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token);
static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
+static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
+static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
+static int generic_array_methods (MonoClass *class);
+static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos);
void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
MonoClass *enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx);
GList *tmp;
- if (enclosing->inited) {
+ if (enclosing->nested_classes_inited) {
/* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
for (tmp = enclosing->nested_classes; tmp; tmp = tmp->next) {
res = tmp->data;
i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
}
}
- g_warning ("TypeRef ResolutionScope not yet handled (%d)", idx);
+ g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
return NULL;
}
case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
return mono_class_from_name (image->references [idx - 1]->image, nspace, name);
}
+
+static void *
+mono_mempool_dup (MonoMemPool *mp, void *data, guint size)
+{
+ void *res = mono_mempool_alloc (mp, size);
+ memcpy (res, data, size);
+ return res;
+}
+
/* Copy everything mono_metadata_free_array free. */
MonoArrayType *
-mono_dup_array_type (MonoArrayType *a)
+mono_dup_array_type (MonoMemPool *mp, MonoArrayType *a)
{
- a = g_memdup (a, sizeof (MonoArrayType));
- if (a->sizes)
- a->sizes = g_memdup (a->sizes, a->numsizes * sizeof (int));
- if (a->lobounds)
- a->lobounds = g_memdup (a->lobounds, a->numlobounds * sizeof (int));
+ if (mp) {
+ mono_loader_lock ();
+ a = mono_mempool_dup (mp, a, sizeof (MonoArrayType));
+ if (a->sizes)
+ a->sizes = mono_mempool_dup (mp, a->sizes, a->numsizes * sizeof (int));
+ if (a->lobounds)
+ a->lobounds = mono_mempool_dup (mp, a->lobounds, a->numlobounds * sizeof (int));
+ mono_loader_unlock ();
+ } else {
+ a = g_memdup (a, sizeof (MonoArrayType));
+ if (a->sizes)
+ a->sizes = g_memdup (a->sizes, a->numsizes * sizeof (int));
+ if (a->lobounds)
+ a->lobounds = g_memdup (a->lobounds, a->numlobounds * sizeof (int));
+ }
return a;
}
/* Copy everything mono_metadata_free_method_signature free. */
MonoMethodSignature*
-mono_metadata_signature_deep_dup (MonoMethodSignature *sig)
+mono_metadata_signature_deep_dup (MonoMemPool *mp, MonoMethodSignature *sig)
{
int i;
- sig = mono_metadata_signature_dup (sig);
+ sig = mono_metadata_signature_dup_full (mp, sig);
- sig->ret = mono_metadata_type_dup (NULL, sig->ret);
+ sig->ret = mono_metadata_type_dup (mp, sig->ret);
for (i = 0; i < sig->param_count; ++i)
- sig->params [i] = mono_metadata_type_dup (NULL, sig->params [i]);
+ sig->params [i] = mono_metadata_type_dup (mp, sig->params [i]);
return sig;
}
}
static MonoType*
-inflate_generic_type (MonoType *type, MonoGenericContext *context)
+inflate_generic_type (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context)
{
switch (type->type) {
case MONO_TYPE_MVAR: {
* 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 = mono_metadata_type_dup (mempool, inst->type_argv [num]);
nt->byref = type->byref;
nt->attrs = type->attrs;
return nt;
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);
- nt = mono_metadata_type_dup (NULL, inst->type_argv [num]);
+ nt = mono_metadata_type_dup (mempool, 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);
+ MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
if (!inflated)
return NULL;
- nt = mono_metadata_type_dup (NULL, type);
+ nt = mono_metadata_type_dup (mempool, type);
nt->data.klass = mono_class_from_mono_type (inflated);
mono_metadata_free_type (inflated);
return nt;
}
case MONO_TYPE_ARRAY: {
MonoClass *eclass = type->data.array->eklass;
- MonoType *nt, *inflated = inflate_generic_type (&eclass->byval_arg, context);
+ MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context);
if (!inflated)
return NULL;
- nt = mono_metadata_type_dup (NULL, type);
+ nt = mono_metadata_type_dup (mempool, type);
nt->data.array = g_memdup (nt->data.array, sizeof (MonoArrayType));
nt->data.array->eklass = mono_class_from_mono_type (inflated);
mono_metadata_free_type (inflated);
if (gclass == type->data.generic_class)
return NULL;
- nt = mono_metadata_type_dup (NULL, type);
+ nt = mono_metadata_type_dup (mempool, type);
nt->data.generic_class = gclass;
return nt;
}
gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
- nt = mono_metadata_type_dup (NULL, type);
+ nt = mono_metadata_type_dup (mempool, type);
nt->type = MONO_TYPE_GENERICINST;
nt->data.generic_class = gclass;
return nt;
}
/*
- * mono_class_inflate_generic_type:
+ * mono_class_inflate_generic_type_with_mempool:
+ * @mempool: a mempool
* @type: a type
* @context: a generics context
*
- * Instantiate the generic type @type, using the generics context @context.
- *
- * Returns: the instantiated type. The returned MonoType is allocated on the heap and is
- * owned by the caller.
+ * The same as mono_class_inflate_generic_type, but allocates the MonoType
+ * from mempool if it is non-NULL. If it is NULL, the MonoType is
+ * allocated on the heap and is owned by the caller.
*/
MonoType*
-mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
+mono_class_inflate_generic_type_with_mempool (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context)
{
- MonoType *inflated = inflate_generic_type (type, context);
+ MonoType *inflated = NULL;
+
+ if (context)
+ inflated = inflate_generic_type (mempool, type, context);
if (!inflated)
- return mono_metadata_type_dup (NULL, type);
+ return mono_metadata_type_dup (mempool, type);
mono_stats.inflated_type_count++;
return inflated;
}
+/*
+ * mono_class_inflate_generic_type:
+ * @type: a type
+ * @context: a generics context
+ *
+ * If @type is a generic type and @context is not NULL, instantiate it using the
+ * generics context @context.
+ *
+ * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
+ * on the heap and is owned by the caller.
+ */
+MonoType*
+mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
+{
+ return mono_class_inflate_generic_type_with_mempool (NULL, type, context);
+}
+
+
static MonoGenericContext
inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with)
{
MonoMethodInflated *iresult, *cached;
MonoMethodSignature *sig;
MonoGenericContext tmp_context;
+ gboolean is_mb_open = FALSE;
/* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
while (method->is_inflated) {
method = imethod->declaring;
}
- if (!method->generic_container && !method->klass->generic_container)
+ if (!method->is_generic && !method->klass->generic_container)
return method;
- mono_stats.inflated_method_count++;
+ /*
+ * The reason for this hack is to fix the behavior of inflating generic methods that come from a MethodBuilder.
+ * What happens is that instantiating a generic MethodBuilder with its own arguments should create a diferent object.
+ * This is opposite to the way non-SRE MethodInfos behave.
+ *
+ * This happens, for example, when we want to emit a recursive generic method. Given the following C# code:
+ *
+ * void Example<T> () {
+ * Example<T> ();
+ * }
+ *
+ * In Example, the method token must be encoded as: "void Example<!!0>()"
+ *
+ * The reference to the first generic argument, "!!0", must be explicit otherwise it won't be inflated
+ * properly. To get that we need to inflate the MethodBuilder with its own arguments.
+ *
+ * On the other hand, inflating a non-SRE generic method with its own arguments should
+ * return itself. For example:
+ *
+ * MethodInfo m = ... //m is a generic method definition
+ * MethodInfo res = m.MakeGenericMethod (m.GetGenericArguments ());
+ * res == m
+ *
+ * To allow such scenarios we must allow inflation of MethodBuilder to happen in a diferent way than
+ * what happens with regular methods.
+ *
+ * There is one last touch to this madness, once a TypeBuilder is finished, IOW CreateType() is called,
+ * everything should behave like a regular type or method.
+ *
+ */
+ is_mb_open = method->is_generic &&
+ method->klass->image->dynamic && !method->klass->wastypebuilder && /* that is a MethodBuilder from an unfinished TypeBuilder */
+ context->method_inst == mono_method_get_generic_container (method)->context.method_inst; /* and it's been instantiated with its own arguments. */
+
iresult = g_new0 (MonoMethodInflated, 1);
iresult->context = *context;
iresult->declaring = method;
+ iresult->is_mb_open = is_mb_open;
- if (!context->method_inst && method->generic_container)
- iresult->context.method_inst = method->generic_container->context.method_inst;
+ if (!context->method_inst && method->is_generic)
+ iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
+
+ if (!context->class_inst) {
+ g_assert (!iresult->declaring->klass->generic_class);
+ if (iresult->declaring->klass->generic_container)
+ iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
+ else if (iresult->declaring->klass->generic_class)
+ iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
+ }
mono_loader_lock ();
cached = mono_method_inflated_lookup (iresult, FALSE);
return (MonoMethod*)cached;
}
+ mono_stats.inflated_method_count++;
+
sig = mono_method_signature (method);
if (sig->pinvoke) {
memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
}
result = (MonoMethod *) iresult;
- result->is_inflated = 1;
+ result->is_inflated = TRUE;
+ result->is_generic = FALSE;
result->signature = NULL;
- if (context->method_inst)
- result->generic_container = NULL;
+ if (!context->method_inst) {
+ /* Set the generic_container of the result to the generic_container of method */
+ MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
- /* Due to the memcpy above, !context->method_inst => result->generic_container == method->generic_container */
+ if (generic_container) {
+ result->is_generic = 1;
+ mono_method_set_generic_container (result, generic_container);
+ }
+ }
if (!klass_hint || !klass_hint->generic_class ||
klass_hint->generic_class->container_class != method->klass ||
result->klass = klass_hint;
if (!result->klass) {
- MonoType *inflated = inflate_generic_type (&method->klass->byval_arg, context);
+ MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context);
result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
if (inflated)
mono_metadata_free_type (inflated);
return &imethod->context;
}
+/*
+ * mono_method_get_generic_container:
+ *
+ * Returns the generic container of METHOD, which should be a generic method definition.
+ * Returns NULL if METHOD is not a generic method definition.
+ * LOCKING: Acquires the loader lock.
+ */
+MonoGenericContainer*
+mono_method_get_generic_container (MonoMethod *method)
+{
+ MonoGenericContainer *container;
+
+ if (!method->is_generic)
+ return NULL;
+
+ mono_loader_lock ();
+ container = mono_property_hash_lookup (method->klass->image->property_hash, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
+ mono_loader_unlock ();
+ g_assert (container);
+
+ return container;
+}
+
+/*
+ * mono_method_set_generic_container:
+ *
+ * Sets the generic container of METHOD to CONTAINER.
+ * LOCKING: Acquires the loader lock.
+ */
+void
+mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
+{
+ g_assert (method->is_generic);
+
+ mono_loader_lock ();
+ mono_property_hash_insert (method->klass->image->property_hash, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
+ mono_loader_unlock ();
+}
+
/**
* mono_class_find_enum_basetype:
* @class: The enum class
if (!ftype)
return NULL;
if (class->generic_class) {
+ //FIXME do we leak here?
ftype = mono_class_inflate_generic_type (ftype, mono_class_get_context (class));
ftype->attrs = cols [MONO_FIELD_FLAGS];
}
if (class->size_inited)
return;
+ if (class->generic_class && class->generic_class->container_class->image->dynamic && !class->generic_class->container_class->wastypebuilder) {
+ /*
+ * This happens when a generic instance of an unfinished generic typebuilder
+ * is used as an element type for creating an array type. We can't initialize
+ * the fields of this class using the fields of gklass, since gklass is not
+ * finished yet, fields could be added to it later.
+ */
+ return;
+ }
+
if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
mono_class_setup_fields (gklass);
/* Prevent infinite loops if the class references itself */
class->size_inited = 1;
- class->fields = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassField) * top);
+ class->fields = mono_image_alloc0 (class->image, sizeof (MonoClassField) * top);
if (class->generic_container) {
container = class->generic_container;
ifield->generic_type = gfield->type;
field->name = gfield->name;
field->generic_info = ifield;
- field->type = mono_class_inflate_generic_type (gfield->type, mono_class_get_context (class));
+ /*This memory must come from the image mempool as we don't have a chance to free it.*/
+ field->type = mono_class_inflate_generic_type_with_mempool (class->image->mempool, gfield->type, mono_class_get_context (class));
field->type->attrs = gfield->type->attrs;
if (mono_field_is_deleted (field))
continue;
blittable = FALSE;
} else {
MonoClass *field_class = mono_class_from_mono_type (field->type);
+ if (field_class)
+ mono_class_setup_fields (field_class);
if (!field_class || !field_class->blittable)
blittable = FALSE;
}
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.
+ * 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));
}
-#endif
class->size_inited = 1;
}
}
+static MonoMethod*
+create_array_method (MonoClass *class, const char *name, MonoMethodSignature *sig)
+{
+ MonoMethod *method;
+
+ method = (MonoMethod *) mono_image_alloc0 (class->image, sizeof (MonoMethodPInvoke));
+ method->klass = class;
+ method->flags = METHOD_ATTRIBUTE_PUBLIC;
+ method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
+ method->signature = sig;
+ method->name = name;
+ method->slot = -1;
+ /* .ctor */
+ if (name [0] == '.') {
+ method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
+ } else {
+ method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
+ }
+ return method;
+}
+
/*
* mono_class_setup_methods:
* @class: a class
methods [i] = mono_class_inflate_generic_method_full (
gklass->methods [i], class, mono_class_get_context (class));
}
+ } else if (class->rank) {
+ MonoMethod *amethod;
+ MonoMethodSignature *sig;
+ int count_generic = 0, first_generic = 0;
+ int method_num = 0;
+
+ class->method.count = 3 + (class->rank > 1? 2: 1);
+
+ if (class->interface_count) {
+ count_generic = generic_array_methods (class);
+ first_generic = class->method.count;
+ class->method.count += class->interface_count * count_generic;
+ }
+
+ methods = mono_image_alloc0 (class->image, sizeof (MonoMethod*) * class->method.count);
+
+ sig = mono_metadata_signature_alloc (class->image, class->rank);
+ sig->ret = &mono_defaults.void_class->byval_arg;
+ sig->pinvoke = TRUE;
+ sig->hasthis = TRUE;
+ for (i = 0; i < class->rank; ++i)
+ sig->params [i] = &mono_defaults.int32_class->byval_arg;
+
+ amethod = create_array_method (class, ".ctor", sig);
+ methods [method_num++] = amethod;
+ if (class->rank > 1) {
+ sig = mono_metadata_signature_alloc (class->image, class->rank * 2);
+ sig->ret = &mono_defaults.void_class->byval_arg;
+ sig->pinvoke = TRUE;
+ sig->hasthis = TRUE;
+ for (i = 0; i < class->rank * 2; ++i)
+ sig->params [i] = &mono_defaults.int32_class->byval_arg;
+
+ amethod = create_array_method (class, ".ctor", sig);
+ methods [method_num++] = amethod;
+ }
+ /* element Get (idx11, [idx2, ...]) */
+ sig = mono_metadata_signature_alloc (class->image, class->rank);
+ sig->ret = &class->element_class->byval_arg;
+ sig->pinvoke = TRUE;
+ sig->hasthis = TRUE;
+ for (i = 0; i < class->rank; ++i)
+ sig->params [i] = &mono_defaults.int32_class->byval_arg;
+ amethod = create_array_method (class, "Get", sig);
+ methods [method_num++] = amethod;
+ /* element& Address (idx11, [idx2, ...]) */
+ sig = mono_metadata_signature_alloc (class->image, class->rank);
+ sig->ret = &class->element_class->this_arg;
+ sig->pinvoke = TRUE;
+ sig->hasthis = TRUE;
+ for (i = 0; i < class->rank; ++i)
+ sig->params [i] = &mono_defaults.int32_class->byval_arg;
+ amethod = create_array_method (class, "Address", sig);
+ methods [method_num++] = amethod;
+ /* void Set (idx11, [idx2, ...], element) */
+ sig = mono_metadata_signature_alloc (class->image, class->rank + 1);
+ sig->ret = &mono_defaults.void_class->byval_arg;
+ sig->pinvoke = TRUE;
+ sig->hasthis = TRUE;
+ for (i = 0; i < class->rank; ++i)
+ sig->params [i] = &mono_defaults.int32_class->byval_arg;
+ sig->params [i] = &class->element_class->byval_arg;
+ amethod = create_array_method (class, "Set", sig);
+ methods [method_num++] = amethod;
+
+ for (i = 0; i < class->interface_count; i++)
+ setup_generic_array_ifaces (class, class->interfaces [i], methods, first_generic + i * count_generic);
} else {
- methods = mono_mempool_alloc (class->image->mempool, sizeof (MonoMethod*) * class->method.count);
+ methods = mono_image_alloc (class->image, sizeof (MonoMethod*) * class->method.count);
for (i = 0; i < class->method.count; ++i) {
int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1);
methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class);
- if (class->valuetype && methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !(methods [i]->flags & MONO_METHOD_ATTR_STATIC))
- mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
}
}
for (i = 0; i < class->method.count; ++i)
methods [i]->slot = i;
- /* Leave this assignment as the last op in this function */
+ /* Needed because of the double-checking locking pattern */
+ mono_memory_barrier ();
+
class->methods = methods;
if (mono_debugger_class_loaded_methods_func)
mono_loader_unlock ();
}
+/*
+ * mono_class_get_method_by_index:
+ *
+ * Returns class->methods [index], initializing class->methods if neccesary.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
+MonoMethod*
+mono_class_get_method_by_index (MonoClass *class, int index)
+{
+ /* Avoid calling setup_methods () if possible */
+ if (class->generic_class && !class->methods) {
+ MonoClass *gklass = class->generic_class->container_class;
+ MonoMethod *m;
+
+ m = mono_class_inflate_generic_method_full (
+ gklass->methods [index], class, mono_class_get_context (class));
+ /*
+ * If setup_methods () is called later for this class, no duplicates are created,
+ * since inflate_generic_method guarantees that only one instance of a method
+ * is created for each context.
+ */
+ /*
+ mono_class_setup_methods (class);
+ g_assert (m == class->methods [index]);
+ */
+ return m;
+ } else {
+ mono_class_setup_methods (class);
+ g_assert (index >= 0 && index < class->method.count);
+ return class->methods [index];
+ }
+}
static void
mono_class_setup_properties (MonoClass *class)
if (class->property.count)
mono_class_setup_methods (class);
- properties = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoProperty) * class->property.count);
+ properties = mono_image_alloc0 (class->image, sizeof (MonoProperty) * class->property.count);
for (i = class->property.first; i < last; ++i) {
mono_metadata_decode_table_row (class->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
properties [i - class->property.first].parent = class;
}
}
}
+ /*Flush any pending writes as we do double checked locking on class->properties */
+ mono_memory_barrier ();
/* Leave this assignment as the last op in the function */
class->properties = properties;
if (class->event.count)
mono_class_setup_methods (class);
- events = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoEvent) * class->event.count);
+ events = mono_image_alloc0 (class->image, sizeof (MonoEvent) * class->event.count);
for (i = class->event.first; i < last; ++i) {
MonoEvent *event = &events [i - class->event.first];
}
}
}
+ /*Flush any pending writes as we do double checked locking on class->properties */
+ mono_memory_barrier ();
+
/* Leave this assignment as the last op in the function */
class->events = events;
return res;
}
-typedef struct _IOffsetInfo IOffsetInfo;
-struct _IOffsetInfo {
- IOffsetInfo *next;
- int size;
- int next_free;
- int data [MONO_ZERO_LEN_ARRAY];
-};
-
-static IOffsetInfo *cached_offset_info = NULL;
-static int next_offset_info_size = 128;
-
-static int*
-cache_interface_offsets (int max_iid, int *data)
-{
- IOffsetInfo *cached_info;
- int *cached;
- int new_size;
- for (cached_info = cached_offset_info; cached_info; cached_info = cached_info->next) {
- cached = cached_info->data;
- while (cached < cached_info->data + cached_info->size && *cached) {
- if (*cached == max_iid) {
- int i, matched = TRUE;
- cached++;
- for (i = 0; i < max_iid; ++i) {
- if (cached [i] != data [i]) {
- matched = FALSE;
- break;
- }
- }
- if (matched)
- return cached;
- cached += max_iid;
- } else {
- cached += *cached + 1;
- }
- }
- }
- /* find a free slot */
- for (cached_info = cached_offset_info; cached_info; cached_info = cached_info->next) {
- if (cached_info->size - cached_info->next_free >= max_iid + 1) {
- cached = &cached_info->data [cached_info->next_free];
- *cached++ = max_iid;
- memcpy (cached, data, max_iid * sizeof (int));
- cached_info->next_free += max_iid + 1;
- return cached;
- }
- }
- /* allocate a new chunk */
- if (max_iid + 1 < next_offset_info_size) {
- new_size = next_offset_info_size;
- if (next_offset_info_size < 4096)
- next_offset_info_size += next_offset_info_size >> 2;
- } else {
- new_size = max_iid + 1;
- }
- cached_info = g_malloc0 (sizeof (IOffsetInfo) + sizeof (int) * new_size);
- cached_info->size = new_size;
- /*g_print ("allocated %d offset entries at %p (total: %d)\n", new_size, cached_info->data, offset_info_total_size);*/
- cached = &cached_info->data [0];
- *cached++ = max_iid;
- memcpy (cached, data, max_iid * sizeof (int));
- cached_info->next_free += max_iid + 1;
- cached_info->next = cached_offset_info;
- cached_offset_info = cached_info;
- return cached;
-}
-
static int
compare_interface_ids (const void *p_key, const void *p_element) {
const MonoClass *key = p_key;
"System.Collections.Generic", "IEnumerator`1");
}
+ mono_class_init (eclass);
+
/*
* Arrays in 2.0 need to implement a number of generic interfaces
* (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
/*
* get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
- * implicit innterfaces have the property that they are assigned the same slot in the vtables
- * for compatible interfaces
+ * implicit interfaces have the property that they are assigned the same slot in the
+ * vtables for compatible interfaces
*/
array_interfaces = get_implicit_generic_array_interfaces (class, &num_array_interfaces, &is_enumerator);
interface_offsets_count ++;
}
}
- class->interface_offsets_count = interface_offsets_count;
- 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));
- class->interfaces_packed [interface_offsets_count] = interfaces_full [i];
- class->interface_offsets_packed [interface_offsets_count] = interface_offsets_full [i];
- /*if (num_array_interfaces)
- g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&class->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/
- interface_offsets_count ++;
+
+ /*
+ * We might get called twice: once from mono_class_init () then once from
+ * mono_class_setup_vtable ().
+ */
+ if (class->interfaces_packed) {
+ g_assert (class->interface_offsets_count == interface_offsets_count);
+ } else {
+ class->interface_offsets_count = interface_offsets_count;
+ class->interfaces_packed = mono_image_alloc (class->image, sizeof (MonoClass*) * interface_offsets_count);
+ class->interface_offsets_packed = mono_image_alloc (class->image, sizeof (guint16) * interface_offsets_count);
+ class->interface_bitmap = mono_image_alloc0 (class->image, (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));
+ class->interfaces_packed [interface_offsets_count] = interfaces_full [i];
+ class->interface_offsets_packed [interface_offsets_count] = interface_offsets_full [i];
+ /*if (num_array_interfaces)
+ g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&class->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/
+ interface_offsets_count ++;
+ }
}
}
mono_loader_unlock ();
}
-
+
+/*
+ * mono_class_setup_vtable:
+ *
+ * Creates the generic vtable of CLASS.
+ * Initializes the following fields in MonoClass:
+ * - vtable
+ * - vtable_size
+ * Plus all the fields initialized by setup_interface_offsets ().
+ * If there is an error during vtable construction, class->exception_type is set.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
void
mono_class_setup_vtable (MonoClass *class)
{
if (class->vtable)
return;
+ /* This sets method->slot for all methods if this is an interface */
mono_class_setup_methods (class);
if (MONO_CLASS_IS_INTERFACE (class))
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;
- }
+ if (override_level != base_level && base_level == MONO_SECURITY_CORE_CLR_CRITICAL)
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
}
int im_slot = ic_offset + im->slot;
MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
+ if (im->flags & METHOD_ATTRIBUTE_STATIC)
+ continue;
+
// If there is an explicit implementation, just use it right away,
// otherwise look for a matching method
if (override_im == NULL) {
MonoMethod *im = ic->methods [im_index];
int im_slot = ic_offset + im->slot;
+ if (im->flags & METHOD_ATTRIBUTE_STATIC)
+ continue;
+
TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
if (vtable [im_slot] == NULL) {
mono_class_init (gklass);
class->vtable_size = MAX (gklass->vtable_size, cur_slot);
- } else
+ } else {
+ /* Check that the vtable_size value computed in mono_class_init () is correct */
+ if (class->vtable_size)
+ g_assert (cur_slot == class->vtable_size);
class->vtable_size = cur_slot;
+ }
/* Try to share the vtable with our parent. */
if (class->parent && (class->parent->vtable_size == class->vtable_size) && (memcmp (class->parent->vtable, vtable, sizeof (gpointer) * class->vtable_size) == 0)) {
+ mono_memory_barrier ();
class->vtable = class->parent->vtable;
} else {
- class->vtable = mono_mempool_alloc0 (class->image->mempool, sizeof (gpointer) * class->vtable_size);
- memcpy (class->vtable, vtable, sizeof (gpointer) * class->vtable_size);
+ MonoMethod **tmp = mono_image_alloc0 (class->image, sizeof (gpointer) * class->vtable_size);
+ memcpy (tmp, vtable, sizeof (gpointer) * class->vtable_size);
+ mono_memory_barrier ();
+ class->vtable = tmp;
}
DEBUG_INTERFACE_VTABLE (print_vtable_full (class, class->vtable, class->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
g_assert_not_reached ();
}
- name = mono_mempool_alloc (mono_defaults.corlib->mempool, strlen (iname) + strlen (mname) + 1);
+ name = mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
strcpy (name, iname);
strcpy (name + strlen (iname), mname);
generic_array_method_info [i].name = name;
}
static void
-setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos)
+setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos)
{
MonoGenericContext tmp_context;
int i;
MonoMethod *inflated;
inflated = mono_class_inflate_generic_method (m, &tmp_context);
- class->methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated);
- }
-}
-
-static MonoMethod*
-create_array_method (MonoClass *class, const char *name, MonoMethodSignature *sig)
-{
- MonoMethod *method;
-
- method = (MonoMethod *) mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethodPInvoke));
- method->klass = class;
- method->flags = METHOD_ATTRIBUTE_PUBLIC;
- method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
- method->signature = sig;
- method->name = name;
- method->slot = -1;
- /* .ctor */
- if (name [0] == '.') {
- method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
- } else {
- method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
+ methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated);
}
- return method;
}
static char*
-concat_two_strings_with_zero (MonoMemPool *pool, const char *s1, const char *s2)
+concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
{
int len = strlen (s1) + strlen (s2) + 2;
- char *s = mono_mempool_alloc (pool, len);
+ char *s = mono_image_alloc (image, len);
int result;
result = g_snprintf (s, len, "%s%c%s", s1, '\0', s2);
static void
set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
{
- class->exception_type = error->exception_type;
+ gpointer exception_data = NULL;
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);
+ exception_data = concat_two_strings_with_zero (class->image, 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);
+ exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->member_name);
break;
case MONO_EXCEPTION_MISSING_FIELD: {
else
class_name = error->klass->name;
- class->exception_data = concat_two_strings_with_zero (class->image->mempool, class_name, error->member_name);
+ exception_data = concat_two_strings_with_zero (class->image, class_name, error->member_name);
if (name_space)
g_free ((void*)class_name);
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);
+ exception_data = concat_two_strings_with_zero (class->image, msg, error->assembly_name);
break;
}
case MONO_EXCEPTION_BAD_IMAGE:
- class->exception_data = error->msg;
+ exception_data = error->msg;
break;
default :
g_assert_not_reached ();
}
+
+ mono_class_set_failure (class, error->exception_type, exception_data);
}
static void
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;
- }
+ if (class_level < parent_level)
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
}
/**
* mono_class_init:
* @class: the class to initialize
*
- * compute the instance_size, class_size and other infos that cannot be
- * computed at mono_class_get() time. Also compute a generic vtable and
- * the method slot numbers. We use this infos later to create a domain
- * specific vtable.
- *
+ * 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).
+ *
+ * LOCKING: Acquires the loader lock.
*/
gboolean
mono_class_init (MonoClass *class)
g_assert (class);
+ /* Double-checking locking pattern */
if (class->inited)
return class->exception_type == MONO_EXCEPTION_NONE;
has_cached_info = mono_class_get_cached_class_info (class, &cached_info);
- 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;
- guint32 cols [MONO_NESTED_CLASS_SIZE];
- mono_metadata_decode_row (&class->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
- nclass = mono_class_create_from_typedef (class->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
- class->nested_classes = g_list_prepend_mempool (class->nested_classes, class->image->mempool, nclass);
-
- i = mono_metadata_nesting_typedef (class->image, class->type_token, i + 1);
- }
- }
+ if (class->generic_class || class->image->dynamic || !class->type_token || (has_cached_info && !cached_info.has_nested_classes))
+ class->nested_classes_inited = TRUE;
/*
* Computes the size used by the fields, and their locations
}
}
-
- /* initialize method pointers */
+ /* Initialize arrays */
if (class->rank) {
- MonoMethod *amethod;
- MonoMethodSignature *sig;
- int count_generic = 0, first_generic = 0;
- int method_num = 0;
-
class->method.count = 3 + (class->rank > 1? 2: 1);
if (class->interface_count) {
- count_generic = generic_array_methods (class);
- first_generic = class->method.count;
+ int count_generic = generic_array_methods (class);
class->method.count += class->interface_count * count_generic;
}
+ }
- sig = mono_metadata_signature_alloc (class->image, class->rank);
- sig->ret = &mono_defaults.void_class->byval_arg;
- sig->pinvoke = TRUE;
- sig->hasthis = TRUE;
- for (i = 0; i < class->rank; ++i)
- sig->params [i] = &mono_defaults.int32_class->byval_arg;
-
- amethod = create_array_method (class, ".ctor", sig);
- class->methods = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethod*) * class->method.count);
- class->methods [method_num++] = amethod;
- if (class->rank > 1) {
- sig = mono_metadata_signature_alloc (class->image, class->rank * 2);
- sig->ret = &mono_defaults.void_class->byval_arg;
- sig->pinvoke = TRUE;
- sig->hasthis = TRUE;
- for (i = 0; i < class->rank * 2; ++i)
- sig->params [i] = &mono_defaults.int32_class->byval_arg;
-
- amethod = create_array_method (class, ".ctor", sig);
- class->methods [method_num++] = amethod;
- }
- /* element Get (idx11, [idx2, ...]) */
- sig = mono_metadata_signature_alloc (class->image, class->rank);
- sig->ret = &class->element_class->byval_arg;
- sig->pinvoke = TRUE;
- sig->hasthis = TRUE;
- for (i = 0; i < class->rank; ++i)
- sig->params [i] = &mono_defaults.int32_class->byval_arg;
- amethod = create_array_method (class, "Get", sig);
- class->methods [method_num++] = amethod;
- /* element& Address (idx11, [idx2, ...]) */
- sig = mono_metadata_signature_alloc (class->image, class->rank);
- sig->ret = &class->element_class->this_arg;
- sig->pinvoke = TRUE;
- sig->hasthis = TRUE;
- for (i = 0; i < class->rank; ++i)
- sig->params [i] = &mono_defaults.int32_class->byval_arg;
- amethod = create_array_method (class, "Address", sig);
- class->methods [method_num++] = amethod;
- /* void Set (idx11, [idx2, ...], element) */
- sig = mono_metadata_signature_alloc (class->image, class->rank + 1);
- sig->ret = &mono_defaults.void_class->byval_arg;
- sig->pinvoke = TRUE;
- sig->hasthis = TRUE;
- for (i = 0; i < class->rank; ++i)
- sig->params [i] = &mono_defaults.int32_class->byval_arg;
- sig->params [i] = &class->element_class->byval_arg;
- amethod = create_array_method (class, "Set", sig);
- class->methods [method_num++] = amethod;
-
- for (i = 0; i < class->interface_count; i++)
- setup_generic_array_ifaces (class, class->interfaces [i], first_generic + i * count_generic);
- }
-
- mono_class_setup_supertypes (class);
+ mono_class_setup_supertypes (class);
if (!default_ghc)
initialize_object_slots (class);
- /*
- * If possible, avoid the creation of the generic vtable by requesting
- * cached info from the runtime.
+ /*
+ * Initialize the rest of the data without creating a generic vtable if possible.
+ * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
+ * also avoid computing a generic vtable.
*/
if (has_cached_info) {
- guint32 cur_slot = 0;
-
+ /* AOT case */
class->vtable_size = cached_info.vtable_size;
class->has_finalize = cached_info.has_finalize;
class->ghcimpl = cached_info.ghcimpl;
class->has_cctor = cached_info.has_cctor;
+ } else if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) {
+ static int szarray_vtable_size = 0;
- if (class->parent) {
- mono_class_init (class->parent);
- cur_slot = class->parent->vtable_size;
+ /* SZARRAY case */
+ if (!szarray_vtable_size) {
+ mono_class_setup_vtable (class);
+ szarray_vtable_size = class->vtable_size;
+ } else {
+ class->vtable_size = szarray_vtable_size;
}
+ } else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) {
+ MonoClass *gklass = class->generic_class->container_class;
- setup_interface_offsets (class, cur_slot);
- }
- else {
- mono_class_setup_vtable (class);
+ /* Generic instance case */
+ class->ghcimpl = gklass->ghcimpl;
+ class->has_finalize = gklass->has_finalize;
+ class->has_cctor = gklass->has_cctor;
- if (class->exception_type || mono_loader_get_last_error ()){
- class_init_ok = FALSE;
- goto leave;
- }
+ mono_class_setup_vtable (gklass);
+ if (gklass->exception_type)
+ goto fail;
+
+ class->vtable_size = gklass->vtable_size;
+ } else {
+ /* General case */
+ /* ghcimpl is not currently used
class->ghcimpl = 1;
if (class->parent) {
MonoMethod *cmethod = class->vtable [ghc_slot];
class->ghcimpl = 0;
}
}
+ */
+
+ /* Interfaces and valuetypes are not supposed to have finalizers */
+ if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
+ MonoMethod *cmethod = NULL;
+
+ if (class->type_token) {
+ cmethod = find_method_in_metadata (class, "Finalize", 0, METHOD_ATTRIBUTE_VIRTUAL);
+ } else if (class->parent) {
+ /* FIXME: Optimize this */
+ mono_class_setup_vtable (class);
+ if (class->exception_type || mono_loader_get_last_error ())
+ goto fail;
+ cmethod = class->vtable [finalize_slot];
+ }
- /* Object::Finalize should have empty implemenatation */
- class->has_finalize = 0;
- if (class->parent) {
- MonoMethod *cmethod = class->vtable [finalize_slot];
- if (cmethod->is_inflated)
- cmethod = ((MonoMethodInflated*)cmethod)->declaring;
- if (cmethod != default_finalize) {
- class->has_finalize = 1;
+ if (cmethod) {
+ /* Check that this is really the finalizer method */
+ mono_class_setup_vtable (class);
+ if (class->exception_type || mono_loader_get_last_error ())
+ goto fail;
+
+ class->has_finalize = 0;
+ if (class->parent) {
+ cmethod = class->vtable [finalize_slot];
+ if (cmethod->is_inflated)
+ cmethod = ((MonoMethodInflated*)cmethod)->declaring;
+ if (cmethod != default_finalize) {
+ class->has_finalize = 1;
+ }
+ }
}
}
- for (i = 0; i < class->method.count; ++i) {
- MonoMethod *method = class->methods [i];
- if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
- (strcmp (".cctor", method->name) == 0)) {
- class->has_cctor = 1;
- break;
+ /* C# doesn't allow interfaces to have cctors */
+ if (!MONO_CLASS_IS_INTERFACE (class) || class->image != mono_defaults.corlib) {
+ MonoMethod *cmethod = NULL;
+
+ if (class->type_token) {
+ cmethod = find_method_in_metadata (class, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
+ /* The find_method function ignores the 'flags' argument */
+ if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
+ class->has_cctor = 1;
+ } else {
+ mono_class_setup_methods (class);
+
+ for (i = 0; i < class->method.count; ++i) {
+ MonoMethod *method = class->methods [i];
+ if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
+ (strcmp (".cctor", method->name) == 0)) {
+ class->has_cctor = 1;
+ break;
+ }
+ }
}
}
}
- if (MONO_CLASS_IS_INTERFACE (class)) {
- /*
- * knowledge of interface offsets is needed for the castclass/isinst code, so
- * we have to setup them for interfaces, too.
+ if (!mono_setup_vtable_in_class_init) {
+ /*
+ * This is an embedding API break, since the caller might assume that
+ * mono_class_init () constructs a generic vtable, so vtable construction errors
+ * are visible right after the mono_class_init (), and not after
+ * mono_class_vtable ().
*/
- setup_interface_offsets (class, 0);
+ if (class->parent) {
+ /* This will compute class->parent->vtable_size for some classes */
+ mono_class_init (class->parent);
+ if (class->parent->exception_type || mono_loader_get_last_error ())
+ goto fail;
+ if (!class->parent->vtable_size) {
+ /* FIXME: Get rid of this somehow */
+ mono_class_setup_vtable (class->parent);
+ if (class->parent->exception_type || mono_loader_get_last_error ())
+ goto fail;
+ }
+ setup_interface_offsets (class, class->parent->vtable_size);
+ } else {
+ setup_interface_offsets (class, 0);
+ }
+ } else {
+ mono_class_setup_vtable (class);
+
+ if (MONO_CLASS_IS_INTERFACE (class))
+ setup_interface_offsets (class, 0);
+ }
+
+ if (mono_verifier_is_enabled_for_class (class) && !mono_verifier_verify_class (class)) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (class->image, class->name, class->image->assembly_name));
+ class_init_ok = FALSE;
}
+ goto leave;
+
+ fail:
+ class_init_ok = FALSE;
+
leave:
+ /* Because of the double-checking locking pattern */
+ mono_memory_barrier ();
class->inited = 1;
class->init_pending = 0;
return class_init_ok;
}
+static gboolean
+is_corlib_image (MonoImage *image)
+{
+ /* FIXME: allow the dynamic case for our compilers and with full trust */
+ if (image->dynamic)
+ return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib");
+ else
+ return image == mono_defaults.corlib;
+}
+
/*
* LOCKING: this assumes the loader lock is held
*/
{
const char *name = class->name;
const char *nspace = class->name_space;
+ gboolean is_corlib = is_corlib_image (class->image);
class->this_arg.byref = 1;
class->this_arg.data.klass = class;
class->byval_arg.data.klass = class;
class->byval_arg.type = MONO_TYPE_CLASS;
- if (!strcmp (nspace, "System")) {
+ if (is_corlib && !strcmp (nspace, "System")) {
if (!strcmp (name, "ValueType")) {
/*
* do not set the valuetype bit for System.ValueType.
class->this_arg.type = class->byval_arg.type = MONO_TYPE_TYPEDBYREF;
}
}
-
+
if (class->valuetype) {
int t = MONO_TYPE_VALUETYPE;
- if (!strcmp (nspace, "System")) {
+
+ if (is_corlib && !strcmp (nspace, "System")) {
switch (*name) {
case 'B':
if (!strcmp (name, "Boolean")) {
mono_class_setup_parent (MonoClass *class, MonoClass *parent)
{
gboolean system_namespace;
+ gboolean is_corlib = is_corlib_image (class->image);
- system_namespace = !strcmp (class->name_space, "System");
+ system_namespace = !strcmp (class->name_space, "System") && is_corlib;
/* if root of the hierarchy */
if (system_namespace && !strcmp (class->name, "Object")) {
if (parent == mono_defaults.object_class)
parent = mono_defaults.com_object_class;
}
- class->parent = parent;
-
+ if (!parent) {
+ /* set the parent to something useful and safe, but mark the type as broken */
+ parent = mono_defaults.object_class;
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ }
- if (!parent)
- g_assert_not_reached (); /* FIXME */
+ class->parent = parent;
if (parent->generic_class && !parent->name) {
/*
class->delegate = 1;
}
- if (class->parent->enumtype || ((strcmp (class->parent->name, "ValueType") == 0) &&
+ if (class->parent->enumtype || (is_corlib_image (class->parent->image) && (strcmp (class->parent->name, "ValueType") == 0) &&
(strcmp (class->parent->name_space, "System") == 0)))
class->valuetype = 1;
- if (((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) {
+ if (is_corlib_image (class->parent->image) && ((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) {
class->valuetype = class->enumtype = 1;
}
/*class->enumtype = class->parent->enumtype; */
class->idepth = 1;
ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth);
- class->supertypes = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClass *) * ms);
+ class->supertypes = mono_image_alloc0 (class->image, sizeof (MonoClass *) * ms);
if (class->parent) {
class->supertypes [class->idepth - 1] = class;
name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
- class = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+ class = mono_image_alloc0 (image, sizeof (MonoClass));
class->name = name;
class->name_space = nspace;
}
}
- if (MONO_CLASS_IS_INTERFACE (klass))
- setup_interface_offsets (klass, 0);
-
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
mono_loader_unlock ();
/* FIXME: */
image = mono_defaults.corlib;
- klass = param->pklass = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+ klass = param->pklass = mono_image_alloc0 (image, sizeof (MonoClass));
if (param->name)
klass->name = param->name;
else {
- klass->name = mono_mempool_alloc0 (image->mempool, 16);
+ klass->name = mono_image_alloc0 (image, 16);
sprintf ((char*)klass->name, is_mvar ? "!!%d" : "!%d", param->num);
}
klass->name_space = "";
if (count - pos > 0) {
klass->interface_count = count - pos;
- klass->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass *) * (count - pos));
+ klass->interfaces = mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos));
for (i = pos; i < count; i++)
klass->interfaces [i - pos] = param->constraints [i];
}
klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param;
klass->this_arg.byref = TRUE;
+ if (param->owner) {
+ guint32 owner;
+ guint32 cols [MONO_GENERICPARAM_SIZE];
+ MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM];
+ i = 0;
+
+ if (is_mvar && param->owner->owner.method)
+ i = mono_metadata_get_generic_param_row (image, param->owner->owner.method->token, &owner);
+ else if (!is_mvar && param->owner->owner.klass)
+ i = mono_metadata_get_generic_param_row (image, param->owner->owner.klass->type_token, &owner);
+
+ if (i) {
+ mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
+ do {
+ if (cols [MONO_GENERICPARAM_NUMBER] == param->num) {
+ klass->sizes.generic_param_token = i | MONO_TOKEN_GENERIC_PARAM;
+ break;
+ }
+ if (++i > tdef->rows)
+ break;
+ mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
+ } while (cols [MONO_GENERICPARAM_OWNER] == owner);
+ }
+ }
+
mono_class_setup_supertypes (klass);
mono_loader_unlock ();
mono_loader_unlock ();
return result;
}
- result = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+ result = mono_image_alloc0 (image, sizeof (MonoClass));
result->parent = NULL; /* no parent for PTR types */
result->name_space = el_class->name_space;
name = g_strdup_printf ("%s*", el_class->name);
- result->name = mono_mempool_strdup (image->mempool, name);
+ result->name = mono_image_strdup (image, name);
g_free (name);
mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
* @context: the generic context used to evaluate generic instantiations in
*/
static MonoType *
-mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
+mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate)
{
MonoType *t = mono_type_create_from_typespec (image, type_spec);
if (!t)
return NULL;
if (context && (context->class_inst || context->method_inst)) {
- MonoType *inflated = inflate_generic_type (t, context);
- if (inflated)
+ MonoType *inflated = inflate_generic_type (NULL, t, context);
+ if (inflated) {
t = inflated;
+ *did_inflate = TRUE;
+ }
}
return t;
}
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);
+ MonoClass *ret;
+ gboolean inflated = FALSE;
+ MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated);
if (!t)
return NULL;
- return mono_class_from_mono_type (t);
+ ret = mono_class_from_mono_type (t);
+ if (inflated)
+ mono_metadata_free_type (t);
+ return ret;
}
/**
mono_class_init (parent);
}
- class = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+ class = mono_image_alloc0 (image, sizeof (MonoClass));
class->image = image;
class->name_space = eclass->name_space;
nsize = strlen (eclass->name);
- name = g_malloc (nsize + 2 + rank);
+ name = g_malloc (nsize + 2 + rank + 1);
memcpy (name, eclass->name, nsize);
name [nsize] = '[';
if (rank > 1)
memset (name + nsize + 1, ',', rank - 1);
- name [nsize + rank] = ']';
- name [nsize + rank + 1] = 0;
- class->name = mono_mempool_strdup (image->mempool, name);
+ if (bounded)
+ name [nsize + rank] = '*';
+ name [nsize + rank + bounded] = ']';
+ name [nsize + rank + bounded + 1] = 0;
+ class->name = mono_image_strdup (image, name);
g_free (name);
mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
/* generic IList, ICollection, IEnumerable */
class->interface_count = 1;
- class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
+ class->interfaces = mono_image_alloc0 (image, sizeof (MonoClass*) * class->interface_count);
args [0] = &eclass->byval_arg;
class->interfaces [0] = mono_class_bind_generic_parameters (
class->element_class = eclass;
if ((rank > 1) || bounded) {
- MonoArrayType *at = mono_mempool_alloc0 (image->mempool, sizeof (MonoArrayType));
+ MonoArrayType *at = mono_image_alloc0 (image, sizeof (MonoArrayType));
class->byval_arg.type = MONO_TYPE_ARRAY;
class->byval_arg.data.array = at;
at->eklass = eclass;
g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
if (!field->data) {
- cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), cindex + 1);
+ cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
g_assert (cindex);
g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
{
MonoType *type = NULL;
+ gboolean inflated = FALSE;
//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 class ? mono_class_get_type (class) : NULL;
}
- type = mono_type_retrieve_from_typespec (image, type_token, context);
+ type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated);
if (!type) {
char *name = mono_class_name_from_token (image, type_token);
char *assembly = mono_assembly_name_from_token (image, type_token);
+ if (inflated)
+ mono_metadata_free_type (type);
mono_loader_set_error_type_load (name, assembly);
}
+ if (inflated) {
+ MonoType *tmp = type;
+ type = mono_class_get_type (mono_class_from_mono_type (type));
+ /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
+ * A MonoClass::byval_arg of a generic type definion has type CLASS.
+ * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg.
+ *
+ * The long term solution is to chaise this places and make then set MonoType::type correctly.
+ * */
+ if (type->type != tmp->type)
+ type = tmp;
+ else
+ mono_metadata_free_type (tmp);
+ }
return type;
}
}
static MonoClass*
-return_nested_in (MonoClass *class, char *nested) {
+return_nested_in (MonoClass *class, char *nested)
+{
MonoClass *found;
char *s = strchr (nested, '/');
- GList *tmp;
+ gpointer iter = NULL;
if (s) {
*s = 0;
s++;
}
- for (tmp = class->nested_classes; tmp; tmp = tmp->next) {
- found = tmp->data;
+
+ while ((found = mono_class_get_nested_types (class, &iter))) {
if (strcmp (found->name, nested) == 0) {
if (s)
return return_nested_in (found, s);
return NULL;
}
+static MonoClass*
+search_modules (MonoImage *image, const char *name_space, const char *name)
+{
+ MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
+ MonoImage *file_image;
+ MonoClass *class;
+ int i;
+
+ /*
+ * The EXPORTEDTYPES table only contains public types, so have to search the
+ * modules as well.
+ * Note: image->modules contains the contents of the MODULEREF table, while
+ * the real module list is in the FILE table.
+ */
+ for (i = 0; i < file_table->rows; i++) {
+ guint32 cols [MONO_FILE_SIZE];
+ mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
+ if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
+ continue;
+
+ file_image = mono_image_load_file_for_image (image, i + 1);
+ if (file_image) {
+ class = mono_class_from_name (file_image, name_space, name);
+ if (class)
+ return class;
+ }
+ }
+
+ return NULL;
+}
/**
* mono_class_from_name:
if (get_class_from_name) {
gboolean res = get_class_from_name (image, name_space, name, &class);
if (res) {
+ if (!class)
+ class = search_modules (image, name_space, name);
if (nested)
return class ? return_nested_in (class, nested) : NULL;
else
}
}
+ if (!token) {
+ class = search_modules (image, name_space, name);
+ if (class)
+ return class;
+ }
+
if (!token)
return NULL;
return class;
} else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
MonoAssembly **references = image->references;
- if (!references [idx - 1])
- mono_assembly_load_reference (image, idx - 1);
+ guint32 assembly_idx;
+
+ assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
+
+ if (!references [assembly_idx - 1])
+ mono_assembly_load_reference (image, assembly_idx - 1);
g_assert (references == image->references);
- g_assert (references [idx - 1]);
- if (references [idx - 1] == (gpointer)-1)
+ g_assert (references [assembly_idx - 1]);
+ if (references [assembly_idx - 1] == (gpointer)-1)
return NULL;
else
/* FIXME: Cycle detection */
- return mono_class_from_name (references [idx - 1]->image, name_space, name);
+ return mono_class_from_name (references [assembly_idx - 1]->image, name_space, name);
} else {
g_error ("not yet implemented");
}
* interface_offsets set.
*/
return mono_reflection_call_is_assignable_to (oklass, klass);
-
+ if (!oklass->interface_bitmap)
+ /* Happens with generic instances of not-yet created dynamic types */
+ return FALSE;
if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
return TRUE;
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]);
+ if (param1_class->valuetype != param2_class->valuetype) {
+ match = FALSE;
+ break;
+ }
/*
* The _VARIANT and _COVARIANT constants should read _COVARIANT and
* _CONTRAVARIANT, but they are in a public header so we can't fix it.
;
else if (((container->type_params [i].flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
;
- else
+ else {
match = FALSE;
+ break;
+ }
}
}
}
return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
- } else if (mono_class_is_nullable (klass))
- return (mono_class_is_assignable_from (klass->cast_class, oklass));
- else if (klass == mono_defaults.object_class)
+ } else if (mono_class_is_nullable (klass)) {
+ if (mono_class_is_nullable (oklass))
+ return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
+ else
+ return mono_class_is_assignable_from (klass->cast_class, oklass);
+ } else if (klass == mono_defaults.object_class)
return TRUE;
return mono_class_has_parent (oklass, klass);
MonoClassField* field;
if (!iter)
return NULL;
- mono_class_setup_fields_locking (klass);
if (!*iter) {
+ mono_class_setup_fields_locking (klass);
/* start from the first */
if (klass->field.count) {
return *iter = &klass->fields [0];
mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
{
GList *item;
+ int i;
+
if (!iter)
return NULL;
if (!klass->inited)
mono_class_init (klass);
+ if (!klass->nested_classes_inited) {
+ if (!klass->type_token)
+ klass->nested_classes_inited = TRUE;
+ mono_loader_lock ();
+ if (!klass->nested_classes_inited) {
+ i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
+ while (i) {
+ MonoClass* nclass;
+ guint32 cols [MONO_NESTED_CLASS_SIZE];
+ mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
+ nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
+ klass->nested_classes = g_list_prepend_mempool (klass->nested_classes, klass->image->mempool, nclass);
+
+ i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
+ }
+ }
+ mono_memory_barrier ();
+ klass->nested_classes_inited = TRUE;
+ mono_loader_unlock ();
+ }
+
if (!*iter) {
/* start from the first */
if (klass->nested_classes) {
return mono_class_get_method_from_name_flags (klass, name, param_count, 0);
}
+static MonoMethod*
+find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
+{
+ MonoMethod *res = NULL;
+ int i;
+
+ /* Search directly in the metadata to avoid calling setup_methods () */
+ for (i = 0; i < klass->method.count; ++i) {
+ guint32 cols [MONO_METHOD_SIZE];
+ MonoMethod *method;
+
+ /* class->method.first points into the methodptr table */
+ mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
+
+ if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
+ method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
+ if ((param_count == -1) || mono_method_signature (method)->param_count == param_count) {
+ res = method;
+ break;
+ }
+ }
+ }
+
+ return res;
+}
+
/**
* mono_class_get_method_from_name_flags:
* @klass: where to look for the method
mono_class_init (klass);
- if (klass->methods) {
+ if (klass->methods || klass->generic_class) {
mono_class_setup_methods (klass);
for (i = 0; i < klass->method.count; ++i) {
MonoMethod *method = klass->methods [i];
}
}
else {
- /* Search directly in the metadata to avoid calling setup_methods () */
- for (i = 0; i < klass->method.count; ++i) {
- guint32 cols [MONO_METHOD_SIZE];
- MonoMethod *method;
-
- /* class->method.first points into the methodptr table */
- mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
-
- if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
- method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
- if ((param_count == -1) || mono_method_signature (method)->param_count == param_count) {
- res = method;
- break;
- }
- }
- }
+ res = find_method_in_metadata (klass, name, param_count, flags);
}
return res;
*
* Keep a detected failure informations in the class for later processing.
* Note that only the first failure is kept.
+ *
+ * LOCKING: Acquires the loader lock.
*/
gboolean
mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
{
if (klass->exception_type)
return FALSE;
+
+ mono_loader_lock ();
klass->exception_type = ex_type;
- klass->exception_data = ex_data;
+ if (ex_data)
+ mono_property_hash_insert (klass->image->property_hash, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
+ mono_loader_unlock ();
+
return TRUE;
}
+/*
+ * mono_class_get_exception_data:
+ *
+ * Return the exception_data property of KLASS.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
+gpointer
+mono_class_get_exception_data (MonoClass *klass)
+{
+ gpointer res;
+
+ mono_loader_lock ();
+ res = mono_property_hash_lookup (klass->image->property_hash, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
+ mono_loader_unlock ();
+ return res;
+}
+
/**
* mono_classes_init:
*
void
mono_classes_cleanup (void)
{
- IOffsetInfo *cached_info, *next;
-
if (global_interface_bitset)
mono_bitset_free (global_interface_bitset);
-
- for (cached_info = cached_offset_info; cached_info;) {
- next = cached_info->next;
-
- g_free (cached_info);
- cached_info = next;
- }
}
/**
MonoException*
mono_class_get_exception_for_failure (MonoClass *klass)
{
+ gpointer exception_data = mono_class_get_exception_data (klass);
+
switch (klass->exception_type) {
case MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND: {
MonoDomain *domain = mono_domain_get ();
MonoSecurityManager* secman = mono_security_manager_get_methods ();
- MonoMethod *method = klass->exception_data;
+ MonoMethod *method = exception_data;
guint32 error = (method) ? MONO_METADATA_INHERITANCEDEMAND_METHOD : MONO_METADATA_INHERITANCEDEMAND_CLASS;
MonoObject *exc = NULL;
gpointer args [4];
return ex;
}
case MONO_EXCEPTION_MISSING_METHOD: {
- char *class_name = klass->exception_data;
+ char *class_name = 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 *class_name = 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 *msg_format = exception_data;
char *assembly_name = msg_format + strlen (msg_format) + 1;
char *msg = g_strdup_printf (msg_format, assembly_name);
MonoException *ex;
return ex;
}
case MONO_EXCEPTION_BAD_IMAGE: {
- return mono_get_exception_bad_image_format (klass->exception_data);
+ return mono_get_exception_bad_image_format (exception_data);
}
default: {
MonoLoaderError *error;
}
}
+static gboolean
+is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
+ {
+ outer_klass = mono_class_get_generic_type_definition (outer_klass);
+ inner_klass = mono_class_get_generic_type_definition (inner_klass);
+ do {
+ if (outer_klass == inner_klass)
+ return TRUE;
+ inner_klass = inner_klass->nested_in;
+ } while (inner_klass);
+ return FALSE;
+}
+
+MonoClass *
+mono_class_get_generic_type_definition (MonoClass *klass)
+{
+ return klass->generic_class ? klass->generic_class->container_class : klass;
+}
+
+/*
+ * Check if @klass is a subtype of @parent ignoring generic instantiations.
+ *
+ * Generic instantiations are ignored for all super types of @klass.
+ *
+ * Visibility checks ignoring generic instantiations.
+ */
+static gboolean
+mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
+{
+ int i;
+ klass = mono_class_get_generic_type_definition (klass);
+ parent = mono_class_get_generic_type_definition (parent);
+
+ for (i = 0; i < klass->idepth; ++i) {
+ if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
+ return TRUE;
+ }
+ return FALSE;
+}
+/*
+ * Subtype can only access parent members with family protection if the site object
+ * is subclass of Subtype. For example:
+ * class A { protected int x; }
+ * class B : A {
+ * void valid_access () {
+ * B b;
+ * b.x = 0;
+ * }
+ * void invalid_access () {
+ * A a;
+ * a.x = 0;
+ * }
+ * }
+ * */
+static gboolean
+is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
+{
+ if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
+ return FALSE;
+
+ if (context_klass == NULL)
+ return TRUE;
+ /*if access_klass is not member_klass context_klass must be type compat*/
+ if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
+ return FALSE;
+ return TRUE;
+}
+
static gboolean
can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
{
return TRUE;
if (!accessed || !accessing)
return FALSE;
+ mono_assembly_load_friends (accessed);
for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
MonoAssemblyName *friend = tmp->data;
/* Be conservative with checks */
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))
+ if (!mono_public_tokens_are_equal (friend->public_key_token, accessing->aname.public_key_token))
continue;
}
return TRUE;
return NULL;
}
+static gboolean
+can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
+{
+ int i;
+ for (i = 0; i < ginst->type_argc; ++i) {
+ MonoType *type = ginst->type_argv[i];
+ if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
+ continue;
+ if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+can_access_type (MonoClass *access_klass, MonoClass *member_klass)
+{
+ int access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+
+ if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
+ return FALSE;
+
+ if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
+ return TRUE;
+
+ if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
+ return FALSE;
+
+ switch (access_level) {
+ case TYPE_ATTRIBUTE_NOT_PUBLIC:
+ return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+
+ case TYPE_ATTRIBUTE_PUBLIC:
+ return TRUE;
+
+ case TYPE_ATTRIBUTE_NESTED_PUBLIC:
+ return TRUE;
+
+ case TYPE_ATTRIBUTE_NESTED_PRIVATE:
+ return is_nesting_type (member_klass, access_klass);
+
+ case TYPE_ATTRIBUTE_NESTED_FAMILY:
+ return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
+
+ case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
+ return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+
+ case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
+ return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
+ mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
+
+ case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
+ return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
+ mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
+ }
+ return FALSE;
+}
+
/* FIXME: check visibility of type, too */
static gboolean
-can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
+can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
{
MonoClass *member_generic_def;
if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
else
access_container = access_klass->generic_class->container_class;
- if (can_access_member (access_container, member_generic_def, access_level))
+ if (can_access_member (access_container, member_generic_def, context_klass, access_level))
return TRUE;
}
case FIELD_ATTRIBUTE_PRIVATE:
return access_klass == member_klass;
case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
- if (mono_class_has_parent (access_klass, member_klass) &&
+ if (is_valid_family_access (access_klass, member_klass, context_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))
+ if (is_valid_family_access (access_klass, member_klass, context_klass))
return TRUE;
return FALSE;
case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
- if (mono_class_has_parent (access_klass, member_klass))
+ if (is_valid_family_access (access_klass, member_klass, context_klass))
return TRUE;
return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
case FIELD_ATTRIBUTE_PUBLIC:
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);
+ int can = can_access_member (method->klass, field->parent, NULL, 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);
+ can = can_access_member (nested, field->parent, NULL, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
if (can)
return TRUE;
nested = nested->nested_in;
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);
+ int can = can_access_member (method->klass, called->klass, NULL, 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);
+ can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
if (can)
return TRUE;
nested = nested->nested_in;
return can;
}
+/*
+ * mono_method_can_access_method_with_context:
+ * @method: The caller method
+ * @called: The called method
+ * @context_klass:TThe static type on stack of the owner @called object used
+ *
+ * This function must be used with instance calls, as they have more strict family accessibility.
+ * It can be used with static mehthod, but context_klass should be NULL.
+ *
+ * Returns: TRUE if caller have proper visibility and acessibility to @called
+ */
+gboolean
+mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
+{
+ MonoClass *access_class = method->klass;
+ MonoClass *member_class = called->klass;
+ int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ if (!can) {
+ MonoClass *nested = access_class->nested_in;
+ while (nested) {
+ can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ if (can)
+ break;
+ nested = nested->nested_in;
+ }
+ }
+
+ if (!can)
+ return FALSE;
+
+ if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class)))
+ return FALSE;
+
+ if (called->is_inflated) {
+ MonoMethodInflated * infl = (MonoMethodInflated*)called;
+ if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * mono_method_can_access_method_with_context:
+ * @method: The caller method
+ * @field: The accessed field
+ * @context_klass: The static type on stack of the owner @field object used
+ *
+ * This function must be used with instance fields, as they have more strict family accessibility.
+ * It can be used with static fields, but context_klass should be NULL.
+ *
+ * Returns: TRUE if caller have proper visibility and acessibility to @field
+ */
+gboolean
+mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
+{
+ MonoClass *access_class = method->klass;
+ MonoClass *member_class = field->parent;
+ /* FIXME: check all overlapping fields */
+ int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ if (!can) {
+ MonoClass *nested = access_class->nested_in;
+ while (nested) {
+ can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ if (can)
+ break;
+ nested = nested->nested_in;
+ }
+ }
+
+ if (!can)
+ return FALSE;
+
+ if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class)))
+ return FALSE;
+ return TRUE;
+}
+
/**
* mono_type_is_valid_enum_basetype:
* @type: The MonoType to check
gboolean
mono_class_generic_sharing_enabled (MonoClass *class)
{
- static int generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+ static gboolean supported = TRUE;
+#else
+ /* Not supported by the JIT backends */
+ static gboolean supported = FALSE;
+#endif
+ static int generic_sharing = MONO_GENERIC_SHARING_NONE;
static gboolean inited = FALSE;
if (!inited) {
const char *option;
+ if (supported)
+ generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+ else
+ generic_sharing = MONO_GENERIC_SHARING_NONE;
+
if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
if (strcmp (option, "corlib") == 0)
generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+ else if (strcmp (option, "collections") == 0)
+ generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
else if (strcmp (option, "all") == 0)
generic_sharing = MONO_GENERIC_SHARING_ALL;
else if (strcmp (option, "none") == 0)
g_warning ("Unknown generic sharing option `%s'.", option);
}
+ if (!supported)
+ generic_sharing = MONO_GENERIC_SHARING_NONE;
+
inited = TRUE;
}
return TRUE;
case MONO_GENERIC_SHARING_CORLIB :
return class->image == mono_defaults.corlib;
+ case MONO_GENERIC_SHARING_COLLECTIONS:
+ if (class->image != mono_defaults.corlib)
+ return FALSE;
+ while (class->nested_in)
+ class = class->nested_in;
+ return g_str_has_prefix (class->name_space, "System.Collections.Generic");
default:
g_assert_not_reached ();
}