* Author:
* Miguel de Icaza (miguel@ximian.com)
*
- * (C) 2001-2006 Novell, Inc.
- *
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
*/
#include <config.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <signal.h>
#if !PLATFORM_WIN32
#include <mono/io-layer/atomic.h>
#endif
#include <mono/metadata/attrdefs.h>
#include <mono/metadata/gc-internal.h>
#include <mono/metadata/verify-internals.h>
+#include <mono/metadata/mono-debug.h>
#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-string.h>
+#include <mono/utils/mono-error-internals.h>
MonoStats mono_stats;
*/
gboolean mono_setup_vtable_in_class_init = TRUE;
+/* Statistics */
+guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
+guint32 classes_size, class_ext_size;
+
/* Function supplied by the runtime to find classes by name using information from the AOT file */
static MonoGetClassFromName get_class_from_name = NULL;
static int generic_array_methods (MonoClass *class);
static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos);
+static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
+
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)
+ return NULL;
+
+ if (enclosing->nested_classes_inited && enclosing->ext) {
/* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
- for (tmp = enclosing->nested_classes; tmp; tmp = tmp->next) {
+ for (tmp = enclosing->ext->nested_classes; tmp; tmp = tmp->next) {
res = tmp->data;
if (strcmp (res->name, name) == 0)
return res;
static void *
-mono_mempool_dup (MonoMemPool *mp, void *data, guint size)
+mono_image_memdup (MonoImage *image, void *data, guint size)
{
- void *res = mono_mempool_alloc (mp, size);
+ void *res = mono_image_alloc (image, size);
memcpy (res, data, size);
return res;
}
/* Copy everything mono_metadata_free_array free. */
MonoArrayType *
-mono_dup_array_type (MonoMemPool *mp, MonoArrayType *a)
+mono_dup_array_type (MonoImage *image, MonoArrayType *a)
{
- if (mp) {
- mono_loader_lock ();
- a = mono_mempool_dup (mp, a, sizeof (MonoArrayType));
+ if (image) {
+ a = mono_image_memdup (image, a, sizeof (MonoArrayType));
if (a->sizes)
- a->sizes = mono_mempool_dup (mp, a->sizes, a->numsizes * sizeof (int));
+ a->sizes = mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
if (a->lobounds)
- a->lobounds = mono_mempool_dup (mp, a->lobounds, a->numlobounds * sizeof (int));
- mono_loader_unlock ();
+ a->lobounds = mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
} else {
a = g_memdup (a, sizeof (MonoArrayType));
if (a->sizes)
/* Copy everything mono_metadata_free_method_signature free. */
MonoMethodSignature*
-mono_metadata_signature_deep_dup (MonoMemPool *mp, MonoMethodSignature *sig)
+mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
{
int i;
- sig = mono_metadata_signature_dup_full (mp, sig);
+ sig = mono_metadata_signature_dup_full (image, sig);
- sig->ret = mono_metadata_type_dup (mp, sig->ret);
+ sig->ret = mono_metadata_type_dup (image, sig->ret);
for (i = 0; i < sig->param_count; ++i)
- sig->params [i] = mono_metadata_type_dup (mp, sig->params [i]);
+ sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
return sig;
}
}
case MONO_TYPE_VAR:
case MONO_TYPE_MVAR:
- g_assert (type->data.generic_param->name);
- g_string_append (str, type->data.generic_param->name);
-
+ if (!mono_generic_param_info (type->data.generic_param))
+ g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
+ else
+ g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
+
mono_type_name_check_byref (type, str);
break;
for (i = 0; i < klass->generic_container->type_argc; i++) {
if (i)
g_string_append_c (str, ',');
- g_string_append (str, klass->generic_container->type_params [i].name);
+ g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
}
if (format == MONO_TYPE_NAME_FORMAT_IL)
g_string_append_c (str, '>');
}
/**
- * mono_type_get_name:
+ * mono_type_get_name_full:
* @type: a type
* @format: the format for the return string.
*
mono_type_get_underlying_type (MonoType *type)
{
if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype && !type->byref)
- return type->data.klass->enum_basetype;
+ return mono_class_enum_basetype (type->data.klass);
if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype && !type->byref)
- return type->data.generic_class->container_class->enum_basetype;
+ return mono_class_enum_basetype (type->data.generic_class->container_class);
return type;
}
}
static MonoType*
-inflate_generic_type (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context)
+inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
{
+ mono_error_init (error);
+
switch (type->type) {
case MONO_TYPE_MVAR: {
MonoType *nt;
- int num = type->data.generic_param->num;
+ int num = mono_type_get_generic_param_num (type);
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);
+ if (num >= inst->type_argc) {
+ MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
+ mono_error_set_bad_image (error, image->module_name, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
+ num, info ? info->name : "", inst->type_argc);
+ return NULL;
+ }
/*
* 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 (mempool, inst->type_argv [num]);
+ nt = mono_metadata_type_dup (image, 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;
+ int num = mono_type_get_generic_param_num (type);
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);
- nt = mono_metadata_type_dup (mempool, inst->type_argv [num]);
+ if (num >= inst->type_argc) {
+ MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
+ mono_error_set_bad_image (error, image->module_name, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
+ num, info ? info->name : "", inst->type_argc);
+ return NULL;
+ }
+ nt = mono_metadata_type_dup (image, 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 (NULL, &eclass->byval_arg, context);
- if (!inflated)
+ MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
+ if (!inflated || !mono_error_ok (error))
return NULL;
- nt = mono_metadata_type_dup (mempool, type);
+ nt = mono_metadata_type_dup (image, 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 (NULL, &eclass->byval_arg, context);
- if (!inflated)
+ MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
+ if (!inflated || !mono_error_ok (error))
return NULL;
- nt = mono_metadata_type_dup (mempool, type);
+ nt = mono_metadata_type_dup (image, 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 (mempool, type);
+ nt = mono_metadata_type_dup (image, type);
nt->data.generic_class = gclass;
return nt;
}
gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
- nt = mono_metadata_type_dup (mempool, type);
+ nt = mono_metadata_type_dup (image, type);
nt->type = MONO_TYPE_GENERICINST;
nt->data.generic_class = gclass;
return nt;
return class->generic_class ? mono_generic_class_get_context (class->generic_class) : NULL;
}
+/*
+ * mono_class_get_generic_container:
+ *
+ * Return the generic container of KLASS which should be a generic type definition.
+ */
+MonoGenericContainer*
+mono_class_get_generic_container (MonoClass *klass)
+{
+ g_assert (klass->is_generic);
+
+ return klass->generic_container;
+}
+
+/*
+ * mono_class_get_generic_class:
+ *
+ * Return the MonoGenericClass of KLASS, which should be a generic instance.
+ */
+MonoGenericClass*
+mono_class_get_generic_class (MonoClass *klass)
+{
+ g_assert (klass->is_inflated);
+
+ return klass->generic_class;
+}
+
/*
* mono_class_inflate_generic_type_with_mempool:
* @mempool: a mempool
* @type: a type
* @context: a generics context
+ * @error: error context
*
* 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.
+ * The returned type can potentially be the same as TYPE, so it should not be
+ * modified by the caller, and it should be freed using mono_metadata_free_type ().
*/
MonoType*
-mono_class_inflate_generic_type_with_mempool (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context)
+mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
{
- MonoType *inflated = NULL;
+ MonoType *inflated = NULL;
+ mono_error_init (error);
if (context)
- inflated = inflate_generic_type (mempool, type, context);
+ inflated = inflate_generic_type (image, type, context, error);
+ if (!mono_error_ok (error))
+ return NULL;
- if (!inflated)
- return mono_metadata_type_dup (mempool, type);
+ if (!inflated) {
+ MonoType *shared = mono_metadata_get_shared_type (type);
+
+ if (shared) {
+ return shared;
+ } else {
+ return mono_metadata_type_dup (image, type);
+ }
+ }
mono_stats.inflated_type_count++;
return inflated;
* 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.
+ * on the heap and is owned by the caller. Returns NULL on error.
+ *
+ * @deprecated Please use mono_class_inflate_generic_type_checked instead
*/
MonoType*
mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
{
- return mono_class_inflate_generic_type_with_mempool (NULL, type, context);
+ MonoError error;
+ MonoType *result;
+ result = mono_class_inflate_generic_type_checked (type, context, &error);
+
+ if (!mono_error_ok (&error)) {
+ mono_error_cleanup (&error);
+ return NULL;
+ }
+ return result;
+}
+
+/*
+ * mono_class_inflate_generic_type:
+ * @type: a type
+ * @context: a generics context
+ * @error: error context to use
+ *
+ * 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_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
+{
+ return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
+}
+
+/*
+ * mono_class_inflate_generic_type_no_copy:
+ *
+ * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
+ * was done.
+ */
+static MonoType*
+mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context)
+{
+ MonoError error;
+ MonoType *inflated = NULL;
+
+ if (context) {
+ inflated = inflate_generic_type (image, type, context, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+ }
+
+ if (!inflated)
+ return type;
+
+ mono_stats.inflated_type_count++;
+ return inflated;
}
+/*
+ * mono_class_inflate_generic_class:
+ *
+ * Inflate the class GKLASS with CONTEXT.
+ */
+MonoClass*
+mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
+{
+ MonoError error;
+ MonoClass *res;
+ MonoType *inflated;
+
+ inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+
+ res = mono_class_from_mono_type (inflated);
+ mono_metadata_free_type (inflated);
+
+ return res;
+}
static MonoGenericContext
inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with)
}
/**
- * mono_class_inflate_generic_method:
+ * mono_class_inflate_generic_method_full:
*
* Instantiate method @method with the generic context @context.
* BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
iresult = g_new0 (MonoMethodInflated, 1);
iresult->context = *context;
iresult->declaring = method;
- iresult->is_mb_open = is_mb_open;
+ iresult->method.method.is_mb_open = is_mb_open;
if (!context->method_inst && method->is_generic)
iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
mono_stats.inflated_method_count++;
+ inflated_methods_size += sizeof (MonoMethodInflated);
+
sig = mono_method_signature (method);
if (sig->pinvoke) {
memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
result->is_inflated = TRUE;
result->is_generic = FALSE;
result->signature = NULL;
+ result->is_mb_open = is_mb_open;
if (!context->method_inst) {
/* Set the generic_container of the result to the generic_container of method */
result->klass = klass_hint;
if (!result->klass) {
- MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context);
+ MonoError error;
+ MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, &error);
+
+ g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+
result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
if (inflated)
mono_metadata_free_type (inflated);
return method;
}
+/*
+ * mono_method_get_context_general:
+ * @method: a method
+ * @uninflated: handle uninflated methods?
+ *
+ * Returns the generic context of a method or NULL if it doesn't have
+ * one. For an inflated method that's the context stored in the
+ * method. Otherwise it's in the method's generic container or in the
+ * generic container of the method's class.
+ */
MonoGenericContext*
-mono_method_get_context (MonoMethod *method)
+mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
{
- MonoMethodInflated *imethod;
- if (!method->is_inflated)
+ if (method->is_inflated) {
+ MonoMethodInflated *imethod = (MonoMethodInflated *) method;
+ return &imethod->context;
+ }
+ if (!uninflated)
return NULL;
- imethod = (MonoMethodInflated *) method;
- return &imethod->context;
+ if (method->is_generic)
+ return &(mono_method_get_generic_container (method)->context);
+ if (method->klass->generic_container)
+ return &method->klass->generic_container->context;
+ return NULL;
+}
+
+/*
+ * mono_method_get_context:
+ * @method: a method
+ *
+ * Returns the generic context for method if it's inflated, otherwise
+ * NULL.
+ */
+MonoGenericContext*
+mono_method_get_context (MonoMethod *method)
+{
+ return mono_method_get_context_general (method, FALSE);
}
/*
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 ();
+ container = mono_image_property_lookup (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
g_assert (container);
return 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_image_property_insert (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
}
/**
static MonoType*
mono_class_find_enum_basetype (MonoClass *class)
{
+ MonoGenericContainer *container = NULL;
MonoImage *m = class->image;
const int top = class->field.count;
int i;
g_assert (class->enumtype);
+ if (class->generic_container)
+ container = class->generic_container;
+ else if (class->generic_class) {
+ MonoClass *gklass = class->generic_class->container_class;
+
+ container = gklass->generic_container;
+ g_assert (container);
+ }
+
/*
* Fetch all the field information.
*/
const char *sig;
guint32 cols [MONO_FIELD_SIZE];
int idx = class->field.first + i;
- MonoGenericContainer *container = NULL;
MonoType *ftype;
/* class->field.first and idx points into the fieldptr table */
mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
+
+ if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
+ continue;
+
+ if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL))
+ return NULL;
+
sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
mono_metadata_decode_value (sig, &sig);
/* FIELD signature == 0x06 */
- g_assert (*sig == 0x06);
- if (class->generic_container)
- container = class->generic_container;
- else if (class->generic_class) {
- MonoClass *gklass = class->generic_class->container_class;
+ if (*sig != 0x06)
+ return NULL;
- container = gklass->generic_container;
- g_assert (container);
- }
ftype = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
if (!ftype)
return NULL;
ftype->attrs = cols [MONO_FIELD_FLAGS];
}
- if (class->enumtype && !(cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC))
- return ftype;
+ return ftype;
}
return NULL;
gboolean explicit_size;
MonoClassField *field;
MonoGenericContainer *container = NULL;
- MonoClass *gklass = NULL;
+ MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
if (class->size_inited)
return;
return;
}
- if (class->generic_class) {
- MonoClass *gklass = class->generic_class->container_class;
- mono_class_setup_fields (gklass);
- top = gklass->field.count;
- class->field.count = gklass->field.count;
+ if (gtd) {
+ mono_class_setup_fields (gtd);
+ if (gtd->exception_type) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ return;
+ }
+
+ top = gtd->field.count;
+ class->field.first = gtd->field.first;
+ class->field.count = gtd->field.count;
}
class->instance_size = 0;
if (class->parent) {
/* For generic instances, class->parent might not have been initialized */
mono_class_init (class->parent);
- if (!class->parent->size_inited)
+ if (!class->parent->size_inited) {
mono_class_setup_fields (class->parent);
+ if (class->parent->exception_type) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ return;
+ }
+ }
class->instance_size += class->parent->instance_size;
class->min_align = class->parent->min_align;
/* we use |= since it may have been set already */
class->min_align = 1;
}
+ /* We can't really enable 16 bytes alignment until the GC supports it.
+ The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
+ boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
+ Bug #506144 is an example of this issue.
+
+ if (class->simd_type)
+ class->min_align = 16;
+ */
/* Get the real size */
explicit_size = mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size);
/* 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;
- } else if (class->generic_class) {
- gklass = class->generic_class->container_class;
- container = gklass->generic_container;
+ } else if (gtd) {
+ container = gtd->generic_container;
g_assert (container);
-
- mono_class_setup_fields (gklass);
}
/*
field->parent = class;
- if (class->generic_class) {
- MonoClassField *gfield = &gklass->fields [i];
- MonoInflatedField *ifield = g_new0 (MonoInflatedField, 1);
-
- ifield->generic_type = gfield->type;
- field->name = gfield->name;
- field->generic_info = ifield;
- /*This memory must come from the image mempool as we don't have a change 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 (gtd) {
+ MonoClassField *gfield = >d->fields [i];
+
+ field->name = mono_field_get_name (gfield);
+ /*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_no_copy (class->image, gfield->type, mono_class_get_context (class));
+ g_assert (field->type->attrs == gfield->type->attrs);
if (mono_field_is_deleted (field))
continue;
field->offset = gfield->offset;
- field->data = gfield->data;
} else {
- guint32 rva;
const char *sig;
guint32 cols [MONO_FIELD_SIZE];
mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
/* The name is needed for fieldrefs */
field->name = mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]);
+ if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL)) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ break;
+ }
sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
mono_metadata_decode_value (sig, &sig);
/* FIELD signature == 0x06 */
field->offset = offset;
if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
g_warning ("%s not initialized correctly (missing field layout info for %s)",
- class->name, field->name);
- }
-
- if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
- mono_metadata_field_info (m, idx, NULL, &rva, NULL);
- if (!rva)
- g_warning ("field %s in %s should have RVA data, but hasn't", field->name, class->name);
- field->data = mono_image_rva_map (class->image, rva);
+ class->name, mono_field_get_name (field));
}
}
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->exception_type) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ break;
+ }
+ }
if (!field_class || !field_class->blittable)
blittable = FALSE;
}
}
if (class->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- class->enum_basetype = field->type;
- class->cast_class = class->element_class = mono_class_from_mono_type (class->enum_basetype);
+ class->cast_class = class->element_class = mono_class_from_mono_type (field->type);
blittable = class->element_class->blittable;
}
class->blittable = blittable;
- if (class->enumtype && !class->enum_basetype) {
+ if (class->enumtype && !mono_class_enum_basetype (class)) {
if (!((strcmp (class->name, "Enum") == 0) && (strcmp (class->name_space, "System") == 0)))
G_BREAKPOINT ();
}
}
if ((top == 1) && (class->instance_size == sizeof (MonoObject)) &&
- (strcmp (field->name, "$PRIVATE$") == 0)) {
+ (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
/* This field is a hack inserted by MCS to empty structures */
continue;
}
{
MonoMethod *method;
- method = (MonoMethod *) mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethodPInvoke));
+ method = (MonoMethod *) mono_image_alloc0 (class->image, sizeof (MonoMethodPInvoke));
method->klass = class;
method->flags = METHOD_ATTRIBUTE_PUBLIC;
method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
class->method.count = 3 + (class->rank > 1? 2: 1);
+ mono_class_setup_interfaces (class);
+
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_mempool_alloc0 (class->image->mempool, sizeof (MonoMethod*) * class->method.count);
+ 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;
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 (MONO_CLASS_IS_INTERFACE (class))
- for (i = 0; i < class->method.count; ++i)
- methods [i]->slot = i;
+ if (MONO_CLASS_IS_INTERFACE (class)) {
+ int slot = 0;
+ /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
+ for (i = 0; i < class->method.count; ++i) {
+ if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
+ methods [i]->slot = slot++;
+ }
+ }
/* Needed because of the double-checking locking pattern */
mono_memory_barrier ();
}
}
+/*
+ * mono_class_get_inflated_method:
+ *
+ * Given an inflated class CLASS and a method METHOD which should be a method of
+ * CLASS's generic definition, return the inflated method corresponding to METHOD.
+ */
+MonoMethod*
+mono_class_get_inflated_method (MonoClass *class, MonoMethod *method)
+{
+ MonoClass *gklass = class->generic_class->container_class;
+ int i;
+
+ mono_class_setup_methods (gklass);
+ for (i = 0; i < gklass->method.count; ++i) {
+ if (gklass->methods [i] == method) {
+ if (class->methods)
+ return class->methods [i];
+ else
+ return mono_class_inflate_generic_method_full (gklass->methods [i], class, mono_class_get_context (class));
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * mono_class_get_vtable_entry:
+ *
+ * Returns class->vtable [offset], computing it if neccesary.
+ * LOCKING: Acquires the loader lock.
+ */
+MonoMethod*
+mono_class_get_vtable_entry (MonoClass *class, int offset)
+{
+ MonoMethod *m;
+
+ if (class->rank == 1) {
+ /*
+ * szarrays do not overwrite any methods of Array, so we can avoid
+ * initializing their vtables in some cases.
+ */
+ mono_class_setup_vtable (class->parent);
+ if (offset < class->parent->vtable_size)
+ return class->parent->vtable [offset];
+ }
+
+ if (class->generic_class) {
+ MonoClass *gklass = class->generic_class->container_class;
+ mono_class_setup_vtable (gklass);
+ m = gklass->vtable [offset];
+
+ m = mono_class_inflate_generic_method_full (m, class, mono_class_get_context (class));
+ } else {
+ mono_class_setup_vtable (class);
+ m = class->vtable [offset];
+ }
+
+ return m;
+}
+
+/*
+ * mono_class_get_vtable_size:
+ *
+ * Return the vtable size for KLASS.
+ */
+int
+mono_class_get_vtable_size (MonoClass *klass)
+{
+ mono_class_setup_vtable (klass);
+
+ return klass->vtable_size;
+}
+
static void
mono_class_setup_properties (MonoClass *class)
{
MonoProperty *properties;
guint32 last;
- if (class->properties)
+ if (class->ext && class->ext->properties)
return;
mono_loader_lock ();
- if (class->properties) {
+ if (class->ext && class->ext->properties) {
mono_loader_unlock ();
return;
}
+ mono_class_alloc_ext (class);
+
if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
- class->property = gklass->property;
-
mono_class_init (gklass);
mono_class_setup_properties (gklass);
- properties = g_new0 (MonoProperty, class->property.count + 1);
+ class->ext->property = gklass->ext->property;
- for (i = 0; i < class->property.count; i++) {
+ properties = g_new0 (MonoProperty, class->ext->property.count + 1);
+
+ for (i = 0; i < class->ext->property.count; i++) {
MonoProperty *prop = &properties [i];
- *prop = gklass->properties [i];
+ *prop = gklass->ext->properties [i];
if (prop->get)
prop->get = mono_class_inflate_generic_method_full (
prop->parent = class;
}
} else {
- class->property.first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
- class->property.count = last - class->property.first;
+ class->ext->property.first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
+ class->ext->property.count = last - class->ext->property.first;
- if (class->property.count)
+ if (class->ext->property.count)
mono_class_setup_methods (class);
- properties = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoProperty) * class->property.count);
- for (i = class->property.first; i < last; ++i) {
+ properties = mono_image_alloc0 (class->image, sizeof (MonoProperty) * class->ext->property.count);
+ for (i = class->ext->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;
- properties [i - class->property.first].attrs = cols [MONO_PROPERTY_FLAGS];
- properties [i - class->property.first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
+ properties [i - class->ext->property.first].parent = class;
+ properties [i - class->ext->property.first].attrs = cols [MONO_PROPERTY_FLAGS];
+ properties [i - class->ext->property.first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
startm = mono_metadata_methods_from_property (class->image, i, &endm);
for (j = startm; j < endm; ++j) {
switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
case METHOD_SEMANTIC_SETTER:
- properties [i - class->property.first].set = method;
+ properties [i - class->ext->property.first].set = method;
break;
case METHOD_SEMANTIC_GETTER:
- properties [i - class->property.first].get = method;
+ properties [i - class->ext->property.first].get = method;
break;
default:
break;
}
}
}
+ /*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;
+ class->ext->properties = properties;
mono_loader_unlock ();
}
guint32 last;
MonoEvent *events;
- if (class->events)
+ if (class->ext && class->ext->events)
return;
mono_loader_lock ();
- if (class->events) {
+ if (class->ext && class->ext->events) {
mono_loader_unlock ();
return;
}
+ mono_class_alloc_ext (class);
+
if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
MonoGenericContext *context;
mono_class_setup_events (gklass);
- class->event = gklass->event;
+ class->ext->event = gklass->ext->event;
- class->events = g_new0 (MonoEvent, class->event.count);
+ class->ext->events = g_new0 (MonoEvent, class->ext->event.count);
- if (class->event.count)
+ if (class->ext->event.count)
context = mono_class_get_context (class);
- for (i = 0; i < class->event.count; i++) {
- MonoEvent *event = &class->events [i];
- MonoEvent *gevent = &gklass->events [i];
+ for (i = 0; i < class->ext->event.count; i++) {
+ MonoEvent *event = &class->ext->events [i];
+ MonoEvent *gevent = &gklass->ext->events [i];
event->parent = class;
event->name = gevent->name;
return;
}
- class->event.first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
- class->event.count = last - class->event.first;
+ class->ext->event.first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
+ class->ext->event.count = last - class->ext->event.first;
- if (class->event.count)
+ if (class->ext->event.count)
mono_class_setup_methods (class);
- events = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoEvent) * class->event.count);
- for (i = class->event.first; i < last; ++i) {
- MonoEvent *event = &events [i - class->event.first];
+ events = mono_image_alloc0 (class->image, sizeof (MonoEvent) * class->ext->event.count);
+ for (i = class->ext->event.first; i < last; ++i) {
+ MonoEvent *event = &events [i - class->ext->event.first];
mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
event->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->events = events;
+ class->ext->events = events;
mono_loader_unlock ();
}
{
int i;
MonoClass *ic;
+
+ mono_class_setup_interfaces (klass);
for (i = 0; i < klass->interface_count; i++) {
ic = klass->interfaces [i];
}
}
+static MonoClass*
+inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
+{
+ MonoType *args [1];
+ args [0] = &arg0->byval_arg;
+
+ return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
+}
+
+static MonoClass*
+array_class_get_if_rank (MonoClass *class, guint rank)
+{
+ return rank ? mono_array_class_get (class, rank) : class;
+}
+
+static void
+fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *eclass, int rank)
+{
+ valuetype_types [0] = eclass;
+ if (eclass == mono_defaults.int16_class)
+ valuetype_types [1] = mono_defaults.uint16_class;
+ else if (eclass == mono_defaults.uint16_class)
+ valuetype_types [1] = mono_defaults.int16_class;
+ else if (eclass == mono_defaults.int32_class)
+ valuetype_types [1] = mono_defaults.uint32_class;
+ else if (eclass == mono_defaults.uint32_class)
+ valuetype_types [1] = mono_defaults.int32_class;
+ else if (eclass == mono_defaults.int64_class)
+ valuetype_types [1] = mono_defaults.uint64_class;
+ else if (eclass == mono_defaults.uint64_class)
+ valuetype_types [1] = mono_defaults.int64_class;
+ else if (eclass == mono_defaults.byte_class)
+ valuetype_types [1] = mono_defaults.sbyte_class;
+ else if (eclass == mono_defaults.sbyte_class)
+ valuetype_types [1] = mono_defaults.byte_class;
+ else if (eclass->enumtype && mono_class_enum_basetype (eclass))
+ valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
+}
+
/* this won't be needed once bug #325495 is completely fixed
* though we'll need something similar to know which interfaces to allow
* in arrays when they'll be lazyly created
+ *
+ * FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
+ * MS returns diferrent types based on which instance is called. For example:
+ * object obj = new byte[10][];
+ * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
+ * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
+ * a != b ==> true
+ *
+ * Fixing this should kill quite some code, save some bits and improve compatibility.
*/
static MonoClass**
get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enumerator)
static MonoClass* generic_icollection_class = NULL;
static MonoClass* generic_ienumerable_class = NULL;
static MonoClass* generic_ienumerator_class = NULL;
- MonoClass *fclass = NULL;
+ MonoClass *valuetype_types[2] = { NULL, NULL };
MonoClass **interfaces = NULL;
- int i, interface_count, real_count;
+ int i, interface_count, real_count, original_rank;
int all_interfaces;
gboolean internal_enumerator;
gboolean eclass_is_valuetype;
}
internal_enumerator = FALSE;
eclass_is_valuetype = FALSE;
+ original_rank = eclass->rank;
if (class->byval_arg.type != MONO_TYPE_SZARRAY) {
if (class->generic_class && class->nested_in == mono_defaults.array_class && strcmp (class->name, "InternalEnumerator`1") == 0) {
/*
* For a Enumerator<T[]> we need to get the list of interfaces for T.
*/
eclass = mono_class_from_mono_type (class->generic_class->context.class_inst->type_argv [0]);
+ original_rank = eclass->rank;
eclass = eclass->element_class;
internal_enumerator = TRUE;
*is_enumerator = TRUE;
* the generic interfaces needed to implement.
*/
if (eclass->valuetype) {
- if (eclass == mono_defaults.int16_class)
- fclass = mono_defaults.uint16_class;
- else if (eclass == mono_defaults.uint16_class)
- fclass = mono_defaults.int16_class;
- else if (eclass == mono_defaults.int32_class)
- fclass = mono_defaults.uint32_class;
- else if (eclass == mono_defaults.uint32_class)
- fclass = mono_defaults.int32_class;
- else if (eclass == mono_defaults.int64_class)
- fclass = mono_defaults.uint64_class;
- else if (eclass == mono_defaults.uint64_class)
- fclass = mono_defaults.int64_class;
- else if (eclass == mono_defaults.byte_class)
- fclass = mono_defaults.sbyte_class;
- else if (eclass == mono_defaults.sbyte_class)
- fclass = mono_defaults.byte_class;
- else {
- /* No additional interfaces for other value types */
- *num = 0;
- return NULL;
- }
+ fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank);
/* IList, ICollection, IEnumerable */
- real_count = interface_count = 3;
- interfaces = g_malloc0 (sizeof (MonoClass*) * interface_count);
- interfaces [0] = fclass;
+ real_count = interface_count = valuetype_types [1] ? 6 : 3;
+ if (internal_enumerator) {
+ ++real_count;
+ if (valuetype_types [1])
+ ++real_count;
+ }
+
+ interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
+ interfaces [0] = valuetype_types [0];
+ if (valuetype_types [1])
+ interfaces [3] = valuetype_types [1];
+
eclass_is_valuetype = TRUE;
} else {
int j;
interface_count++;
else
interface_count += idepth;
+ if (eclass->rank && eclass->element_class->valuetype) {
+ fill_valuetype_array_derived_types (valuetype_types, eclass->element_class, original_rank);
+ if (valuetype_types [1])
+ ++interface_count;
+ }
/* IList, ICollection, IEnumerable */
interface_count *= 3;
real_count = interface_count;
- if (internal_enumerator)
- real_count += idepth + eclass->interface_offsets_count;
+ if (internal_enumerator) {
+ real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count;
+ if (valuetype_types [1])
+ ++real_count;
+ }
interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
if (MONO_CLASS_IS_INTERFACE (eclass)) {
interfaces [0] = mono_defaults.object_class;
j += 3;
}
}
+ if (valuetype_types [1]) {
+ interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank);
+ j += 3;
+ }
}
/* instantiate the generic interfaces */
for (i = 0; i < interface_count; i += 3) {
- MonoType *args [1];
MonoClass *iface = interfaces [i];
- args [0] = &iface->byval_arg;
- interfaces [i] = mono_class_bind_generic_parameters (
- mono_defaults.generic_ilist_class, 1, args, FALSE);
- //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));
- args [0] = &iface->byval_arg;
- interfaces [i + 1] = mono_class_bind_generic_parameters (
- generic_icollection_class, 1, args, FALSE);
- args [0] = &iface->byval_arg;
- interfaces [i + 2] = mono_class_bind_generic_parameters (
- generic_ienumerable_class, 1, args, FALSE);
- //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i + 1]->byval_arg, 0));
- //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i + 2]->byval_arg, 0));
+ interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface);
+ interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface);
+ interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
}
if (internal_enumerator) {
int j;
/* instantiate IEnumerator<iface> */
for (i = 0; i < interface_count; i++) {
- MonoType *args [1];
- MonoClass *iface = interfaces [i];
-
- args [0] = &iface->byval_arg;
- interfaces [i] = mono_class_bind_generic_parameters (
- generic_ienumerator_class, 1, args, FALSE);
- /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+ interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]);
}
+ j = interface_count;
if (!eclass_is_valuetype) {
- j = interface_count;
- for (i = 0; i < eclass->idepth; i++) {
- MonoType *args [1];
- args [0] = &eclass->supertypes [i]->byval_arg;
- interfaces [j] = mono_class_bind_generic_parameters (
- generic_ienumerator_class, 1, args, FALSE);
- /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+ if (MONO_CLASS_IS_INTERFACE (eclass)) {
+ interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, mono_defaults.object_class);
j ++;
+ } else {
+ for (i = 0; i < eclass->idepth; i++) {
+ interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->supertypes [i]);
+ j ++;
+ }
}
for (i = 0; i < eclass->interface_offsets_count; i++) {
- MonoClass *iface = eclass->interfaces_packed [i];
- MonoType *args [1];
- args [0] = &iface->byval_arg;
- interfaces [j] = mono_class_bind_generic_parameters (
- generic_ienumerator_class, 1, args, FALSE);
- /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+ interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->interfaces_packed [i]);
j ++;
}
+ } else {
+ interfaces [j++] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [0], original_rank));
}
+ if (valuetype_types [1])
+ interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [1], original_rank));
+ }
+#if 0
+ {
+ char *type_name = mono_type_get_name_full (&class->byval_arg, 0);
+ for (i = 0; i < real_count; ++i) {
+ char *name = mono_type_get_name_full (&interfaces [i]->byval_arg, 0);
+ g_print ("%s implements %s\n", type_name, name);
+ g_free (name);
+ }
+ g_free (type_name);
}
+#endif
*num = real_count;
return interfaces;
}
+static int
+find_array_interface (MonoClass *klass, const char *name)
+{
+ int i;
+ for (i = 0; i < klass->interface_count; ++i) {
+ if (strcmp (klass->interfaces [i]->name, name) == 0)
+ return i;
+ }
+ return -1;
+}
+
/*
- * LOCKING: this is supposed to be called with the loader lock held.
+ * Return the number of virtual methods.
+ * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
+ * FIXME It would be nice if this information could be cached somewhere.
*/
static int
-setup_interface_offsets (MonoClass *class, int cur_slot)
+count_virtual_methods (MonoClass *class)
{
- MonoClass *k, *ic;
- int i, max_iid;
- MonoClass **interfaces_full;
- int *interface_offsets_full;
+ int i, count = 0;
+ guint32 flags;
+ class = mono_class_get_generic_type_definition (class); /*We can find this information by looking at the GTD*/
+
+ if (class->methods || !MONO_CLASS_HAS_STATIC_METADATA (class)) {
+ mono_class_setup_methods (class);
+
+ for (i = 0; i < class->method.count; ++i) {
+ flags = class->methods [i]->flags;
+ if (flags & METHOD_ATTRIBUTE_VIRTUAL)
+ ++count;
+ }
+ } else {
+ for (i = 0; i < class->method.count; ++i) {
+ flags = mono_metadata_decode_table_row_col (class->image, MONO_TABLE_METHOD, class->method.first + i, MONO_METHOD_FLAGS);
+
+ if (flags & METHOD_ATTRIBUTE_VIRTUAL)
+ ++count;
+ }
+ }
+ return count;
+}
+
+/*
+ * LOCKING: this is supposed to be called with the loader lock held.
+ */
+static int
+setup_interface_offsets (MonoClass *class, int cur_slot)
+{
+ MonoClass *k, *ic;
+ int i, max_iid;
+ MonoClass **interfaces_full;
+ int *interface_offsets_full;
GPtrArray *ifaces;
int interface_offsets_count;
MonoClass **array_interfaces;
interface_offsets_full [i] = -1;
}
- ifaces = mono_class_get_implemented_interfaces (class);
- if (ifaces) {
- for (i = 0; i < ifaces->len; ++i) {
- ic = g_ptr_array_index (ifaces, i);
- interfaces_full [ic->interface_id] = ic;
- interface_offsets_full [ic->interface_id] = cur_slot;
- cur_slot += ic->method.count;
- }
- g_ptr_array_free (ifaces, TRUE);
- }
-
for (k = class->parent; k ; k = k->parent) {
ifaces = mono_class_get_implemented_interfaces (k);
if (ifaces) {
for (i = 0; i < ifaces->len; ++i) {
+ int io;
ic = g_ptr_array_index (ifaces, i);
-
- if (interface_offsets_full [ic->interface_id] == -1) {
- int io = mono_class_interface_offset (k, ic);
-
- g_assert (io >= 0);
-
- interfaces_full [ic->interface_id] = ic;
- interface_offsets_full [ic->interface_id] = io;
- }
+
+ /*Force the sharing of interface offsets between parent and subtypes.*/
+ io = mono_class_interface_offset (k, ic);
+ g_assert (io >= 0);
+ interfaces_full [ic->interface_id] = ic;
+ interface_offsets_full [ic->interface_id] = io;
}
g_ptr_array_free (ifaces, TRUE);
}
}
+
+ ifaces = mono_class_get_implemented_interfaces (class);
+ if (ifaces) {
+ for (i = 0; i < ifaces->len; ++i) {
+ ic = g_ptr_array_index (ifaces, i);
+ if (interfaces_full [ic->interface_id] != NULL)
+ continue;
+ interfaces_full [ic->interface_id] = ic;
+ interface_offsets_full [ic->interface_id] = cur_slot;
+ cur_slot += count_virtual_methods (ic);
+ }
+ g_ptr_array_free (ifaces, TRUE);
+ }
+
if (MONO_CLASS_IS_INTERFACE (class)) {
interfaces_full [class->interface_id] = class;
interface_offsets_full [class->interface_id] = cur_slot;
if (num_array_interfaces) {
if (is_enumerator) {
int ienumerator_offset;
- g_assert (strcmp (class->interfaces [0]->name, "IEnumerator`1") == 0);
- ienumerator_offset = interface_offsets_full [class->interfaces [0]->interface_id];
+ int ienumerator_idx = find_array_interface (class, "IEnumerator`1");
+ ienumerator_offset = interface_offsets_full [class->interfaces [ienumerator_idx]->interface_id];
for (i = 0; i < num_array_interfaces; ++i) {
ic = array_interfaces [i];
interfaces_full [ic->interface_id] = ic;
}
} else {
int ilist_offset, icollection_offset, ienumerable_offset;
- g_assert (strcmp (class->interfaces [0]->name, "IList`1") == 0);
- g_assert (strcmp (class->interfaces [0]->interfaces [0]->name, "ICollection`1") == 0);
- g_assert (strcmp (class->interfaces [0]->interfaces [1]->name, "IEnumerable`1") == 0);
- ilist_offset = interface_offsets_full [class->interfaces [0]->interface_id];
- icollection_offset = interface_offsets_full [class->interfaces [0]->interfaces [0]->interface_id];
- ienumerable_offset = interface_offsets_full [class->interfaces [0]->interfaces [1]->interface_id];
+ int ilist_iface_idx = find_array_interface (class, "IList`1");
+ int icollection_iface_idx = find_array_interface (class->interfaces [ilist_iface_idx], "ICollection`1");
+ int ienumerable_iface_idx = find_array_interface (class->interfaces [ilist_iface_idx], "IEnumerable`1");
+ ilist_offset = interface_offsets_full [class->interfaces [ilist_iface_idx]->interface_id];
+ icollection_offset = interface_offsets_full [class->interfaces [ilist_iface_idx]->interfaces [icollection_iface_idx]->interface_id];
+ ienumerable_offset = interface_offsets_full [class->interfaces [ilist_iface_idx]->interfaces [ienumerable_iface_idx]->interface_id];
g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
for (i = 0; i < num_array_interfaces; ++i) {
ic = array_interfaces [i];
g_assert (class->interface_offsets_count == interface_offsets_count);
} else {
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 (guint16) * interface_offsets_count);
- class->interface_bitmap = mono_mempool_alloc0 (class->image->mempool, (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0));
+ 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));
}
/*
- * Setup interface offsets for interfaces. Used by Ref.Emit.
+ * Setup interface offsets for interfaces.
+ * Initializes:
+ * - class->max_interface_id
+ * - class->interface_offsets_count
+ * - class->interfaces_packed
+ * - class->interface_offsets_packed
+ * - class->interface_bitmap
*/
void
mono_class_setup_interface_offsets (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_debug_using_mono_debugger ())
+ /* The debugger currently depends on this */
+ mono_class_setup_methods (class);
- if (MONO_CLASS_IS_INTERFACE (class))
+ if (MONO_CLASS_IS_INTERFACE (class)) {
+ /* This sets method->slot for all methods if this is an interface */
+ mono_class_setup_methods (class);
return;
+ }
mono_loader_lock ();
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)
- mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
-}
-
-
-static int __use_new_interface_vtable_code = -1;
-static gboolean
-use_new_interface_vtable_code (void) {
- if (__use_new_interface_vtable_code == -1) {
- char *env_var = getenv ("MONO_USE_NEW_INTERFACE_VTABLE_CODE");
- if (env_var == NULL) {
- __use_new_interface_vtable_code = TRUE;
- } else {
- if ((strcmp (env_var, "0") == 0) || (strcmp (env_var, "false") == 0) || (strcmp (env_var, "FALSE") == 0)) {
- __use_new_interface_vtable_code = FALSE;
- } else {
- __use_new_interface_vtable_code = TRUE;
- }
- }
- }
- return __use_new_interface_vtable_code;
-}
-
-
#define DEBUG_INTERFACE_VTABLE_CODE 0
#define TRACE_INTERFACE_VTABLE_CODE 0
+#define VERIFY_INTERFACE_VTABLE_CODE 0
+#define VTABLE_SELECTOR (1)
#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
#define DEBUG_INTERFACE_VTABLE(stmt) do {\
+ if (!(VTABLE_SELECTOR)) break; \
stmt;\
} while (0)
#else
#if TRACE_INTERFACE_VTABLE_CODE
#define TRACE_INTERFACE_VTABLE(stmt) do {\
+ if (!(VTABLE_SELECTOR)) break; \
stmt;\
} while (0)
#else
#define TRACE_INTERFACE_VTABLE(stmt)
#endif
+#if VERIFY_INTERFACE_VTABLE_CODE
+#define VERIFY_INTERFACE_VTABLE(stmt) do {\
+ if (!(VTABLE_SELECTOR)) break; \
+ stmt;\
+} while (0)
+#else
+#define VERIFY_INTERFACE_VTABLE(stmt)
+#endif
+
#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
static char*
}
if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_override_method (class, cm, im);
+ mono_security_core_clr_check_override (class, cm, im);
TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
return TRUE;
} else {
}
if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_override_method (class, cm, im);
+ mono_security_core_clr_check_override (class, cm, im);
TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
return TRUE;
}
#endif
+#if VERIFY_INTERFACE_VTABLE_CODE
+static int
+mono_method_try_get_vtable_index (MonoMethod *method)
+{
+ if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+ MonoMethodInflated *imethod = (MonoMethodInflated*)method;
+ if (imethod->declaring->is_generic)
+ return imethod->declaring->slot;
+ }
+ return method->slot;
+}
+
+static void
+mono_class_verify_vtable (MonoClass *class)
+{
+ int i;
+ char *full_name = mono_type_full_name (&class->byval_arg);
+
+ printf ("*** Verifying VTable of class '%s' \n", full_name);
+ g_free (full_name);
+ full_name = NULL;
+
+ if (!class->methods)
+ return;
+
+ for (i = 0; i < class->method.count; ++i) {
+ MonoMethod *cm = class->methods [i];
+ int slot;
+
+ if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ continue;
+
+ g_free (full_name);
+ full_name = mono_method_full_name (cm, TRUE);
+
+ slot = mono_method_try_get_vtable_index (cm);
+ if (slot >= 0) {
+ if (slot >= class->vtable_size) {
+ printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, class->vtable_size);
+ continue;
+ }
+
+ if (slot >= 0 && class->vtable [slot] != cm && (class->vtable [slot])) {
+ char *other_name = class->vtable [slot] ? mono_method_full_name (class->vtable [slot], TRUE) : g_strdup ("[null value]");
+ printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
+ g_free (other_name);
+ }
+ } else
+ printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
+ }
+ g_free (full_name);
+}
+#endif
+
static void
print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
int index;
char *method_signature;
+ char *type_name;
for (index = 0; index < onum; ++index) {
g_print (" at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
}
method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
- printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
- mono_type_get_name (&ic->byval_arg), im->name, method_signature, class->name_space, class->name);
+ type_name = mono_type_full_name (&class->byval_arg);
+ printf ("no implementation for interface method %s::%s(%s) in class %s\n",
+ mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name);
g_free (method_signature);
+ g_free (type_name);
+ mono_class_setup_methods (class);
for (index = 0; index < class->method.count; ++index) {
MonoMethod *cm = class->methods [index];
method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
}
}
+static gboolean
+verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
+{
+ int i;
+
+ for (i = 0; i < onum; ++i) {
+ MonoMethod *decl = overrides [i * 2];
+ MonoMethod *body = overrides [i * 2 + 1];
+
+ if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (class)) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
+ return FALSE;
+ }
+
+ if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
+ if (body->flags & METHOD_ATTRIBUTE_STATIC)
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
+ else
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
+ return FALSE;
+ }
+
+ if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
+ if (body->flags & METHOD_ATTRIBUTE_STATIC)
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
+ else
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
+ return FALSE;
+ }
+
+ if (!mono_class_is_assignable_from_slow (decl->klass, class)) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type"));
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
/*
* LOCKING: this is supposed to be called with the loader lock held.
*/
MonoClass *k, *ic;
MonoMethod **vtable;
int i, max_vtsize = 0, max_iid, cur_slot = 0;
- GPtrArray *ifaces, *pifaces = NULL;
+ GPtrArray *ifaces = NULL;
GHashTable *override_map = NULL;
gboolean security_enabled = mono_is_security_manager_active ();
+ MonoMethod *cm;
+ gpointer class_iter;
#if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
int first_non_interface_slot;
#endif
if (class->vtable)
return;
+ if (overrides && !verify_class_overrides (class, overrides, onum))
+ return;
+
ifaces = mono_class_get_implemented_interfaces (class);
+
if (ifaces) {
for (i = 0; i < ifaces->len; i++) {
MonoClass *ic = g_ptr_array_index (ifaces, i);
max_iid = class->max_interface_id;
DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
- if (use_new_interface_vtable_code ()) {
- if (class->parent && class->parent->vtable_size) {
- MonoClass *parent = class->parent;
- int i;
-
- memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
-
- // Also inherit parent interface vtables, just as a starting point.
- // This is needed otherwise bug-77127.exe fails when the property methods
- // have different names in the iterface and the class, because for child
- // classes the ".override" information is not used anymore.
- for (i = 0; i < parent->interface_offsets_count; i++) {
- MonoClass *parent_interface = parent->interfaces_packed [i];
- int interface_offset = mono_class_interface_offset (class, parent_interface);
+ /* Optimized version for generic instances */
+ if (class->generic_class) {
+ MonoClass *gklass = class->generic_class->container_class;
+ MonoMethod **tmp;
+
+ mono_class_setup_vtable (gklass);
+ if (gklass->exception_type != MONO_EXCEPTION_NONE) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ return;
+ }
+
+ tmp = mono_image_alloc0 (class->image, sizeof (gpointer) * gklass->vtable_size);
+ class->vtable_size = gklass->vtable_size;
+ for (i = 0; i < gklass->vtable_size; ++i)
+ if (gklass->vtable [i]) {
+ tmp [i] = mono_class_inflate_generic_method_full (gklass->vtable [i], class, mono_class_get_context (class));
+ tmp [i]->slot = gklass->vtable [i]->slot;
+ }
+ mono_memory_barrier ();
+ class->vtable = tmp;
+
+ /* Have to set method->slot for abstract virtual methods */
+ if (class->methods && gklass->methods) {
+ for (i = 0; i < class->method.count; ++i)
+ if (class->methods [i]->slot == -1)
+ class->methods [i]->slot = gklass->methods [i]->slot;
+ }
+
+ return;
+ }
+
+ if (class->parent && class->parent->vtable_size) {
+ MonoClass *parent = class->parent;
+ int i;
+
+ memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
+
+ // Also inherit parent interface vtables, just as a starting point.
+ // This is needed otherwise bug-77127.exe fails when the property methods
+ // have different names in the iterface and the class, because for child
+ // classes the ".override" information is not used anymore.
+ for (i = 0; i < parent->interface_offsets_count; i++) {
+ MonoClass *parent_interface = parent->interfaces_packed [i];
+ int interface_offset = mono_class_interface_offset (class, parent_interface);
+ /*FIXME this is now dead code as this condition will never hold true.
+ Since interface offsets are inherited then the offset of an interface implemented
+ by a parent will never be the out of it's vtable boundary.
+ */
+ if (interface_offset >= parent->vtable_size) {
+ int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
+ int j;
- if (interface_offset >= parent->vtable_size) {
- int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
- int j;
-
- mono_class_setup_methods (parent_interface);
- TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
- for (j = 0; j < parent_interface->method.count; j++) {
- vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
- TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
- parent_interface_offset + j, parent_interface_offset, j,
- interface_offset + j, interface_offset, j));
- }
+ mono_class_setup_methods (parent_interface);
+ TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
+ for (j = 0; j < parent_interface->method.count; j++) {
+ vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
+ TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
+ parent_interface_offset + j, parent_interface_offset, j,
+ interface_offset + j, interface_offset, j));
}
-
}
+
}
- } else {
- if (class->parent && class->parent->vtable_size)
- memcpy (vtable, class->parent->vtable, sizeof (gpointer) * class->parent->vtable_size);
}
TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
MonoMethod *decl = overrides [i*2];
if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
int dslot;
- mono_class_setup_methods (decl->klass);
- g_assert (decl->slot != -1);
- dslot = decl->slot + mono_class_interface_offset (class, decl->klass);
+ dslot = mono_method_get_vtable_slot (decl) + mono_class_interface_offset (class, decl->klass);
vtable [dslot] = overrides [i*2 + 1];
vtable [dslot]->slot = dslot;
if (!override_map)
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_security_core_clr_check_override (class, vtable [dslot], decl);
}
}
TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
- if (use_new_interface_vtable_code ()) {
- // Loop on all implemented interfaces...
- for (i = 0; i < class->interface_offsets_count; i++) {
- MonoClass *parent = class->parent;
- int ic_offset;
- gboolean interface_is_explicitly_implemented_by_class;
- int im_index;
-
- ic = class->interfaces_packed [i];
- ic_offset = mono_class_interface_offset (class, ic);
+ // Loop on all implemented interfaces...
+ for (i = 0; i < class->interface_offsets_count; i++) {
+ MonoClass *parent = class->parent;
+ int ic_offset;
+ gboolean interface_is_explicitly_implemented_by_class;
+ int im_index;
+
+ ic = class->interfaces_packed [i];
+ ic_offset = mono_class_interface_offset (class, ic);
- mono_class_setup_methods (ic);
-
- // Check if this interface is explicitly implemented (instead of just inherited)
- if (parent != NULL) {
- int implemented_interfaces_index;
- interface_is_explicitly_implemented_by_class = FALSE;
- for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
- if (ic == class->interfaces [implemented_interfaces_index]) {
- interface_is_explicitly_implemented_by_class = TRUE;
- break;
- }
+ mono_class_setup_methods (ic);
+
+ // Check if this interface is explicitly implemented (instead of just inherited)
+ if (parent != NULL) {
+ int implemented_interfaces_index;
+ interface_is_explicitly_implemented_by_class = FALSE;
+ for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
+ if (ic == class->interfaces [implemented_interfaces_index]) {
+ interface_is_explicitly_implemented_by_class = TRUE;
+ break;
}
- } else {
- interface_is_explicitly_implemented_by_class = TRUE;
}
+ } else {
+ interface_is_explicitly_implemented_by_class = TRUE;
+ }
+
+ // Loop on all interface methods...
+ for (im_index = 0; im_index < ic->method.count; im_index++) {
+ MonoMethod *im = ic->methods [im_index];
+ int im_slot = ic_offset + im->slot;
+ MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
- // Loop on all interface methods...
- for (im_index = 0; im_index < ic->method.count; im_index++) {
- MonoMethod *im = ic->methods [im_index];
- 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 (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) {
- int cm_index;
-
- // First look for a suitable method among the class methods
- for (cm_index = 0; cm_index < class->method.count; cm_index++) {
- MonoMethod *cm = class->methods [cm_index];
+ // If there is an explicit implementation, just use it right away,
+ // otherwise look for a matching method
+ if (override_im == NULL) {
+ int cm_index;
+ gpointer iter;
+ MonoMethod *cm;
+
+ // First look for a suitable method among the class methods
+ iter = NULL;
+ while ((cm = mono_class_get_virtual_methods (class, &iter))) {
+ TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
+ if (check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
+ TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
+ vtable [im_slot] = cm;
+ /* Why do we need this? */
+ if (cm->slot < 0) {
+ cm->slot = im_slot;
+ }
+ }
+ TRACE_INTERFACE_VTABLE (printf ("\n"));
+ }
+
+ // If the slot is still empty, look in all the inherited virtual methods...
+ if ((vtable [im_slot] == NULL) && class->parent != NULL) {
+ MonoClass *parent = class->parent;
+ // Reverse order, so that last added methods are preferred
+ for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
+ MonoMethod *cm = parent->vtable [cm_index];
- TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
- if ((cm->flags & METHOD_ATTRIBUTE_VIRTUAL) && check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
- TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
+ TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
+ if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
+ TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
vtable [im_slot] = cm;
/* Why do we need this? */
if (cm->slot < 0) {
cm->slot = im_slot;
}
+ break;
}
- TRACE_INTERFACE_VTABLE (printf ("\n"));
- }
-
- // If the slot is still empty, look in all the inherited virtual methods...
- if ((vtable [im_slot] == NULL) && class->parent != NULL) {
- MonoClass *parent = class->parent;
- // Reverse order, so that last added methods are preferred
- for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
- MonoMethod *cm = parent->vtable [cm_index];
-
- TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
- if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
- TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
- vtable [im_slot] = cm;
- /* Why do we need this? */
- if (cm->slot < 0) {
- cm->slot = im_slot;
- }
- break;
- }
- TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
- }
+ TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
}
- } else {
- g_assert (vtable [im_slot] == override_im);
}
+ } else {
+ g_assert (vtable [im_slot] == override_im);
}
}
-
- // If the class is not abstract, check that all its interface slots are full.
- // The check is done here and not directly at the end of the loop above because
- // it can happen (for injected generic array interfaces) that the same slot is
- // processed multiple times (those interfaces have overlapping slots), and it
- // will not always be the first pass the one that fills the slot.
- if (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
- for (i = 0; i < class->interface_offsets_count; i++) {
- int ic_offset;
- int im_index;
-
- ic = class->interfaces_packed [i];
- ic_offset = mono_class_interface_offset (class, ic);
+ }
+
+ // If the class is not abstract, check that all its interface slots are full.
+ // The check is done here and not directly at the end of the loop above because
+ // it can happen (for injected generic array interfaces) that the same slot is
+ // processed multiple times (those interfaces have overlapping slots), and it
+ // will not always be the first pass the one that fills the slot.
+ if (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ for (i = 0; i < class->interface_offsets_count; i++) {
+ int ic_offset;
+ int im_index;
+
+ ic = class->interfaces_packed [i];
+ ic_offset = mono_class_interface_offset (class, ic);
+
+ for (im_index = 0; im_index < ic->method.count; im_index++) {
+ MonoMethod *im = ic->methods [im_index];
+ int im_slot = ic_offset + im->slot;
- for (im_index = 0; im_index < ic->method.count; im_index++) {
- 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) {
- print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum);
- mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
- if (override_map)
- g_hash_table_destroy (override_map);
- return;
- }
- }
- }
- }
- } else {
- for (k = class; k ; k = k->parent) {
- int nifaces = 0;
-
- ifaces = mono_class_get_implemented_interfaces (k);
- if (ifaces) {
- nifaces = ifaces->len;
- if (k->generic_class) {
- pifaces = mono_class_get_implemented_interfaces (
- k->generic_class->container_class);
- g_assert (pifaces && (pifaces->len == nifaces));
- }
- }
- for (i = 0; i < nifaces; i++) {
- MonoClass *pic = NULL;
- int j, l, io;
-
- ic = g_ptr_array_index (ifaces, i);
- if (pifaces)
- pic = g_ptr_array_index (pifaces, i);
- g_assert (ic->interface_id <= k->max_interface_id);
- io = mono_class_interface_offset (k, ic);
-
- g_assert (io >= 0);
- g_assert (io <= max_vtsize);
-
- if (k == class) {
- mono_class_setup_methods (ic);
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = ic->methods [l];
-
- if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
- continue;
-
- for (j = 0; j < class->method.count; ++j) {
- MonoMethod *cm = class->methods [j];
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
- !((cm->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) ||
- !(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT))
- continue;
- if (!strcmp(cm->name, im->name) &&
- mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
-
- /* 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;
- TRACE_INTERFACE_VTABLE (printf (" [NOA] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
- TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
- TRACE_INTERFACE_VTABLE (printf ("\n"));
- }
- }
- }
- } else {
- /* already implemented */
- if (io >= k->vtable_size)
- continue;
- }
-
- // Override methods with the same fully qualified name
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = ic->methods [l];
- char *qname, *fqname, *cname, *the_cname;
- MonoClass *k1;
-
- if (vtable [io + l])
- continue;
-
- if (pic) {
- the_cname = mono_type_get_name_full (&pic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
- cname = the_cname;
- } else {
- the_cname = NULL;
- cname = (char*)ic->name;
- }
-
- qname = g_strconcat (cname, ".", im->name, NULL);
- if (ic->name_space && ic->name_space [0])
- fqname = g_strconcat (ic->name_space, ".", cname, ".", im->name, NULL);
- else
- fqname = NULL;
-
- for (k1 = class; k1; k1 = k1->parent) {
- for (j = 0; j < k1->method.count; ++j) {
- MonoMethod *cm = k1->methods [j];
-
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
- continue;
-
- if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
- 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;
- TRACE_INTERFACE_VTABLE (printf (" [FQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
- TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
- TRACE_INTERFACE_VTABLE (printf ("\n"));
- break;
- }
- }
- }
- g_free (the_cname);
- g_free (qname);
- g_free (fqname);
- }
-
- // Override methods with the same name
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = ic->methods [l];
- MonoClass *k1;
-
- g_assert (io + l <= max_vtsize);
-
- if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
- continue;
-
- for (k1 = class; k1; k1 = k1->parent) {
- for (j = 0; j < k1->method.count; ++j) {
- MonoMethod *cm = k1->methods [j];
-
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
- !(cm->flags & METHOD_ATTRIBUTE_PUBLIC))
- continue;
-
- if (!strcmp(cm->name, im->name) &&
- mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
-
- /* 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;
- TRACE_INTERFACE_VTABLE (printf (" [SQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
- TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
- TRACE_INTERFACE_VTABLE (printf ("\n"));
- break;
- }
-
- }
- g_assert (io + l <= max_vtsize);
- if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
- break;
- }
- }
-
- if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
- for (l = 0; l < ic->method.count; l++) {
- char *msig;
- MonoMethod *im = ic->methods [l];
- if (im->flags & METHOD_ATTRIBUTE_STATIC)
- continue;
- g_assert (io + l <= max_vtsize);
-
- /*
- * If one of our parents already implements this interface
- * we can inherit the implementation.
- */
- if (!(vtable [io + l])) {
- MonoClass *parent = class->parent;
-
- for (; parent; parent = parent->parent) {
- if (MONO_CLASS_IMPLEMENTS_INTERFACE (parent, ic->interface_id) &&
- parent->vtable) {
- vtable [io + l] = parent->vtable [mono_class_interface_offset (parent, ic) + l];
- TRACE_INTERFACE_VTABLE (printf (" [INH] Filling slot %d (%d+%d) with method '%s'.'%s':'%s'\n", io + l, io, l, vtable [io + l]->klass->name_space, vtable [io + l]->klass->name, vtable [io + l]->name));
- }
- }
- }
-
- if (!(vtable [io + l])) {
- for (j = 0; j < onum; ++j) {
- g_print (" at slot %d: %s (%d) overrides %s (%d)\n", io+l, overrides [j*2+1]->name,
- overrides [j*2+1]->slot, overrides [j*2]->name, overrides [j*2]->slot);
- }
- msig = mono_signature_get_desc (mono_method_signature (im), FALSE);
- printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
- mono_type_get_name (&ic->byval_arg), im->name, msig, class->name_space, class->name);
- g_free (msig);
- for (j = 0; j < class->method.count; ++j) {
- MonoMethod *cm = class->methods [j];
- msig = mono_signature_get_desc (mono_method_signature (cm), TRUE);
-
- printf ("METHOD %s(%s)\n", cm->name, msig);
- g_free (msig);
- }
-
- 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);
+ if (im->flags & METHOD_ATTRIBUTE_STATIC)
+ continue;
- return;
- }
- }
- }
-
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = vtable [io + l];
-
- if (im) {
- g_assert (io + l <= max_vtsize);
- if (im->slot < 0) {
- /* FIXME: why do we need this ? */
- im->slot = io + l;
- /* g_assert_not_reached (); */
- }
- }
+ 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) {
+ print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum);
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (override_map)
+ g_hash_table_destroy (override_map);
+ return;
}
}
- if (ifaces)
- g_ptr_array_free (ifaces, TRUE);
- }
- }
-
- TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
- for (i = 0; i < class->method.count; ++i) {
- MonoMethod *cm;
-
- cm = class->methods [i];
-
- /*
- * Non-virtual method have no place in the vtable.
- * This also catches static methods (since they are not virtual).
- */
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
- continue;
-
+ }
+ }
+
+ TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
+ class_iter = NULL;
+ while ((cm = mono_class_get_virtual_methods (class, &class_iter))) {
/*
* If the method is REUSE_SLOT, we must check in the
* base class for a method to override.
if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
int slot = -1;
for (k = class->parent; k ; k = k->parent) {
- int j;
- for (j = 0; j < k->method.count; ++j) {
- MonoMethod *m1 = k->methods [j];
- MonoMethodSignature *cmsig, *m1sig;
+ gpointer k_iter;
+ MonoMethod *m1;
- if (!(m1->flags & METHOD_ATTRIBUTE_VIRTUAL))
- continue;
+ k_iter = NULL;
+ while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
+ MonoMethodSignature *cmsig, *m1sig;
cmsig = mono_method_signature (cm);
m1sig = mono_method_signature (m1);
}
if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_override_method (class, cm, m1);
+ mono_security_core_clr_check_override (class, cm, m1);
- slot = k->methods [j]->slot;
+ slot = mono_method_get_vtable_slot (m1);
g_assert (cm->slot < max_vtsize);
if (!override_map)
override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
cm->slot = slot;
}
+ /*Non final newslot methods must be given a non-interface vtable slot*/
+ if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
+ cm->slot = -1;
+
if (cm->slot < 0)
cm->slot = cur_slot++;
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);
+ mono_security_core_clr_check_override (class, vtable [decl->slot], decl);
}
}
g_hash_table_destroy (override_map);
}
+ /* Ensure that all vtable slots are filled with concrete instance methods */
+ if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ for (i = 0; i < cur_slot; ++i) {
+ if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
+ char *type_name = mono_type_get_full_name (class);
+ char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name));
+ g_free (type_name);
+ g_free (method_name);
+ return;
+ }
+ }
+ }
+
if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
mono_memory_barrier ();
class->vtable = class->parent->vtable;
} else {
- MonoMethod **tmp = mono_mempool_alloc0 (class->image->mempool, 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;
printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&class->byval_arg),
class->vtable_size, icount);
- for (i = 0; i < class->vtable_size; ++i) {
+ for (i = 0; i < cur_slot; ++i) {
MonoMethod *cm;
cm = vtable [i];
ic = class->interfaces [i];
printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
mono_class_interface_offset (class, ic),
- ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg));
+ count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
}
for (k = class->parent; k ; k = k->parent) {
for (i = 0; i < k->interface_count; i++) {
ic = k->interfaces [i];
- printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
+ printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
mono_class_interface_offset (class, ic),
- ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg));
+ count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
}
}
}
}
+
+ VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (class));
+}
+
+/*
+ * mono_method_get_vtable_slot:
+ *
+ * Returns method->slot, computing it if neccesary.
+ * LOCKING: Acquires the loader lock.
+ */
+int
+mono_method_get_vtable_slot (MonoMethod *method)
+{
+ if (method->slot == -1) {
+ mono_class_setup_vtable (method->klass);
+ g_assert (method->slot != -1);
+ }
+ return method->slot;
+}
+
+/**
+ * mono_method_get_vtable_index:
+ * @method: a method
+ *
+ * Returns the index into the runtime vtable to access the method or,
+ * in the case of a virtual generic method, the virtual generic method
+ * thunk.
+ */
+int
+mono_method_get_vtable_index (MonoMethod *method)
+{
+ if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+ MonoMethodInflated *imethod = (MonoMethodInflated*)method;
+ if (imethod->declaring->is_generic)
+ return mono_method_get_vtable_slot (imethod->declaring);
+ }
+ return mono_method_get_vtable_slot (method);
}
static MonoMethod *default_ghc = NULL;
}
}
-static GList*
-g_list_prepend_mempool (GList* l, MonoMemPool* mp, gpointer datum)
-{
- GList* n = mono_mempool_alloc (mp, sizeof (GList));
- n->next = l;
- n->prev = NULL;
- n->data = datum;
- return n;
-}
-
typedef struct {
MonoMethod *array_method;
char *name;
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;
/*g_print ("array generic methods: %d\n", count_generic);*/
generic_array_method_num = count_generic;
+ g_list_free (list);
return generic_array_method_num;
}
}
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);
switch (error->exception_type) {
case MONO_EXCEPTION_TYPE_LOAD:
- 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:
- 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;
- 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.";
- 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;
}
mono_class_set_failure (class, error->exception_type, exception_data);
}
-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)
- mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
-}
-
/**
* mono_class_init:
* @class: the class to initialize
class->init_pending = 1;
+ if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
+ MonoClass *element_class = class->element_class;
+ if (!element_class->inited)
+ mono_class_init (element_class);
+ if (element_class->exception_type != MONO_EXCEPTION_NONE) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ goto fail;
+ }
+ }
+
/* CAS - SecurityAction.InheritanceDemand */
if (mono_is_security_manager_active () && class->parent && (class->parent->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) {
mono_secman_inheritancedemand_class (class, class->parent);
}
if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_inheritance (class);
+ mono_security_core_clr_check_inheritance (class);
mono_stats.initialized_class_count++;
class->field = gklass->field;
mono_class_init (gklass);
+ // FIXME: Why is this needed ?
mono_class_setup_methods (gklass);
- mono_class_setup_properties (gklass);
if (MONO_CLASS_IS_INTERFACE (class))
class->interface_id = mono_get_unique_iid (class);
-
- g_assert (class->interface_count == gklass->interface_count);
}
if (class->parent && !class->parent->inited)
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
class->has_cctor = gklass->has_cctor;
mono_class_setup_vtable (gklass);
- if (gklass->exception_type)
+ if (gklass->exception_type) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
goto fail;
+ }
class->vtable_size = gklass->vtable_size;
} else {
}
*/
- if (!MONO_CLASS_IS_INTERFACE (class)) {
+ /* 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];
- }
+ if (class->parent && class->parent->has_finalize) {
+ class->has_finalize = 1;
+ } else {
+ 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];
+ }
- if (cmethod) {
- /* Check that this is really the finalizer method */
- mono_class_setup_vtable (class);
- if (class->exception_type || mono_loader_get_last_error ())
+ 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;
+ 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;
+ }
}
}
}
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 ())
+ if (class->parent->exception_type) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ goto fail;
+ }
+ if (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 ())
+ if (class->parent->exception_type) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ goto fail;
+ }
+ if (mono_loader_get_last_error ())
goto fail;
}
setup_interface_offsets (class, class->parent->vtable_size);
}
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->mempool, class->name, class->image->assembly_name));
+ 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;
}
}
+/*
+ * COM initialization (using mono_init_com_types) is delayed until needed.
+ * However when a [ComImport] attribute is present on a type it will trigger
+ * the initialization. This is not a problem unless the BCL being executed
+ * lacks the types that COM depends on (e.g. Variant on Silverlight).
+ */
+static void
+init_com_from_comimport (MonoClass *class)
+{
+ /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
+ if ((mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)) {
+ /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
+ if (!mono_security_core_clr_determine_platform_image (class->image)) {
+ /* but it can not be made available for application (i.e. user code) since all COM calls
+ * are considered native calls. In this case we fail with a TypeLoadException (just like
+ * Silverlight 2 does */
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ return;
+ }
+ }
+ /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
+ mono_init_com_types ();
+}
+
/*
* LOCKING: this assumes the loader lock is held
*/
if (!MONO_CLASS_IS_INTERFACE (class)) {
/* Imported COM Objects always derive from __ComObject. */
if (MONO_CLASS_IS_IMPORT (class)) {
- mono_init_com_types ();
+ init_com_from_comimport (class);
if (parent == mono_defaults.object_class)
parent = mono_defaults.com_object_class;
}
} else {
/* initialize com types if COM interfaces are present */
if (MONO_CLASS_IS_IMPORT (class))
- mono_init_com_types ();
+ init_com_from_comimport (class);
class->parent = NULL;
}
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;
mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), class);
+ classes_size += sizeof (MonoClass);
+
/*
* Check whether we're a generic type definition.
*/
class->generic_container = mono_metadata_load_generic_params (image, class->type_token, NULL);
if (class->generic_container) {
+ class->is_generic = 1;
class->generic_container->owner.klass = class;
context = &class->generic_container->context;
}
if (cols [MONO_TYPEDEF_EXTENDS]) {
- parent = mono_class_get_full (
- image, mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]), context);
+ guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
+
+ if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
+ /*WARNING: this must satisfy mono_metadata_type_hash*/
+ class->this_arg.byref = 1;
+ class->this_arg.data.klass = class;
+ class->this_arg.type = MONO_TYPE_CLASS;
+ class->byval_arg.data.klass = class;
+ class->byval_arg.type = MONO_TYPE_CLASS;
+ }
+ parent = mono_class_get_full (image, parent_token, context);
+
if (parent == NULL){
mono_internal_hash_table_remove (&image->class_cache, GUINT_TO_POINTER (type_token));
mono_loader_unlock ();
/* uses ->valuetype, which is initialized by mono_class_setup_parent above */
mono_class_setup_mono_type (class);
+ if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
+ class->unicode = 1;
+
+#ifdef PLATFORM_WIN32
+ if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
+ class->unicode = 1;
+#endif
+
+ class->cast_class = class->element_class = class;
+
if (!class->enumtype) {
if (!mono_metadata_interfaces_from_typedef_full (
- image, type_token, &interfaces, &icount, context)){
+ image, type_token, &interfaces, &icount, FALSE, context)){
mono_loader_unlock ();
mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
return NULL;
class->interfaces = interfaces;
class->interface_count = icount;
+ class->interfaces_inited = 1;
}
- if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
- class->unicode = 1;
-
-#if PLATFORM_WIN32
- if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
- class->unicode = 1;
-#endif
-
- class->cast_class = class->element_class = class;
-
/*g_print ("Load class %s\n", name);*/
/*
class->method.count = 0;
/* reserve space to store vector pointer in arrays */
- if (!strcmp (nspace, "System") && !strcmp (name, "Array")) {
+ if (is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
class->instance_size += 2 * sizeof (gpointer);
g_assert (class->field.count == 0);
}
if (class->enumtype) {
- class->enum_basetype = mono_class_find_enum_basetype (class);
- if (!class->enum_basetype) {
+ MonoType *enum_basetype = mono_class_find_enum_basetype (class);
+ if (!enum_basetype) {
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
return NULL;
}
- class->cast_class = class->element_class = mono_class_from_mono_type (class->enum_basetype);
+ class->cast_class = class->element_class = mono_class_from_mono_type (enum_basetype);
}
/*
* We must do this after the class has been constructed to make certain recursive scenarios
* work.
*/
- if (class->generic_container)
- mono_metadata_load_generic_param_constraints (
- image, type_token, class->generic_container);
+ if (class->generic_container && !mono_metadata_load_generic_param_constraints_full (image, type_token, class->generic_container)){
+ char *class_name = g_strdup_printf("%s.%s", class->name_space, class->name);
+ char *error = concat_two_strings_with_zero (class->image, class_name, class->image->assembly_name);
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, error);
+ g_free (class_name);
+ mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
+ return NULL;
+ }
+
+ if (class->image->assembly_name && !strcmp (class->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
+ if (!strncmp (name, "Vector", 6))
+ class->simd_type = !strcmp (name + 6, "2d") || !strcmp (name + 6, "2ul") || !strcmp (name + 6, "2l") || !strcmp (name + 6, "4f") || !strcmp (name + 6, "4ui") || !strcmp (name + 6, "4i") || !strcmp (name + 6, "8s") || !strcmp (name + 6, "8us") || !strcmp (name + 6, "16b") || !strcmp (name + 6, "16sb");
+ }
mono_loader_unlock ();
mono_generic_class_get_class (MonoGenericClass *gclass)
{
MonoClass *klass, *gklass;
- int i;
mono_loader_lock ();
if (gclass->cached_class) {
* nesting context should have, but it may also have additional
* generic parameters...
*/
- MonoType *inflated = mono_class_inflate_generic_type (
- &gklass->nested_in->byval_arg, mono_generic_class_get_context (gclass));
- klass->nested_in = mono_class_from_mono_type (inflated);
- mono_metadata_free_type (inflated);
+ klass->nested_in = mono_class_inflate_generic_class (gklass->nested_in,
+ mono_generic_class_get_context (gclass));
}
klass->name = gklass->name;
klass->flags = gklass->flags;
klass->type_token = gklass->type_token;
klass->field.count = gklass->field.count;
- klass->property.count = gklass->property.count;
+ klass->is_inflated = 1;
klass->generic_class = gclass;
klass->this_arg.type = klass->byval_arg.type = MONO_TYPE_GENERICINST;
if (mono_class_is_nullable (klass))
klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
- klass->interface_count = gklass->interface_count;
- klass->interfaces = g_new0 (MonoClass *, klass->interface_count);
- for (i = 0; i < klass->interface_count; i++) {
- MonoType *it = &gklass->interfaces [i]->byval_arg;
- MonoType *inflated = mono_class_inflate_generic_type (it, mono_generic_class_get_context (gclass));
- klass->interfaces [i] = mono_class_from_mono_type (inflated);
- mono_metadata_free_type (inflated);
- }
-
/*
* We're not interested in the nested classes of a generic instance.
* We use the generic type definition to look for nested classes.
*/
- klass->nested_classes = NULL;
if (gklass->parent) {
- MonoType *inflated = mono_class_inflate_generic_type (
- &gklass->parent->byval_arg, mono_generic_class_get_context (gclass));
-
- klass->parent = mono_class_from_mono_type (inflated);
- mono_metadata_free_type (inflated);
+ klass->parent = mono_class_inflate_generic_class (gklass->parent, mono_generic_class_get_context (gclass));
}
if (klass->parent)
mono_class_setup_parent (klass, klass->parent);
if (klass->enumtype) {
- klass->enum_basetype = gklass->enum_basetype;
klass->cast_class = gklass->cast_class;
+ klass->element_class = gklass->element_class;
}
if (gclass->is_dynamic) {
}
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+
+ inflated_classes ++;
+ inflated_classes_size += sizeof (MonoClass);
mono_loader_unlock ();
return klass;
}
-MonoClass *
-mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
+static MonoClass*
+make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is_mvar, MonoGenericParamInfo *pinfo)
{
MonoClass *klass, **ptr;
int count, pos, i;
- mono_loader_lock ();
-
- if (param->pklass) {
- mono_loader_unlock ();
- return param->pklass;
- }
-
- if (!image && param->owner) {
- if (is_mvar) {
- MonoMethod *method = param->owner->owner.method;
- image = (method && method->klass) ? method->klass->image : NULL;
- } else {
- MonoClass *klass = param->owner->owner.klass;
- // FIXME: 'klass' should not be null
- // But, monodis creates GenericContainers without associating a owner to it
- image = klass ? klass->image : NULL;
- }
- }
if (!image)
/* FIXME: */
image = mono_defaults.corlib;
- klass = param->pklass = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+ klass = mono_image_alloc0 (image, sizeof (MonoClass));
+ classes_size += sizeof (MonoClass);
- if (param->name)
- klass->name = param->name;
- else {
- klass->name = mono_mempool_alloc0 (image->mempool, 16);
- sprintf ((char*)klass->name, is_mvar ? "!!%d" : "!%d", param->num);
+ if (pinfo) {
+ klass->name = pinfo->name;
+ } else {
+ int n = mono_generic_param_num (param);
+ klass->name = mono_image_alloc0 (image, 16);
+ sprintf ((char*)klass->name, "%d", n);
}
+
klass->name_space = "";
mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
-
- for (count = 0, ptr = param->constraints; ptr && *ptr; ptr++, count++)
- ;
+
+ count = 0;
+ if (pinfo)
+ for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
+ ;
pos = 0;
- if ((count > 0) && !MONO_CLASS_IS_INTERFACE (param->constraints [0])) {
- klass->parent = param->constraints [0];
+ if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
+ klass->parent = pinfo->constraints [0];
pos++;
- } else if (param->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
+ } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
klass->parent = mono_class_from_name (mono_defaults.corlib, "System", "ValueType");
else
klass->parent = mono_defaults.object_class;
+
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->interfaces [i - pos] = pinfo->constraints [i];
}
- if (!image)
- image = mono_defaults.corlib;
-
klass->image = image;
klass->inited = TRUE;
klass->cast_class = klass->element_class = klass;
- klass->enum_basetype = &klass->element_class->byval_arg;
klass->flags = TYPE_ATTRIBUTE_PUBLIC;
klass->this_arg.type = klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
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);
+ /* FIXME: shouldn't this be ->type_token? */
+ klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
+
+ mono_class_setup_supertypes (klass);
+
+ return klass;
+}
+
+#define FAST_CACHE_SIZE 1024
+static MonoClass *var_cache_fast [FAST_CACHE_SIZE];
+static MonoClass *mvar_cache_fast [FAST_CACHE_SIZE];
+static GHashTable *var_cache_slow;
+static GHashTable *mvar_cache_slow;
+
+static MonoClass *
+get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
+{
+ int n = mono_generic_param_num (param);
+ GHashTable *ht;
+
+ if (n < FAST_CACHE_SIZE)
+ return (is_mvar ? mvar_cache_fast : var_cache_fast) [n];
+ ht = is_mvar ? mvar_cache_slow : var_cache_slow;
+ return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
+}
+
+static void
+set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
+{
+ int n = mono_generic_param_num (param);
+ GHashTable *ht;
+
+ if (n < FAST_CACHE_SIZE) {
+ (is_mvar ? mvar_cache_fast : var_cache_fast) [n] = klass;
+ return;
+ }
+ ht = is_mvar ? mvar_cache_slow : var_cache_slow;
+ if (!ht) {
+ ht = g_hash_table_new (NULL, NULL);
+ if (is_mvar)
+ mvar_cache_slow = ht;
+ else
+ var_cache_slow = ht;
+ }
+
+ g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
+}
+
+/*
+ * LOCKING: Acquires the loader lock.
+ */
+MonoClass *
+mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
+{
+ MonoGenericContainer *container = mono_generic_param_owner (param);
+ MonoGenericParamInfo *pinfo;
+ MonoClass *klass;
+
+ mono_loader_lock ();
+
+ if (container) {
+ pinfo = mono_generic_param_info (param);
+ if (pinfo->pklass) {
+ mono_loader_unlock ();
+ return pinfo->pklass;
+ }
+ } else {
+ pinfo = NULL;
+ image = NULL;
+
+ klass = get_anon_gparam_class (param, is_mvar);
+ if (klass) {
+ mono_loader_unlock ();
+ return klass;
}
}
- mono_class_setup_supertypes (klass);
+ if (!image && container) {
+ if (is_mvar) {
+ MonoMethod *method = container->owner.method;
+ image = (method && method->klass) ? method->klass->image : NULL;
+ } else {
+ MonoClass *klass = container->owner.klass;
+ // FIXME: 'klass' should not be null
+ // But, monodis creates GenericContainers without associating a owner to it
+ image = klass ? klass->image : NULL;
+ }
+ }
+
+ klass = make_generic_param_class (param, image, is_mvar, pinfo);
+
+ mono_memory_barrier ();
+
+ if (container)
+ pinfo->pklass = klass;
+ else
+ set_anon_gparam_class (param, is_mvar, klass);
mono_loader_unlock ();
+ /* FIXME: Should this go inside 'make_generic_param_klass'? */
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
return klass;
mono_loader_unlock ();
return result;
}
- result = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+ result = mono_image_alloc0 (image, sizeof (MonoClass));
+
+ classes_size += 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);
/* Can pointers get boxed? */
result->instance_size = sizeof (gpointer);
result->cast_class = result->element_class = el_class;
- result->enum_basetype = &result->element_class->byval_arg;
result->blittable = TRUE;
result->this_arg.type = result->byval_arg.type = MONO_TYPE_PTR;
- result->this_arg.data.type = result->byval_arg.data.type = result->enum_basetype;
+ result->this_arg.data.type = result->byval_arg.data.type = &result->element_class->byval_arg;
result->this_arg.byref = TRUE;
mono_class_setup_supertypes (result);
result->this_arg.type = result->byval_arg.type = MONO_TYPE_FNPTR;
result->this_arg.data.method = result->byval_arg.data.method = sig;
result->this_arg.byref = TRUE;
- result->enum_basetype = &result->element_class->byval_arg;
result->blittable = TRUE;
mono_class_setup_supertypes (result);
static MonoType *
mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate)
{
+ MonoError error;
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 (NULL, t, context);
+ MonoType *inflated = inflate_generic_type (NULL, t, context, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+
if (inflated) {
t = inflated;
*did_inflate = TRUE;
MonoImage *image;
MonoClass *class;
MonoClass *parent = NULL;
- GSList *list, *rootlist;
+ GSList *list, *rootlist = NULL;
int nsize;
char *name;
gboolean corlib_type = FALSE;
image = eclass->image;
- mono_loader_lock ();
+ if (rank == 1 && !bounded) {
+ /*
+ * This case is very frequent not just during compilation because of calls
+ * from mono_class_from_mono_type (), mono_array_new (),
+ * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
+ */
+ EnterCriticalSection (&image->szarray_cache_lock);
+ if (!image->szarray_cache)
+ image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ class = g_hash_table_lookup (image->szarray_cache, eclass);
+ LeaveCriticalSection (&image->szarray_cache_lock);
+ if (class)
+ return class;
+
+ mono_loader_lock ();
+ } else {
+ mono_loader_lock ();
- if (!image->array_cache)
- image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ if (!image->array_cache)
+ image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
- if ((rootlist = list = g_hash_table_lookup (image->array_cache, eclass))) {
- for (; list; list = list->next) {
- class = list->data;
- if ((class->rank == rank) && (class->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
- mono_loader_unlock ();
- return class;
+ if ((rootlist = list = g_hash_table_lookup (image->array_cache, eclass))) {
+ for (; list; list = list->next) {
+ class = list->data;
+ if ((class->rank == rank) && (class->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
+ mono_loader_unlock ();
+ return class;
+ }
}
}
}
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;
name [nsize + rank] = '*';
name [nsize + rank + bounded] = ']';
name [nsize + rank + bounded + 1] = 0;
- class->name = mono_mempool_strdup (image->mempool, name);
+ class->name = mono_image_strdup (image, name);
g_free (name);
mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
+ classes_size += sizeof (MonoClass);
+
class->type_token = 0;
/* all arrays are marked serializable and sealed, bug #42779 */
class->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED |
class->parent = parent;
class->instance_size = mono_class_instance_size (class->parent);
- if (eclass->enumtype && !eclass->enum_basetype) {
+ if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
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);
mono_class_setup_supertypes (class);
- if (mono_defaults.generic_ilist_class && !bounded && rank == 1) {
- MonoType *args [1];
-
- /* generic IList, ICollection, IEnumerable */
- class->interface_count = 1;
- class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
-
- args [0] = &eclass->byval_arg;
- class->interfaces [0] = mono_class_bind_generic_parameters (
- mono_defaults.generic_ilist_class, 1, args, FALSE);
- }
-
if (eclass->generic_class)
mono_class_init (eclass);
if (!eclass->size_inited)
mono_class_setup_fields (eclass);
+ if (eclass->exception_type) /*FIXME we fail the array type, but we have to let other fields be set.*/
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+
class->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
class->rank = rank;
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;
class->generic_container = eclass->generic_container;
- list = g_slist_append (rootlist, class);
- g_hash_table_insert (image->array_cache, eclass, list);
+ if (rank == 1 && !bounded) {
+ MonoClass *prev_class;
+
+ EnterCriticalSection (&image->szarray_cache_lock);
+ prev_class = g_hash_table_lookup (image->szarray_cache, eclass);
+ if (prev_class)
+ /* Someone got in before us */
+ class = prev_class;
+ else
+ g_hash_table_insert (image->szarray_cache, eclass, class);
+ LeaveCriticalSection (&image->szarray_cache_lock);
+ } else {
+ list = g_slist_append (rootlist, class);
+ g_hash_table_insert (image->array_cache, eclass, list);
+ }
mono_loader_unlock ();
mono_class_get_field_idx (MonoClass *class, int idx)
{
mono_class_setup_fields_locking (class);
+ if (class->exception_type)
+ return NULL;
while (class) {
if (class->image->uncompressed_metadata) {
* class->field.first points to the FieldPtr table, while idx points into the
* Field table, so we have to do a search.
*/
+ /*FIXME this is broken for types with multiple fields with the same name.*/
const char *name = mono_metadata_string_heap (class->image, mono_metadata_decode_row_col (&class->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
int i;
for (i = 0; i < class->field.count; ++i)
- if (class->fields [i].name == name)
+ if (mono_field_get_name (&class->fields [i]) == name)
return &class->fields [i];
g_assert_not_reached ();
} else {
*/
MonoClassField *
mono_class_get_field_from_name (MonoClass *klass, const char *name)
+{
+ return mono_class_get_field_from_name_full (klass, name, NULL);
+}
+
+/**
+ * mono_class_get_field_from_name_full:
+ * @klass: the class to lookup the field.
+ * @name: the field name
+ * @type: the type of the fields. This optional.
+ *
+ * Search the class @klass and it's parents for a field with the name @name and type @type.
+ *
+ * If @klass is an inflated generic type, the type comparison is done with the equivalent field
+ * of its generic type definition.
+ *
+ * Returns: the MonoClassField pointer of the named field or NULL
+ */
+MonoClassField *
+mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
{
int i;
mono_class_setup_fields_locking (klass);
+ if (klass->exception_type)
+ return NULL;
+
while (klass) {
for (i = 0; i < klass->field.count; ++i) {
- if (strcmp (name, klass->fields [i].name) == 0)
- return &klass->fields [i];
+ MonoClassField *field = &klass->fields [i];
+
+ if (strcmp (name, mono_field_get_name (field)) != 0)
+ continue;
+
+ if (type) {
+ MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
+ if (!mono_metadata_type_equal_full (type, field_type, TRUE))
+ continue;
+ }
+ return field;
}
klass = klass->parent;
}
int i;
mono_class_setup_fields_locking (klass);
+ if (klass->exception_type)
+ return 0;
+
while (klass) {
for (i = 0; i < klass->field.count; ++i) {
if (&klass->fields [i] == field) {
klass = klass->parent;
}
- g_assert_not_reached ();
- return 0;
+ g_assert_not_reached ();
+ return 0;
+}
+
+static int
+mono_field_get_index (MonoClassField *field)
+{
+ int index = field - field->parent->fields;
+
+ g_assert (index >= 0 && index < field->parent->field.count);
+
+ return index;
}
/*
{
guint32 cindex;
guint32 constant_cols [MONO_CONSTANT_SIZE];
+ int field_index;
+ MonoClass *klass = field->parent;
g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
- if (!field->data) {
+ if (!klass->ext || !klass->ext->field_def_values) {
+ mono_loader_lock ();
+ mono_class_alloc_ext (klass);
+ if (!klass->ext->field_def_values)
+ klass->ext->field_def_values = mono_image_alloc0 (klass->image, sizeof (MonoFieldDefaultValue) * klass->field.count);
+ mono_loader_unlock ();
+ }
+
+ field_index = mono_field_get_index (field);
+
+ if (!klass->ext->field_def_values [field_index].data) {
cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
g_assert (cindex);
g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
- field->def_type = constant_cols [MONO_CONSTANT_TYPE];
- field->data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
+ klass->ext->field_def_values [field_index].def_type = constant_cols [MONO_CONSTANT_TYPE];
+ klass->ext->field_def_values [field_index].data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
}
- *def_type = field->def_type;
- return field->data;
+ *def_type = klass->ext->field_def_values [field_index].def_type;
+ return klass->ext->field_def_values [field_index].data;
}
guint32
int i;
while (klass) {
- for (i = 0; i < klass->event.count; ++i) {
- if (&klass->events [i] == event)
- return mono_metadata_make_token (MONO_TABLE_EVENT, klass->event.first + i + 1);
+ if (klass->ext) {
+ for (i = 0; i < klass->ext->event.count; ++i) {
+ if (&klass->ext->events [i] == event)
+ return mono_metadata_make_token (MONO_TABLE_EVENT, klass->ext->event.first + i + 1);
+ }
}
klass = klass->parent;
}
int i = 0;
gpointer iter = NULL;
while ((p = mono_class_get_properties (klass, &iter))) {
- if (&klass->properties [i] == prop)
- return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->property.first + i + 1);
+ if (&klass->ext->properties [i] == prop)
+ return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->ext->property.first + i + 1);
i ++;
}
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);
+ return NULL;
}
if (inflated) {
*
* Initializes the class name cache stored in image->name_cache.
*
- * LOCKING: Acquires the loader lock.
+ * LOCKING: Acquires the corresponding image lock.
*/
void
mono_image_init_name_cache (MonoImage *image)
guint32 i, visib, nspace_index;
GHashTable *name_cache2, *nspace_table;
- mono_loader_lock ();
+ mono_image_lock (image);
+
+ if (image->name_cache) {
+ mono_image_unlock (image);
+ return;
+ }
image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
if (image->dynamic) {
- mono_loader_unlock ();
+ mono_image_unlock (image);
return;
}
}
g_hash_table_destroy (name_cache2);
-
- mono_loader_unlock ();
+ mono_image_unlock (image);
}
+/*FIXME Only dynamic assemblies should allow this operation.*/
void
mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
const char *name, guint32 index)
{
GHashTable *nspace_table;
GHashTable *name_cache;
+ guint32 old_index;
- mono_loader_lock ();
+ mono_image_lock (image);
if (!image->name_cache)
mono_image_init_name_cache (image);
nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
}
+
+ if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
+ g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
+
g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
- mono_loader_unlock ();
+ mono_image_unlock (image);
}
typedef struct {
char *name = (char*)key;
FindUserData *data = (FindUserData*)user_data;
- if (!data->value && (g_strcasecmp (name, (char*)data->key) == 0))
+ if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
data->value = value;
}
guint32 token = 0;
FindUserData user_data;
- mono_loader_lock ();
+ mono_image_lock (image);
if (!image->name_cache)
mono_image_init_name_cache (image);
token = GPOINTER_TO_UINT (user_data.value);
}
- mono_loader_unlock ();
+ mono_image_unlock (image);
if (token)
return mono_class_get (image, MONO_TOKEN_TYPE_DEF | token);
continue;
n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
- if (g_strcasecmp (n, name) == 0 && g_strcasecmp (nspace, name_space) == 0)
+ if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
}
return NULL;
}
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
}
}
- mono_loader_lock ();
+ mono_image_lock (image);
if (!image->name_cache)
mono_image_init_name_cache (image);
if (nspace_table)
token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
- mono_loader_unlock ();
+ mono_image_unlock (image);
if (!token && image->dynamic && image->modules) {
/* Search modules as well */
}
if (!token) {
- /*
- * 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.
- */
- MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
- MonoImage *file_image;
-
- 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;
- }
- }
+ class = search_modules (image, name_space, name);
+ if (class)
+ return class;
}
if (!token)
return return_nested_in (class, nested);
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);
- g_assert (references == image->references);
- g_assert (references [idx - 1]);
- if (references [idx - 1] == (gpointer)-1)
+ guint32 assembly_idx;
+
+ assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
+
+ mono_assembly_load_reference (image, assembly_idx - 1);
+ g_assert (image->references [assembly_idx - 1]);
+ if (image->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 (image->references [assembly_idx - 1]->image, name_space, name);
} else {
g_error ("not yet implemented");
}
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))
+ if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
return TRUE;
return FALSE;
* 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;
* _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))
+ if ((mono_generic_container_get_param_info (container, 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 if (((mono_generic_container_get_param_info (container, i)->flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
;
else {
match = FALSE;
}
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);
}
+/*Check if @candidate implements the interface @target*/
+static gboolean
+mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
+{
+ int i;
+
+ do {
+ if (candidate == target)
+ return TRUE;
+
+ /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
+ if (candidate->image->dynamic && !candidate->wastypebuilder) {
+ MonoReflectionTypeBuilder *tb = candidate->reflection_info;
+ int j;
+ if (tb->interfaces) {
+ for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
+ MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
+ MonoClass *iface_class = mono_class_from_mono_type (iface->type);
+ if (iface_class == target || mono_class_implement_interface_slow (target, iface_class))
+ return TRUE;
+ }
+ }
+ } else {
+ /*setup_interfaces don't mono_class_init anything*/
+ mono_class_setup_interfaces (candidate);
+ for (i = 0; i < candidate->interface_count; ++i) {
+ if (candidate->interfaces [i] == target || mono_class_implement_interface_slow (target, candidate->interfaces [i]))
+ return TRUE;
+ }
+ }
+ candidate = candidate->parent;
+ } while (candidate);
+
+ return FALSE;
+}
+
+/*
+ * Check if @oklass can be assigned to @klass.
+ * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
+ */
+gboolean
+mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
+{
+ if (candidate == target)
+ return TRUE;
+ if (target == mono_defaults.object_class)
+ return TRUE;
+
+ /*setup_supertypes don't mono_class_init anything */
+ mono_class_setup_supertypes (candidate);
+ mono_class_setup_supertypes (target);
+
+ if (mono_class_has_parent (candidate, target))
+ return TRUE;
+
+ /*If target is not an interface there is no need to check them.*/
+ if (!MONO_CLASS_IS_INTERFACE (target))
+ return FALSE;
+ return mono_class_implement_interface_slow (target, candidate);
+}
+
/**
* mono_class_get_cctor:
* @klass: A MonoClass pointer
if (mono_class_get_cached_class_info (klass, &cached_info))
return mono_get_method (klass->image, cached_info.cctor_token, klass);
+ if (klass->generic_class && !klass->methods)
+ return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
+
return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
}
if (method)
return (method == caller) ? FALSE : TRUE;
else
- return TRUE;
+ return FALSE;
}
/**
return 8;
case MONO_TYPE_VALUETYPE:
if (type->data.klass->enumtype) {
- type = type->data.klass->enum_basetype;
+ type = mono_class_enum_basetype (type->data.klass);
klass = klass->element_class;
goto handle_enum;
}
case MONO_TYPE_GENERICINST:
type = &type->data.generic_class->container_class->byval_arg;
goto handle_enum;
+
+ case MONO_TYPE_VOID:
+ return 0;
+
default:
g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
}
MonoType*
mono_class_enum_basetype (MonoClass *klass)
{
- return klass->enum_basetype;
+ if (klass->element_class == klass)
+ /* SRE */
+ return NULL;
+ else
+ return &klass->element_class->byval_arg;
}
/**
{
mono_class_setup_properties (klass);
- return klass->property.count;
+ return klass->ext->property.count;
}
/**
{
mono_class_setup_events (klass);
- return klass->event.count;
+ return klass->ext->event.count;
}
/**
return NULL;
if (!*iter) {
mono_class_setup_fields_locking (klass);
+ if (klass->exception_type)
+ return NULL;
/* start from the first */
if (klass->field.count) {
return *iter = &klass->fields [0];
return NULL;
}
+/*
+ * mono_class_get_virtual_methods:
+ *
+ * Iterate over the virtual methods of KLASS.
+ *
+ * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
+ */
+static MonoMethod*
+mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
+{
+ MonoMethod** method;
+ if (!iter)
+ return NULL;
+ if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass) || mono_debug_using_mono_debugger ()) {
+ if (!*iter) {
+ mono_class_setup_methods (klass);
+ /* start from the first */
+ method = &klass->methods [0];
+ } else {
+ method = *iter;
+ method++;
+ }
+ while (method < &klass->methods [klass->method.count]) {
+ if (((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ break;
+ method ++;
+ }
+ if (method < &klass->methods [klass->method.count]) {
+ *iter = method;
+ return *method;
+ } else {
+ return NULL;
+ }
+ } else {
+ /* Search directly in metadata to avoid calling setup_methods () */
+ MonoMethod *res = NULL;
+ int i, start_index;
+
+ if (!*iter) {
+ start_index = 0;
+ } else {
+ start_index = GPOINTER_TO_UINT (*iter);
+ }
+
+ for (i = start_index; i < klass->method.count; ++i) {
+ guint32 cols [MONO_METHOD_SIZE];
+
+ /* 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 (cols [MONO_METHOD_FLAGS] & METHOD_ATTRIBUTE_VIRTUAL)
+ break;
+ }
+
+ if (i < klass->method.count) {
+ res = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
+ /* Add 1 here so the if (*iter) check fails */
+ *iter = GUINT_TO_POINTER (i + 1);
+ return res;
+ } else {
+ return NULL;
+ }
+ }
+}
+
/**
* mono_class_get_properties:
* @klass: the MonoClass to act on
if (!*iter) {
mono_class_setup_properties (klass);
/* start from the first */
- if (klass->property.count) {
- return *iter = &klass->properties [0];
+ if (klass->ext->property.count) {
+ return *iter = &klass->ext->properties [0];
} else {
/* no fields */
return NULL;
}
property = *iter;
property++;
- if (property < &klass->properties [klass->property.count]) {
+ if (property < &klass->ext->properties [klass->ext->property.count]) {
return *iter = property;
}
return NULL;
if (!*iter) {
mono_class_setup_events (klass);
/* start from the first */
- if (klass->event.count) {
- return *iter = &klass->events [0];
+ if (klass->ext->event.count) {
+ return *iter = &klass->ext->events [0];
} else {
/* no fields */
return NULL;
}
event = *iter;
event++;
- if (event < &klass->events [klass->event.count]) {
+ if (event < &klass->ext->events [klass->ext->event.count]) {
return *iter = event;
}
return NULL;
MonoClass** iface;
if (!iter)
return NULL;
- if (!klass->inited)
- mono_class_init (klass);
if (!*iter) {
+ if (!klass->inited)
+ mono_class_init (klass);
+ if (!klass->interfaces_inited)
+ mono_class_setup_interfaces (klass);
/* start from the first */
if (klass->interface_count) {
*iter = &klass->interfaces [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]);
+ mono_class_alloc_ext (klass);
+ klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, 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) {
- *iter = klass->nested_classes;
- return klass->nested_classes->data;
+ if (klass->ext && klass->ext->nested_classes) {
+ *iter = klass->ext->nested_classes;
+ return klass->ext->nested_classes->data;
} else {
/* no nested types */
return NULL;
}
/**
- * mono_field_get_type:
+ * mono_field_get_parent:
* @field: the MonoClassField to act on
*
* Returns: MonoClass where the field was defined.
return field->offset;
}
+static const char *
+mono_field_get_rva (MonoClassField *field)
+{
+ guint32 rva;
+ int field_index;
+ MonoClass *klass = field->parent;
+
+ g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
+
+ if (!klass->ext || !klass->ext->field_def_values) {
+ mono_loader_lock ();
+ mono_class_alloc_ext (klass);
+ if (!klass->ext->field_def_values)
+ klass->ext->field_def_values = mono_image_alloc0 (klass->image, sizeof (MonoFieldDefaultValue) * klass->field.count);
+ mono_loader_unlock ();
+ }
+
+ field_index = mono_field_get_index (field);
+
+ if (!klass->ext->field_def_values [field_index].data && !klass->image->dynamic) {
+ mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
+ if (!rva)
+ g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
+ klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
+ }
+
+ return klass->ext->field_def_values [field_index].data;
+}
+
/**
* mono_field_get_data;
* @field: the MonoClassField to act on
* data if it has an RVA flag.
*/
const char *
-mono_field_get_data (MonoClassField *field)
+mono_field_get_data (MonoClassField *field)
{
- return field->data;
+ if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
+ MonoTypeEnum def_type;
+
+ return mono_class_get_field_default_value (field, &def_type);
+ } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
+ return mono_field_get_rva (field);
+ } else {
+ return NULL;
+ }
}
/**
mono_class_init (klass);
- if (klass->methods || klass->generic_class) {
+ if (klass->generic_class && !klass->methods) {
+ res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
+ if (res)
+ res = mono_class_inflate_generic_method_full (res, klass, mono_class_get_context (klass));
+ return res;
+ }
+
+ if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
mono_class_setup_methods (klass);
for (i = 0; i < klass->method.count; ++i) {
MonoMethod *method = klass->methods [i];
mono_loader_lock ();
klass->exception_type = ex_type;
if (ex_data)
- mono_property_hash_insert (klass->image->property_hash, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
+ mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
mono_loader_unlock ();
return TRUE;
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;
+ return mono_image_property_lookup (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
}
/**
void
mono_classes_init (void)
{
+ mono_counters_register ("Inflated methods size",
+ MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
+ mono_counters_register ("Inflated classes",
+ MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes);
+ mono_counters_register ("Inflated classes size",
+ MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
+ mono_counters_register ("MonoClass size",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
+ mono_counters_register ("MonoClassExt size",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
}
/**
*
* Visibility checks ignoring generic instantiations.
*/
-static gboolean
+gboolean
mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
{
int i;
return TRUE;
if (!accessed || !accessing)
return FALSE;
+
+ /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
+ * anywhere so untrusted friends are not safe to access platform's code internals */
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
+ if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
+ 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 */
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;
+ switch (type->type) {
+ case MONO_TYPE_SZARRAY:
+ if (!can_access_type (access_klass, type->data.klass))
+ return FALSE;
+ break;
+ case MONO_TYPE_ARRAY:
+ if (!can_access_type (access_klass, type->data.array->eklass))
+ return FALSE;
+ break;
+ case MONO_TYPE_PTR:
+ if (!can_access_type (access_klass, mono_class_from_mono_type (type->data.type)))
+ return FALSE;
+ break;
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_VALUETYPE:
+ case MONO_TYPE_GENERICINST:
+ 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;
+ int access_level;
+
+ if (access_klass->element_class && !access_klass->enumtype)
+ access_klass = access_klass->element_class;
+
+ if (member_klass->element_class && !member_klass->enumtype)
+ member_klass = member_klass->element_class;
+
+ access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+
+ if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
+ return TRUE;
if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
return FALSE;
if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
return FALSE;
+ /*Non nested type with nested visibility. We just fail it.*/
+ if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
+ return FALSE;
+
switch (access_level) {
case TYPE_ATTRIBUTE_NOT_PUBLIC:
return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
}
/*
- * mono_method_can_access_method_with_context:
+ * mono_method_can_access_method_full:
* @method: The caller method
* @called: The called method
- * @context_klass:TThe static type on stack of the owner @called object used
+ * @context_klass: The 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.
+ * It can be used with static methods, but context_klass should be NULL.
*
* Returns: TRUE if caller have proper visibility and acessibility to @called
*/
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 FALSE;
}
return TRUE;
/*
- * mono_method_can_access_method_with_context:
+ * mono_method_can_access_field_full:
* @method: The caller method
* @field: The accessed field
* @context_klass: The static type on stack of the owner @field object used
return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
}
+static gboolean gshared_supported;
+
+void
+mono_set_generic_sharing_supported (gboolean supported)
+{
+ gshared_supported = supported;
+}
+
/*
* mono_class_generic_sharing_enabled:
* @class: a class
gboolean
mono_class_generic_sharing_enabled (MonoClass *class)
{
-#if defined(__i386__) || defined(__x86_64__)
- 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_COLLECTIONS;
+ if (gshared_supported)
+ generic_sharing = MONO_GENERIC_SHARING_ALL;
else
generic_sharing = MONO_GENERIC_SHARING_NONE;
g_warning ("Unknown generic sharing option `%s'.", option);
}
- if (!supported)
+ if (!gshared_supported)
generic_sharing = MONO_GENERIC_SHARING_NONE;
inited = TRUE;
g_assert_not_reached ();
}
}
+
+/*
+ * mono_class_setup_interface_id:
+ *
+ * Initializes MonoClass::interface_id if required.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
+void
+mono_class_setup_interface_id (MonoClass *class)
+{
+ mono_loader_lock ();
+ if (MONO_CLASS_IS_INTERFACE (class) && !class->interface_id)
+ class->interface_id = mono_get_unique_iid (class);
+ mono_loader_unlock ();
+}
+
+/*
+ * mono_class_alloc_ext:
+ *
+ * Allocate klass->ext if not already done.
+ * LOCKING: Assumes the loader lock is held.
+ */
+void
+mono_class_alloc_ext (MonoClass *klass)
+{
+ if (!klass->ext) {
+ if (klass->generic_class) {
+ klass->ext = g_new0 (MonoClassExt, 1);
+ } else {
+ klass->ext = mono_image_alloc0 (klass->image, sizeof (MonoClassExt));
+ }
+ class_ext_size += sizeof (MonoClassExt);
+ }
+}
+
+/*
+ * mono_class_setup_interfaces:
+ *
+ * Initialize class->interfaces/interfaces_count.
+ * LOCKING: Acquires the loader lock.
+ */
+void
+mono_class_setup_interfaces (MonoClass *klass)
+{
+ int i;
+
+ if (klass->interfaces_inited)
+ return;
+
+ mono_loader_lock ();
+
+ if (klass->interfaces_inited) {
+ mono_loader_unlock ();
+ return;
+ }
+
+ if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY && mono_defaults.generic_ilist_class) {
+ MonoType *args [1];
+
+ /* generic IList, ICollection, IEnumerable */
+ klass->interface_count = 1;
+ klass->interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * klass->interface_count);
+
+ args [0] = &klass->element_class->byval_arg;
+ klass->interfaces [0] = mono_class_bind_generic_parameters (
+ mono_defaults.generic_ilist_class, 1, args, FALSE);
+ } else if (klass->generic_class) {
+ MonoClass *gklass = klass->generic_class->container_class;
+
+ klass->interface_count = gklass->interface_count;
+ klass->interfaces = g_new0 (MonoClass *, klass->interface_count);
+ for (i = 0; i < klass->interface_count; i++)
+ klass->interfaces [i] = mono_class_inflate_generic_class (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class));
+ }
+
+ mono_memory_barrier ();
+
+ klass->interfaces_inited = TRUE;
+
+ mono_loader_unlock ();
+}