* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#ifdef HAVE_ALLOCA_H
#include <string.h>
#include <stdlib.h>
#include <mono/metadata/image.h>
+#include <mono/metadata/image-internals.h>
#include <mono/metadata/assembly.h>
+#include <mono/metadata/assembly-internals.h>
#include <mono/metadata/metadata.h>
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/profiler-private.h>
gboolean mono_align_small_structs = FALSE;
/* Statistics */
-guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
-guint32 classes_size, class_ext_size;
+guint32 inflated_classes_size, inflated_methods_size;
+guint32 classes_size, class_ext_size, class_ext_count;
+guint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
/* Low level lock which protects data structures in this module */
static mono_mutex_t classes_mutex;
static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
+static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error);
+static gpointer mono_class_get_exception_data (const MonoClass *klass);
+
+
/*
We use gclass recording to allow recursive system f types to be referenced by a parent.
static GSList *gclass_recorded_list;
typedef gboolean (*gclass_record_func) (MonoClass*, void*);
+/* This TLS variable points to a GSList of classes which have setup_fields () executing */
+static MonoNativeTlsKey setup_fields_tls_id;
+
+static MonoNativeTlsKey init_pending_tls_id;
+
static inline void
classes_lock (void)
{
}
}
-/*
+/**
* mono_class_from_typeref:
* @image: a MonoImage
* @type_token: a TypeRef token
*
* Creates the MonoClass* structure representing the type defined by
* the typeref token valid inside @image.
- * Returns: the MonoClass* representing the typeref token, NULL ifcould
+ * Returns: The MonoClass* representing the typeref token, NULL ifcould
* not be loaded.
*/
MonoClass *
return klass;
}
+/**
+ * mono_class_from_typeref_checked:
+ * @image: a MonoImage
+ * @type_token: a TypeRef token
+ * @error: error return code, if any.
+ *
+ * Creates the MonoClass* structure representing the type defined by
+ * the typeref token valid inside @image.
+ *
+ * Returns: The MonoClass* representing the typeref token, NULL if it could
+ * not be loaded with the @error value filled with the information about the
+ * error.
+ */
MonoClass *
mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
{
goto done;
case MONO_RESOLUTION_SCOPE_MODULEREF:
- module = mono_image_load_module (image, idx);
+ module = mono_image_load_module_checked (image, idx, error);
if (module)
res = mono_class_from_name_checked (module, nspace, name, error);
goto done;
}
enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
if (enclosing->nested_classes_inited && enclosing->ext) {
/* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
done:
/* Generic case, should be avoided for when a better error is possible. */
if (!res && mono_error_ok (error)) {
- if (mono_loader_get_last_error ()) { /*FIXME plug the above to not leak errors*/
- mono_error_set_from_loader_error (error);
- } else {
- char *name = mono_class_name_from_token (image, type_token);
- char *assembly = mono_assembly_name_from_token (image, type_token);
- mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
- }
+ char *name = mono_class_name_from_token (image, type_token);
+ char *assembly = mono_assembly_name_from_token (image, type_token);
+ mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
}
- mono_loader_assert_no_error ();
return res;
}
}
if (is_recursed)
break;
- if (klass->generic_class) {
- MonoGenericClass *gclass = klass->generic_class;
+ if (mono_class_is_ginst (klass)) {
+ MonoGenericClass *gclass = mono_class_get_generic_class (klass);
MonoGenericInst *inst = gclass->context.class_inst;
MonoTypeNameFormat nested_format;
int i;
g_string_append_c (str, '>');
else
g_string_append_c (str, ']');
- } else if (klass->generic_container &&
+ } else if (mono_class_is_gtd (klass) &&
(format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
(format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
int i;
g_string_append_c (str, '<');
else
g_string_append_c (str, '[');
- for (i = 0; i < klass->generic_container->type_argc; i++) {
+ for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
if (i)
g_string_append_c (str, ',');
- g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
+ g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
}
if (format == MONO_TYPE_NAME_FORMAT_IL)
g_string_append_c (str, '>');
* @format: the format for the return string.
*
*
- * Returns: the string representation in a number of formats:
+ * Returns: The string representation in a number of formats:
*
* if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
* returned in the formatrequired by System.Reflection, this is the
* mono_type_get_full_name:
* @class: a class
*
- * Returns: the string representation for type as required by System.Reflection.
+ * Returns: The string representation for type as required by System.Reflection.
* The inverse of mono_reflection_parse_type ().
*/
char *
* mono_type_get_name:
* @type: a type
*
- * Returns: the string representation for type as it would be represented in IL code.
+ * Returns: The string representation for type as it would be represented in IL code.
*/
char*
mono_type_get_name (MonoType *type)
* mono_type_get_underlying_type:
* @type: a type
*
- * Returns: the MonoType for the underlying integer type if @type
+ * Returns: The MonoType for the underlying integer type if @type
* is an enum and byref is false, otherwise the type itself.
*/
MonoType*
return type;
}
-/*
+/**
* mono_class_is_open_constructed_type:
* @type: a type
*
- * Returns TRUE if type represents a generics open constructed type.
+ * Returns: TRUE if type represents a generics open constructed type.
* IOW, not all type parameters required for the instantiation have
* been provided or it's a generic type definition.
*
return t->data.generic_class->context.class_inst->is_open;
case MONO_TYPE_CLASS:
case MONO_TYPE_VALUETYPE:
- return t->data.klass->generic_container != NULL;
+ return mono_class_is_gtd (t->data.klass);
default:
return FALSE;
}
return NULL;
inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
+
if (inst != gclass->context.class_inst)
gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
case MONO_TYPE_CLASS:
case MONO_TYPE_VALUETYPE: {
MonoClass *klass = type->data.klass;
- MonoGenericContainer *container = klass->generic_container;
+ MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
MonoGenericInst *inst;
MonoGenericClass *gclass = NULL;
MonoType *nt;
/* We can't use context->class_inst directly, since it can have more elements */
inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
+
if (inst == container->context.class_inst)
return NULL;
MonoGenericContext *
mono_class_get_context (MonoClass *klass)
{
- return klass->generic_class ? mono_generic_class_get_context (klass->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;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ return gklass ? mono_generic_class_get_context (gklass) : NULL;
}
/*
if (context)
inflated = inflate_generic_type (image, type, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
if (!inflated) {
MonoType *shared = mono_metadata_get_shared_type (type);
* 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
+ * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
* on the heap and is owned by the caller. Returns NULL on error.
*
* @deprecated Please use mono_class_inflate_generic_type_checked instead
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;
- }
+ mono_error_cleanup (&error);
return result;
}
* 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
+ * 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_error_init (error);
if (context) {
inflated = inflate_generic_type (image, type, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
}
if (!inflated)
return inflated;
}
+/*
+ * mono_class_inflate_generic_class:
+ *
+ * Inflate the class @gklass with @context. Set @error on failure.
+ */
MonoClass*
mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
{
MonoType *inflated;
inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
res = mono_class_from_mono_type (inflated);
mono_metadata_free_type (inflated);
return res;
}
-/*
- * 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;
-
- res = mono_class_inflate_generic_class_checked (gklass, context, &error);
- g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
-
- return res;
-}
-
-
static MonoGenericContext
inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
*
* Instantiate the generic method @method using the generics context @context.
*
- * Returns: the new instantiated method
+ * Returns: The new instantiated method
*/
MonoMethod *
mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
MonoMethodInflated *imethod = (MonoMethodInflated *) method;
tmp_context = inflate_generic_context (method_context, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
+
context = &tmp_context;
if (mono_metadata_generic_context_equal (method_context, context))
*
*/
if (!((method->is_generic && context->method_inst) ||
- (method->klass->generic_container && context->class_inst)))
+ (mono_class_is_gtd (method->klass) && context->class_inst)))
return method;
iresult = g_new0 (MonoMethodInflated, 1);
iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
if (!context->class_inst) {
- g_assert (!iresult->declaring->klass->generic_class);
- if (iresult->declaring->klass->generic_container)
- iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
- else if (iresult->declaring->klass->generic_class)
- iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
+ g_assert (!mono_class_is_ginst (iresult->declaring->klass));
+ if (mono_class_is_gtd (iresult->declaring->klass))
+ iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
}
/* This can happen with some callers like mono_object_get_virtual_method () */
- if (!iresult->declaring->klass->generic_container && !iresult->declaring->klass->generic_class)
+ if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
iresult->context.class_inst = NULL;
MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
result->sre_method = FALSE;
result->signature = NULL;
- if (!context->method_inst) {
+ if (method->wrapper_type) {
+ MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
+ MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
+ int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
+
+ resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
+ memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
+ }
+
+ if (iresult->context.method_inst) {
/* Set the generic_container of the result to the generic_container of method */
MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
- if (generic_container) {
+ if (generic_container && iresult->context.method_inst == generic_container->context.method_inst) {
result->is_generic = 1;
mono_method_set_generic_container (result, generic_container);
}
}
- if (!klass_hint || !klass_hint->generic_class ||
- klass_hint->generic_class->container_class != method->klass ||
- klass_hint->generic_class->context.class_inst != context->class_inst)
- klass_hint = NULL;
+ if (klass_hint) {
+ MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
+ if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
+ klass_hint = NULL;
+ }
- if (method->klass->generic_container)
+ if (mono_class_is_gtd (method->klass))
result->klass = klass_hint;
if (!result->klass) {
return NULL;
if (method->is_generic)
return &(mono_method_get_generic_container (method)->context);
- if (method->klass->generic_container)
- return &method->klass->generic_container->context;
+ if (mono_class_is_gtd (method->klass))
+ return &mono_class_get_generic_container (method->klass)->context;
return NULL;
}
MonoGenericContainer *container = NULL;
MonoImage *m = klass->image;
const int top = klass->field.count;
- int i;
+ int i, first_field_idx;
g_assert (klass->enumtype);
mono_error_init (error);
- if (klass->generic_container)
- container = klass->generic_container;
- else if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ container = mono_class_try_get_generic_container (klass);
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
- container = gklass->generic_container;
+ container = mono_class_get_generic_container (gklass);
g_assert (container);
}
/*
* Fetch all the field information.
*/
+ first_field_idx = mono_class_get_first_field_idx (klass);
for (i = 0; i < top; i++){
const char *sig;
guint32 cols [MONO_FIELD_SIZE];
- int idx = klass->field.first + i;
+ int idx = first_field_idx + i;
MonoType *ftype;
- /* klass->field.first and idx points into the fieldptr table */
+ /* first_field_idx 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
goto fail;
}
- ftype = mono_metadata_parse_type_full (m, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
- if (!ftype) {
- if (mono_loader_get_last_error ()) /*FIXME plug the above to not leak errors*/
- mono_error_set_from_loader_error (error);
- else
- mono_error_set_bad_image (error, klass->image, "Could not parse type for field signature %x", cols [MONO_FIELD_SIGNATURE]);
+ ftype = mono_metadata_parse_type_checked (m, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
+ if (!ftype)
goto fail;
- }
- if (klass->generic_class) {
+
+ if (mono_class_is_ginst (klass)) {
//FIXME do we leak here?
ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
if (!mono_error_ok (error))
mono_error_set_type_load_class (error, klass, "Could not find base type");
fail:
- mono_loader_assert_no_error ();
return NULL;
}
/*
- * Checks for MonoClass::exception_type without resolving all MonoType's into MonoClass'es
+ * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
*/
static gboolean
mono_type_has_exceptions (MonoType *type)
case MONO_TYPE_CLASS:
case MONO_TYPE_VALUETYPE:
case MONO_TYPE_SZARRAY:
- return type->data.klass->exception_type;
+ return mono_class_has_failure (type->data.klass);
case MONO_TYPE_ARRAY:
- return type->data.array->eklass->exception_type;
+ return mono_class_has_failure (type->data.array->eklass);
case MONO_TYPE_GENERICINST:
- return mono_generic_class_get_class (type->data.generic_class)->exception_type;
+ return mono_class_has_failure (mono_generic_class_get_class (type->data.generic_class));
default:
return FALSE;
}
}
+void
+mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
+{
+ g_assert (mono_class_has_failure (klass));
+ MonoErrorBoxed *box = (MonoErrorBoxed*)mono_class_get_exception_data (klass);
+ mono_error_set_from_boxed (oerror, box);
+}
+
+
/*
* mono_class_alloc:
*
* Allocate memory for some data belonging to CLASS, either from its image's mempool,
* or from the heap.
*/
-static gpointer
+gpointer
mono_class_alloc (MonoClass *klass, int size)
{
- if (klass->generic_class)
- return mono_image_set_alloc (klass->generic_class->owner, size);
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ if (gklass)
+ return mono_image_set_alloc (gklass->owner, size);
else
return mono_image_alloc (klass->image, size);
}
-static gpointer
+gpointer
mono_class_alloc0 (MonoClass *klass, int size)
{
gpointer res;
* mono_class_setup_basic_field_info:
* @class: The class to initialize
*
- * Initializes the klass->fields.
- * LOCKING: Assumes the loader lock is held.
+ * Initializes the following fields in MonoClass:
+ * * klass->fields (only field->parent and field->name)
+ * * klass->field.count
+ * * klass->first_field_idx
+ * LOCKING: Acquires the loader lock
*/
static void
mono_class_setup_basic_field_info (MonoClass *klass)
{
+ MonoGenericClass *gklass;
MonoClassField *field;
+ MonoClassField *fields;
MonoClass *gtd;
MonoImage *image;
int i, top;
if (klass->fields)
return;
- gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+ gklass = mono_class_try_get_generic_class (klass);
+ gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
image = klass->image;
- top = klass->field.count;
- if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
+
+ if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
/*
* This happens when a generic instance of an unfinished generic typebuilder
* is used as an element type for creating an array type. We can't initialize
if (gtd) {
mono_class_setup_basic_field_info (gtd);
- top = gtd->field.count;
- klass->field.first = gtd->field.first;
+ mono_loader_lock ();
klass->field.count = gtd->field.count;
+ mono_loader_unlock ();
}
- klass->fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
+ top = klass->field.count;
+
+ fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
/*
* Fetch all the field information.
*/
- for (i = 0; i < top; i++){
- field = &klass->fields [i];
+ int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
+ for (i = 0; i < top; i++) {
+ field = &fields [i];
field->parent = klass;
if (gtd) {
field->name = mono_field_get_name (>d->fields [i]);
} else {
- int idx = klass->field.first + i;
- /* klass->field.first and idx points into the fieldptr table */
+ int idx = first_field_idx + i;
+ /* first_field_idx and idx points into the fieldptr table */
guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
/* The name is needed for fieldrefs */
field->name = mono_metadata_string_heap (image, name_idx);
}
}
+
+ mono_memory_barrier ();
+
+ mono_loader_lock ();
+ if (!klass->fields)
+ klass->fields = fields;
+ mono_loader_unlock ();
}
+/**
+ * mono_class_set_failure_causedby_class:
+ * @klass: the class that is failing
+ * @caused_by: the class that caused the failure
+ * @msg: Why @klass is failing.
+ *
+ * If @caused_by has a failure, sets a TypeLoadException failure on
+ * @klass with message "@msg, due to: {@caused_by message}".
+ *
+ * Returns: TRUE if a failiure was set, or FALSE if @caused_by doesn't have a failure.
+ */
+static gboolean
+mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
+{
+ if (mono_class_has_failure (caused_by)) {
+ MonoError cause_error;
+ mono_error_init (&cause_error);
+ mono_error_set_for_class_failure (&cause_error, caused_by);
+ mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (&cause_error));
+ mono_error_cleanup (&cause_error);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
/**
* mono_class_setup_fields:
- * @class: The class to initialize
+ * @klass: The class to initialize
+ *
+ * Initializes klass->fields, computes class layout and sizes.
+ * typebuilder_setup_fields () is the corresponding function for dynamic classes.
+ * Sets the following fields in @klass:
+ * - all the fields initialized by mono_class_init_sizes ()
+ * - element_class/cast_class (for enums)
+ * - field->type/offset for all fields
+ * - fields_inited
*
- * Initializes the klass->fields.
- * LOCKING: Assumes the loader lock is held.
+ * LOCKING: Acquires the loader lock.
*/
-static void
+void
mono_class_setup_fields (MonoClass *klass)
{
MonoError error;
MonoImage *m = klass->image;
int top;
- guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
- int i, blittable = TRUE;
+ guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
+ int i;
guint32 real_size = 0;
guint32 packing_size = 0;
+ int instance_size;
gboolean explicit_size;
MonoClassField *field;
- MonoGenericContainer *container = NULL;
- MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
- /*
- * FIXME: We have a race condition here. It's possible that this function returns
- * to its caller with `instance_size` set to `0` instead of the actual size. This
- * is not a problem when the function is called recursively on the same class,
- * because the size will be initialized by the outer invocation. What follows is a
- * description of how it can occur in other cases, too. There it is a problem,
- * because it can lead to the GC being asked to allocate an object of size `0`,
- * which SGen chokes on. The race condition is triggered infrequently by
- * `tests/sgen-suspend.cs`.
- *
- * This function is called for a class whenever one of its subclasses is inited.
- * For example, it's called for every subclass of Object. What it does is this:
- *
- * if (klass->setup_fields_called)
- * return;
- * ...
- * klass->instance_size = 0;
- * ...
- * klass->setup_fields_called = 1;
- * ... critical point
- * klass->instance_size = actual_instance_size;
- *
- * The last two steps are sometimes reversed, but that only changes the way in which
- * the race condition works.
- *
- * Assume thread A goes through this function and makes it to the critical point.
- * Now thread B runs the function and, since `setup_fields_called` is set, returns
- * immediately, but `instance_size` is incorrect.
- *
- * The other case looks like this:
- *
- * if (klass->setup_fields_called)
- * return;
- * ... critical point X
- * klass->instance_size = 0;
- * ... critical point Y
- * klass->instance_size = actual_instance_size;
- * ...
- * klass->setup_fields_called = 1;
- *
- * Assume thread A goes through the function and makes it to critical point X. Now
- * thread B runs through the whole of the function, returning, assuming
- * `instance_size` is set. At that point thread A gets to run and makes it to
- * critical point Y, at which time `instance_size` is `0` again, invalidating thread
- * B's assumption.
- */
- if (klass->setup_fields_called)
+ if (klass->fields_inited)
return;
- if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
+ if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
/*
* This happens when a generic instance of an unfinished generic typebuilder
* is used as an element type for creating an array type. We can't initialize
if (gtd) {
mono_class_setup_fields (gtd);
- if (gtd->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
return;
- }
}
- klass->instance_size = 0;
- if (!klass->rank)
- klass->sizes.class_size = 0;
-
+ instance_size = 0;
if (klass->parent) {
/* For generic instances, klass->parent might not have been initialized */
mono_class_init (klass->parent);
- if (!klass->parent->size_inited) {
- mono_class_setup_fields (klass->parent);
- if (klass->parent->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- return;
- }
- }
- klass->instance_size += klass->parent->instance_size;
- klass->min_align = klass->parent->min_align;
- /* we use |= since it may have been set already */
- klass->has_references |= klass->parent->has_references;
- blittable = klass->parent->blittable;
+ mono_class_setup_fields (klass->parent);
+ if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
+ return;
+ instance_size = klass->parent->instance_size;
} else {
- klass->instance_size = sizeof (MonoObject);
- klass->min_align = 1;
+ instance_size = sizeof (MonoObject);
}
- /* 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 (klass->simd_type)
- klass->min_align = 16;
- */
/* Get the real size */
explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
+ if (explicit_size)
+ instance_size += real_size;
- if (explicit_size) {
- if ((packing_size & 0xffffff00) != 0) {
- char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
- return;
- }
- klass->packing_size = packing_size;
- real_size += klass->instance_size;
- }
-
- if (!top) {
- if (explicit_size && real_size) {
- klass->instance_size = MAX (real_size, klass->instance_size);
- }
- klass->blittable = blittable;
- mono_memory_barrier ();
- klass->size_inited = 1;
- klass->fields_inited = 1;
- klass->setup_fields_called = 1;
+ /*
+ * This function can recursively call itself.
+ * Prevent infinite recursion by using a list in TLS.
+ */
+ GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
+ if (g_slist_find (init_list, klass))
return;
- }
-
- if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")))
- blittable = FALSE;
-
- /* Prevent infinite loops if the class references itself */
- klass->setup_fields_called = 1;
-
- if (klass->generic_container) {
- container = klass->generic_container;
- } else if (gtd) {
- container = gtd->generic_container;
- g_assert (container);
- }
+ init_list = g_slist_prepend (init_list, klass);
+ mono_native_tls_set_value (setup_fields_tls_id, init_list);
/*
* Fetch all the field information.
*/
- for (i = 0; i < top; i++){
- int idx = klass->field.first + i;
+ int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
+ for (i = 0; i < top; i++) {
+ int idx = first_field_idx + i;
field = &klass->fields [i];
- field->parent = klass;
-
if (!field->type) {
mono_field_resolve_type (field, &error);
if (!mono_error_ok (&error)) {
/*mono_field_resolve_type already failed class*/
mono_error_cleanup (&error);
- return;
+ break;
}
if (!field->type)
g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
if (mono_field_is_deleted (field))
continue;
- if (gtd) {
- MonoClassField *gfield = >d->fields [i];
- field->offset = gfield->offset;
- } else {
- if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
- guint32 offset;
- mono_metadata_field_info (m, idx, &offset, NULL, NULL);
- field->offset = offset;
+ if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
+ guint32 uoffset;
+ mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
+ int offset = uoffset;
- if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Missing field layout info for %s", field->name));
- break;
- }
- if (field->offset < -1) { /*-1 is used to encode special static fields */
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name));
- break;
- }
- if (klass->generic_container) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic class cannot have explicit layout."));
- break;
- }
+ if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+ mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
+ break;
}
- }
-
- /* Only do these checks if we still think this type is blittable */
- if (blittable && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
- 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 (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- break;
- }
- }
- if (!field_class || !field_class->blittable)
- blittable = FALSE;
+ if (offset < -1) { /*-1 is used to encode special static fields */
+ mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
+ break;
+ }
+ if (mono_class_is_gtd (klass)) {
+ mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
+ break;
}
}
-
- if (klass->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
- blittable = klass->element_class->blittable;
- }
-
if (mono_type_has_exceptions (field->type)) {
char *class_name = mono_type_get_full_name (klass);
char *type_name = mono_type_full_name (field->type);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "");
g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
g_free (class_name);
g_free (type_name);
/* The def_value of fields is compute lazily during vtable creation */
}
- if (klass == mono_defaults.string_class)
- blittable = FALSE;
+ if (!mono_class_has_failure (klass))
+ mono_class_layout_fields (klass, instance_size, packing_size, FALSE);
- klass->blittable = blittable;
+ init_list = g_slist_remove (init_list, klass);
+ mono_native_tls_set_value (setup_fields_tls_id, init_list);
+}
- if (klass->enumtype && !mono_class_enum_basetype (klass)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- return;
+static void
+init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
+{
+ if (cached_info) {
+ klass->instance_size = cached_info->instance_size;
+ klass->sizes.class_size = cached_info->class_size;
+ klass->packing_size = cached_info->packing_size;
+ klass->min_align = cached_info->min_align;
+ klass->blittable = cached_info->blittable;
+ klass->has_references = cached_info->has_references;
+ klass->has_static_refs = cached_info->has_static_refs;
+ klass->no_special_static_fields = cached_info->no_special_static_fields;
}
- if (explicit_size && real_size) {
- klass->instance_size = MAX (real_size, klass->instance_size);
+ else {
+ if (!klass->size_inited)
+ mono_class_setup_fields (klass);
}
-
- if (klass->exception_type)
- return;
- mono_class_layout_fields (klass);
-
- /*valuetypes can't be neither bigger than 1Mb or empty. */
- if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-
- mono_memory_barrier ();
- klass->fields_inited = 1;
}
+/*
-/**
- * mono_class_setup_fields_locking:
- * @class: The class to initialize
+ * mono_class_init_sizes:
*
- * Initializes the klass->fields array of fields.
- * Aquires the loader lock.
- */
-void
-mono_class_setup_fields_locking (MonoClass *klass)
-{
- /* This can be checked without locks */
- if (klass->fields_inited)
- return;
- mono_loader_lock ();
- mono_class_setup_fields (klass);
- mono_loader_unlock ();
-}
-
-/*
- * mono_class_has_references:
+ * Initializes the size related fields of @klass without loading all field data if possible.
+ * Sets the following fields in @klass:
+ * - instance_size
+ * - sizes.class_size
+ * - packing_size
+ * - min_align
+ * - blittable
+ * - has_references
+ * - has_static_refs
+ * - size_inited
+ * Can fail the class.
*
- * Returns whenever @klass->has_references is set, initializing it if needed.
- * Aquires the loader lock.
+ * LOCKING: Acquires the loader lock.
*/
-static gboolean
-mono_class_has_references (MonoClass *klass)
+static void
+mono_class_init_sizes (MonoClass *klass)
{
- if (klass->init_pending) {
- /* Be conservative */
- return TRUE;
- } else {
- mono_class_init (klass);
+ MonoCachedClassInfo cached_info;
+ gboolean has_cached_info;
- return klass->has_references;
- }
+ has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
+
+ init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
}
/*
return type;
}
+static gboolean
+class_has_references (MonoClass *klass)
+{
+ mono_class_init_sizes (klass);
+
+ /*
+ * has_references is not set if this is called recursively, but this is not a problem since this is only used
+ * during field layout, and instance fields are initialized before static fields, and instance fields can't
+ * embed themselves.
+ */
+ return klass->has_references;
+}
+
static gboolean
type_has_references (MonoClass *klass, MonoType *ftype)
{
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type (ftype)))))
return TRUE;
if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
MonoGenericParam *gparam = ftype->data.generic_param;
if (gparam->gshared_constraint)
- return mono_class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
+ return class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
}
return FALSE;
}
/*
* mono_class_layout_fields:
* @class: a class
+ * @base_instance_size: base instance size
+ * @packing_size:
*
- * Compute the placement of fields inside an object or struct, according to
- * the layout rules and set the following fields in @class:
- * - has_references (if the class contains instance references firled or structs that contain references)
- * - has_static_refs (same, but for static fields)
- * - instance_size (size of the object in memory)
- * - class_size (size needed for the static fields)
- * - size_inited (flag set when the instance_size is set)
+ * This contains the common code for computing the layout of classes and sizes.
+ * This should only be called from mono_class_setup_fields () and
+ * typebuilder_setup_fields ().
*
- * LOCKING: this is supposed to be called with the loader lock held.
+ * LOCKING: Acquires the loader lock
*/
void
-mono_class_layout_fields (MonoClass *klass)
+mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre)
{
int i;
const int top = klass->field.count;
- guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
+ guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
guint32 pass, passes, real_size;
gboolean gc_aware_layout = FALSE;
gboolean has_static_fields = FALSE;
+ gboolean has_references = FALSE;
+ gboolean has_static_refs = FALSE;
MonoClassField *field;
+ gboolean blittable;
+ int instance_size = base_instance_size;
+ int class_size, min_align;
+ int *field_offsets;
+
+ /*
+ * We want to avoid doing complicated work inside locks, so we compute all the required
+ * information and write it to @klass inside a lock.
+ */
+ if (klass->fields_inited)
+ return;
+
+ if ((packing_size & 0xffffff00) != 0) {
+ mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
+ return;
+ }
+
+ if (klass->parent) {
+ min_align = klass->parent->min_align;
+ /* we use | since it may have been set already */
+ has_references = klass->has_references | klass->parent->has_references;
+ } else {
+ 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 (klass->simd_type)
+ min_align = 16;
+ */
/*
* When we do generic sharing we need to have layout
* container), so we don't return in that case anymore.
*/
+ if (klass->enumtype) {
+ for (i = 0; i < top; i++) {
+ field = &klass->fields [i];
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+ klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
+ break;
+ }
+ }
+
+ if (!mono_class_enum_basetype (klass)) {
+ mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
+ return;
+ }
+ }
+
/*
* Enable GC aware auto layout: in this mode, reference
* fields are grouped together inside objects, increasing collector
gc_aware_layout = TRUE;
}
- /* Compute klass->has_references */
- /*
- * Process non-static fields first, since static fields might recursively
- * refer to the class itself.
- */
+ /* Compute klass->blittable */
+ blittable = TRUE;
+ if (klass->parent)
+ blittable = klass->parent->blittable;
+ if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
+ blittable = FALSE;
for (i = 0; i < top; i++) {
- MonoType *ftype;
-
field = &klass->fields [i];
- if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- ftype = mono_type_get_underlying_type (field->type);
- ftype = mono_type_get_basic_type_from_generic (ftype);
- if (type_has_references (klass, ftype))
- klass->has_references = TRUE;
+ if (mono_field_is_deleted (field))
+ continue;
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+ if (blittable) {
+ if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
+ blittable = FALSE;
+ } else {
+ MonoClass *field_class = mono_class_from_mono_type (field->type);
+ if (field_class) {
+ mono_class_setup_fields (field_class);
+ if (mono_class_has_failure (field_class)) {
+ MonoError field_error;
+ mono_error_init (&field_error);
+ mono_error_set_for_class_failure (&field_error, field_class);
+ mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
+ mono_error_cleanup (&field_error);
+ break;
+ }
+ }
+ if (!field_class || !field_class->blittable)
+ blittable = FALSE;
+ }
}
+ if (klass->enumtype)
+ blittable = klass->element_class->blittable;
}
+ if (mono_class_has_failure (klass))
+ return;
+ if (klass == mono_defaults.string_class)
+ blittable = FALSE;
+ /* Compute klass->has_references */
+ /*
+ * Process non-static fields first, since static fields might recursively
+ * refer to the class itself.
+ */
for (i = 0; i < top; i++) {
MonoType *ftype;
field = &klass->fields [i];
- if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
if (type_has_references (klass, ftype))
- klass->has_static_refs = TRUE;
- }
- }
-
- for (i = 0; i < top; i++) {
- MonoType *ftype;
-
- field = &klass->fields [i];
-
- ftype = mono_type_get_underlying_type (field->type);
- ftype = mono_type_get_basic_type_from_generic (ftype);
- if (type_has_references (klass, ftype)) {
- if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
- klass->has_static_refs = TRUE;
- else
- klass->has_references = TRUE;
+ has_references = TRUE;
}
}
/*
* Compute field layout and total size (not considering static fields)
*/
-
+ field_offsets = g_new0 (int, top);
+ int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
switch (layout) {
case TYPE_ATTRIBUTE_AUTO_LAYOUT:
case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
-
if (gc_aware_layout)
passes = 2;
else
if (klass->parent) {
mono_class_setup_fields (klass->parent);
- if (klass->parent->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
return;
- }
real_size = klass->parent->instance_size;
} else {
real_size = sizeof (MonoObject);
}
}
- if ((top == 1) && (klass->instance_size == sizeof (MonoObject)) &&
+ if ((top == 1) && (instance_size == sizeof (MonoObject)) &&
(strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
/* This field is a hack inserted by MCS to empty structures */
continue;
size = mono_type_size (field->type, &align);
/* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
- align = klass->packing_size ? MIN (klass->packing_size, align): align;
+ align = packing_size ? MIN (packing_size, align): align;
/* if the field has managed references, we need to force-align it
* see bug #77788
*/
if (type_has_references (klass, ftype))
align = MAX (align, sizeof (gpointer));
- klass->min_align = MAX (align, klass->min_align);
- field->offset = real_size;
+ min_align = MAX (align, min_align);
+ field_offsets [i] = real_size;
if (align) {
- field->offset += align - 1;
- field->offset &= ~(align - 1);
+ field_offsets [i] += align - 1;
+ field_offsets [i] &= ~(align - 1);
}
/*TypeBuilders produce all sort of weird things*/
- g_assert (image_is_dynamic (klass->image) || field->offset > 0);
- real_size = field->offset + size;
+ g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
+ real_size = field_offsets [i] + size;
}
- klass->instance_size = MAX (real_size, klass->instance_size);
+ instance_size = MAX (real_size, instance_size);
- if (klass->instance_size & (klass->min_align - 1)) {
- klass->instance_size += klass->min_align - 1;
- klass->instance_size &= ~(klass->min_align - 1);
+ if (instance_size & (min_align - 1)) {
+ instance_size += min_align - 1;
+ instance_size &= ~(min_align - 1);
}
}
break;
continue;
size = mono_type_size (field->type, &align);
- align = klass->packing_size ? MIN (klass->packing_size, align): align;
- klass->min_align = MAX (align, klass->min_align);
+ align = packing_size ? MIN (packing_size, align): align;
+ min_align = MAX (align, min_align);
- /*
- * When we get here, field->offset is already set by the
- * loader (for either runtime fields or fields loaded from metadata).
- * The offset is from the start of the object: this works for both
- * classes and valuetypes.
- */
- field->offset += sizeof (MonoObject);
+ if (sre) {
+ /* Already set by typebuilder_setup_fields () */
+ field_offsets [i] = field->offset + sizeof (MonoObject);
+ } else {
+ int idx = first_field_idx + i;
+ guint32 offset;
+ mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
+ field_offsets [i] = offset + sizeof (MonoObject);
+ }
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
if (type_has_references (klass, ftype)) {
- if (field->offset % sizeof (gpointer)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (field_offsets [i] % sizeof (gpointer)) {
+ mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
}
}
/*
* Calc max size.
*/
- real_size = MAX (real_size, size + field->offset);
+ real_size = MAX (real_size, size + field_offsets [i]);
}
if (klass->has_references) {
continue;
ftype = mono_type_get_underlying_type (field->type);
if (MONO_TYPE_IS_REFERENCE (ftype))
- ref_bitmap [field->offset / sizeof (gpointer)] = 1;
+ ref_bitmap [field_offsets [i] / sizeof (gpointer)] = 1;
}
for (i = 0; i < top; i++) {
field = &klass->fields [i];
// FIXME: Too much code does this
#if 0
- if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field->offset / sizeof (gpointer)]) {
- char *err_msg = g_strdup_printf ("Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field->offset);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+ if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / sizeof (gpointer)]) {
+ mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field_offsets [i]);
}
#endif
}
g_free (ref_bitmap);
}
- klass->instance_size = MAX (real_size, klass->instance_size);
- if (klass->instance_size & (klass->min_align - 1)) {
- klass->instance_size += klass->min_align - 1;
- klass->instance_size &= ~(klass->min_align - 1);
+ instance_size = MAX (real_size, instance_size);
+ if (instance_size & (min_align - 1)) {
+ instance_size += min_align - 1;
+ instance_size &= ~(min_align - 1);
}
break;
}
* performance, and since the JIT memset/memcpy code assumes this and generates
* unaligned accesses otherwise. See #78990 for a testcase.
*/
- if (mono_align_small_structs) {
- if (klass->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
- klass->min_align = MAX (klass->min_align, klass->instance_size - sizeof (MonoObject));
+ if (mono_align_small_structs && top) {
+ if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
+ min_align = MAX (min_align, instance_size - sizeof (MonoObject));
}
}
+ if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+ instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
+ else if (klass->byval_arg.type == MONO_TYPE_PTR)
+ instance_size = sizeof (MonoObject) + sizeof (gpointer);
+
+ /* Publish the data */
+ mono_loader_lock ();
+ if (klass->instance_size && !klass->image->dynamic) {
+ /* Might be already set using cached info */
+ g_assert (klass->instance_size == instance_size);
+ } else {
+ klass->instance_size = instance_size;
+ }
+ klass->blittable = blittable;
+ klass->has_references = has_references;
+ klass->packing_size = packing_size;
+ klass->min_align = min_align;
+ for (i = 0; i < top; ++i) {
+ field = &klass->fields [i];
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+ klass->fields [i].offset = field_offsets [i];
+ }
+
mono_memory_barrier ();
klass->size_inited = 1;
+ mono_loader_unlock ();
/*
* Compute static field layout and size
+ * Static fields can reference the class itself, so this has to be
+ * done after instance_size etc. are initialized.
*/
- for (i = 0; i < top; i++){
+ class_size = 0;
+ for (i = 0; i < top; i++) {
gint32 align;
guint32 size;
continue;
if (mono_type_has_exceptions (field->type)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
break;
}
has_static_fields = TRUE;
size = mono_type_size (field->type, &align);
- field->offset = klass->sizes.class_size;
+ field_offsets [i] = class_size;
/*align is always non-zero here*/
- field->offset += align - 1;
- field->offset &= ~(align - 1);
- klass->sizes.class_size = field->offset + size;
+ field_offsets [i] += align - 1;
+ field_offsets [i] &= ~(align - 1);
+ class_size = field_offsets [i] + size;
}
- if (has_static_fields && klass->sizes.class_size == 0)
+ if (has_static_fields && class_size == 0)
/* Simplify code which depends on class_size != 0 if the class has static fields */
- klass->sizes.class_size = 8;
+ class_size = 8;
+
+ /* Compute klass->has_static_refs */
+ has_static_refs = FALSE;
+ for (i = 0; i < top; i++) {
+ MonoType *ftype;
+
+ field = &klass->fields [i];
+
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+ ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
+ if (type_has_references (klass, ftype))
+ has_static_refs = TRUE;
+ }
+ }
+
+ /*valuetypes can't be neither bigger than 1Mb or empty. */
+ if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
+ mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
+
+ /* Publish the data */
+ mono_loader_lock ();
+ if (!klass->rank)
+ klass->sizes.class_size = class_size;
+ klass->has_static_refs = has_static_refs;
+ for (i = 0; i < top; ++i) {
+ field = &klass->fields [i];
+
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ field->offset = field_offsets [i];
+ }
+
+ mono_memory_barrier ();
+ klass->fields_inited = 1;
+ mono_loader_unlock ();
+
+ g_free (field_offsets);
}
static MonoMethod*
* Methods belonging to an interface are assigned a sequential slot starting
* from 0.
*
- * On failure this function sets klass->exception_type
+ * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
*/
void
mono_class_setup_methods (MonoClass *klass)
if (klass->methods)
return;
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
MonoError error;
- MonoClass *gklass = klass->generic_class->container_class;
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_init (gklass);
- if (!gklass->exception_type)
+ if (!mono_class_has_failure (gklass))
mono_class_setup_methods (gklass);
- if (gklass->exception_type) {
- /* FIXME make exception_data less opaque so it's possible to dup it here */
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
return;
- }
/* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
count = gklass->method.count;
gklass->methods [i], klass, mono_class_get_context (klass), &error);
if (!mono_error_ok (&error)) {
char *method = mono_method_full_name (gklass->methods [i], TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not inflate method %s due to %s", method, mono_error_get_message (&error)));
+ mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (&error));
g_free (method);
mono_error_cleanup (&error);
for (i = 0; i < klass->interface_count; i++)
setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
- } else {
+ } else if (mono_class_has_static_metadata (klass)) {
MonoError error;
+ int first_idx = mono_class_get_first_method_idx (klass);
count = klass->method.count;
methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
for (i = 0; i < count; ++i) {
- int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1);
+ int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error);
if (!methods [i]) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load method %d due to %s", i, mono_error_get_message (&error)));
+ mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error));
mono_error_cleanup (&error);
}
}
+ } else {
+ methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
+ count = 0;
}
if (MONO_CLASS_IS_INTERFACE (klass)) {
mono_class_get_method_by_index (MonoClass *klass, int index)
{
MonoError error;
+
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
/* Avoid calling setup_methods () if possible */
- if (klass->generic_class && !klass->methods) {
- MonoClass *gklass = klass->generic_class->container_class;
+ if (gklass && !klass->methods) {
MonoMethod *m;
m = mono_class_inflate_generic_method_full_checked (
- gklass->methods [index], klass, mono_class_get_context (klass), &error);
+ gklass->container_class->methods [index], klass, mono_class_get_context (klass), &error);
g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
/*
* If setup_methods () is called later for this class, no duplicates are created,
return m;
} else {
mono_class_setup_methods (klass);
- if (klass->exception_type) /*FIXME do proper error handling*/
+ if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
return NULL;
g_assert (index >= 0 && index < klass->method.count);
return klass->methods [index];
MonoMethod*
mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method)
{
- MonoClass *gklass = klass->generic_class->container_class;
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
int i;
g_assert (method->klass == gklass);
mono_class_setup_methods (gklass);
- g_assert (!gklass->exception_type); /*FIXME do proper error handling*/
+ g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/
for (i = 0; i < gklass->method.count; ++i) {
if (gklass->methods [i] == method) {
return klass->parent->vtable [offset];
}
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
MonoError error;
- MonoClass *gklass = klass->generic_class->container_class;
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_setup_vtable (gklass);
m = gklass->vtable [offset];
g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
} else {
mono_class_setup_vtable (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return NULL;
m = klass->vtable [offset];
}
if (klass->ext && klass->ext->properties)
return;
- if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_init (gklass);
mono_class_setup_properties (gklass);
- if (gklass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
return;
- }
properties = mono_class_new0 (klass, MonoProperty, gklass->ext->property.count + 1);
if (count) {
mono_class_setup_methods (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return;
}
properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
startm = mono_metadata_methods_from_property (klass->image, i, &endm);
+ int first_idx = mono_class_get_first_method_idx (klass);
for (j = startm; j < endm; ++j) {
MonoMethod *method;
method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
mono_error_cleanup (&error); /* FIXME don't swallow this error */
} else {
- method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
+ method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
}
switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
if (klass->ext && klass->ext->events)
return;
- if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
MonoGenericContext *context = NULL;
mono_class_setup_events (gklass);
- if (gklass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
return;
- }
first = gklass->ext->event.first;
count = gklass->ext->event.count;
if (count) {
mono_class_setup_methods (klass);
- if (klass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+ if (mono_class_has_failure (klass)) {
return;
}
}
event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
startm = mono_metadata_methods_from_event (klass->image, i, &endm);
+ int first_idx = mono_class_get_first_method_idx (klass);
for (j = startm; j < endm; ++j) {
MonoMethod *method;
method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
mono_error_cleanup (&error); /* FIXME don't swallow this error */
} else {
- method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
+ method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
}
switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
}
}
-/*
+/**
* mono_get_unique_iid:
* @class: interface
*
* Assign a unique integer ID to the interface represented by @class.
* The ID will positive and as small as possible.
* LOCKING: Acquires the classes lock.
- * Returns: the new ID.
+ * Returns: The new ID.
*/
static guint32
mono_get_unique_iid (MonoClass *klass)
}
mono_bitset_set (global_interface_bitset, iid);
/* set the bit also in the per-image set */
- if (!klass->generic_class) {
+ if (!mono_class_is_ginst (klass)) {
if (klass->image->interface_bitset) {
if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
if (mono_print_vtable) {
int generic_id;
char *type_name = mono_type_full_name (&klass->byval_arg);
- if (klass->generic_class && !klass->generic_class->context.class_inst->is_open) {
- generic_id = klass->generic_class->context.class_inst->id;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ if (gklass && !gklass->context.class_inst->is_open) {
+ generic_id = gklass->context.class_inst->id;
g_assert (generic_id != 0);
} else {
generic_id = 0;
MonoClass *ic;
mono_class_setup_interfaces (klass, error);
- if (!mono_error_ok (error))
- return;
+ return_if_nok (error);
for (i = 0; i < klass->interface_count; i++) {
ic = klass->interfaces [i];
*res = g_ptr_array_new ();
g_ptr_array_add (*res, ic);
mono_class_init (ic);
- if (ic->exception_type) {
+ if (mono_class_has_failure (ic)) {
mono_error_set_type_load_class (error, ic, "Error Loading class");
return;
}
collect_implemented_interfaces_aux (ic, res, error);
- if (!mono_error_ok (error))
- return;
+ return_if_nok (error);
}
}
}
}
-/*
+/**
* mono_class_interface_offset_with_variance:
*
* Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
}
+static GENERATE_GET_CLASS_WITH_CACHE (generic_icollection, System.Collections.Generic, ICollection`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerable, System.Collections.Generic, IEnumerable`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerator, System.Collections.Generic, IEnumerator`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlylist, System.Collections.Generic, IReadOnlyList`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlycollection, System.Collections.Generic, IReadOnlyCollection`1)
+
/* 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
get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator)
{
MonoClass *eclass = klass->element_class;
- static MonoClass* generic_icollection_class = NULL;
- static MonoClass* generic_ienumerable_class = NULL;
- static MonoClass* generic_ienumerator_class = NULL;
- static MonoClass* generic_ireadonlylist_class = NULL;
- static MonoClass* generic_ireadonlycollection_class = NULL;
+ MonoClass* generic_icollection_class;
+ MonoClass* generic_ienumerable_class;
+ MonoClass* generic_ienumerator_class;
+ MonoClass* generic_ireadonlylist_class;
+ MonoClass* generic_ireadonlycollection_class;
MonoClass *valuetype_types[2] = { NULL, NULL };
MonoClass **interfaces = NULL;
int i, nifaces, interface_count, real_count, original_rank;
eclass_is_valuetype = FALSE;
original_rank = eclass->rank;
if (klass->byval_arg.type != MONO_TYPE_SZARRAY) {
- if (klass->generic_class && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) {
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ if (gklass && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) {
/*
* For a Enumerator<T[]> we need to get the list of interfaces for T.
*/
- eclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ eclass = mono_class_from_mono_type (gklass->context.class_inst->type_argv [0]);
original_rank = eclass->rank;
if (!eclass->rank)
eclass = eclass->element_class;
*/
all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
- if (!generic_icollection_class) {
- generic_icollection_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "ICollection`1");
- generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "IEnumerable`1");
- generic_ienumerator_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "IEnumerator`1");
- generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "IReadOnlyList`1");
- generic_ireadonlycollection_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "IReadOnlyCollection`1");
- }
+ generic_icollection_class = mono_class_get_generic_icollection_class ();
+ generic_ienumerable_class = mono_class_get_generic_ienumerable_class ();
+ generic_ienumerator_class = mono_class_get_generic_ienumerator_class ();
+ generic_ireadonlylist_class = mono_class_get_generic_ireadonlylist_class ();
+ generic_ireadonlycollection_class = mono_class_get_generic_ireadonlycollection_class ();
mono_class_init (eclass);
if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
mono_class_setup_methods (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return -1;
for (i = 0; i < klass->method.count; ++i) {
++count;
}
} else {
+ int first_idx = mono_class_get_first_method_idx (klass);
for (i = 0; i < klass->method.count; ++i) {
- flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
+ flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
if (flags & METHOD_ATTRIBUTE_VIRTUAL)
++count;
* the size of the buffer.
* This compression algorithm assumes the bits set in the bitmap are
* few and far between, like in interface bitmaps.
- * Returns: the size of the compressed bitmap in bytes.
+ * Returns: The size of the compressed bitmap in bytes.
*/
int
mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
* be already checked for being smaller than the maximum id encoded in the
* bitmap.
*
- * Returns: a non-zero value if bit @id is set in the bitmap @bitmap,
+ * Returns: A non-zero value if bit @id is set in the bitmap @bitmap,
* #FALSE otherwise.
*/
int
#endif
/*
- * LOCKING: this is supposed to be called with the loader lock held.
- * Return -1 on failure and set exception_type
+ * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
+ * LOCKING: Acquires the loader lock.
*/
static int
setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
for (i = 0; i < k->interface_count; i++) {
ic = k->interfaces [i];
- if (!ic->inited)
- mono_class_init (ic);
+ mono_class_init (ic);
if (max_iid < ic->interface_id)
max_iid = ic->interface_id;
ifaces = mono_class_get_implemented_interfaces (k, &error);
if (!mono_error_ok (&error)) {
char *name = mono_type_get_full_name (k);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error)));
+ mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error));
g_free (name);
mono_error_cleanup (&error);
cur_slot = -1;
if (max_iid < klass->interface_id)
max_iid = klass->interface_id;
}
- klass->max_interface_id = max_iid;
+
/* compute vtable offset for interfaces */
interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
- for (i = 0; i < num_ifaces; i++) {
+ for (i = 0; i < num_ifaces; i++)
interface_offsets_full [i] = -1;
- }
/* skip the current class */
for (j = 0; j < klass->idepth - 1; j++) {
count = count_virtual_methods (ic);
if (count == -1) {
char *name = mono_type_get_full_name (ic);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error calculating interface offset of %s", name));
+ mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
g_free (name);
cur_slot = -1;
goto end;
for (i = 0; i < num_array_interfaces; ++i) {
int offset;
ic = array_interfaces [i];
- if (ic->generic_class->container_class == mono_defaults.generic_ilist_class)
+ if (mono_class_get_generic_class (ic)->container_class == mono_defaults.generic_ilist_class)
offset = ilist_offset;
else if (strcmp (ic->name, "ICollection`1") == 0)
offset = icollection_offset;
}
for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
- if (interface_offsets_full [i] != -1) {
+ if (interface_offsets_full [i] != -1)
interface_offsets_count ++;
- }
}
+ /* Publish the data */
+ mono_loader_lock ();
+
+ klass->max_interface_id = max_iid;
/*
* We might get called multiple times:
* - mono_class_init ()
klass->interface_bitmap = bitmap;
#endif
}
+ mono_loader_unlock ();
end:
g_free (interfaces_full);
//printf ("JUST DONE: ");
//print_implemented_interfaces (klass);
-
+
return cur_slot;
}
void
mono_class_setup_interface_offsets (MonoClass *klass)
{
- mono_loader_lock ();
-
setup_interface_offsets (klass, 0, FALSE);
-
- mono_loader_unlock ();
}
/*Checks if @klass has @parent as one of it's parents type gtd
{
MonoGenericInst *ginst;
int i;
- if (!klass->generic_class) {
+
+ if (!mono_class_is_ginst (klass)) {
mono_class_setup_vtable_full (klass, in_setup);
- return klass->exception_type == 0;
+ return !mono_class_has_failure (klass);
}
mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
- if (klass->generic_class->container_class->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to load generic definition vtable"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
return FALSE;
- }
- ginst = klass->generic_class->context.class_inst;
+ ginst = mono_class_get_generic_class (klass)->context.class_inst;
for (i = 0; i < ginst->type_argc; ++i) {
MonoClass *arg;
if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
continue;
if (!mono_class_check_vtable_constraints (arg, in_setup)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Failed to load generic parameter %d", i));
+ mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
return FALSE;
}
}
* - vtable
* - vtable_size
* Plus all the fields initialized by setup_interface_offsets ().
- * If there is an error during vtable construction, klass->exception_type is set.
+ * If there is an error during vtable construction, klass->has_failure
+ * is set and details are stored in a MonoErrorBoxed.
*
* LOCKING: Acquires the loader lock.
*/
static void
mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
{
+ MonoError error;
MonoMethod **overrides;
MonoGenericContext *context;
guint32 type_token;
return;
}
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return;
if (g_list_find (in_setup, klass))
mono_stats.generic_vtable_count ++;
in_setup = g_list_prepend (in_setup, klass);
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
if (!mono_class_check_vtable_constraints (klass, in_setup)) {
mono_loader_unlock ();
g_list_remove (in_setup, klass);
}
context = mono_class_get_context (klass);
- type_token = klass->generic_class->container_class->type_token;
+ type_token = mono_class_get_generic_class (klass)->container_class->type_token;
} else {
- context = (MonoGenericContext *) klass->generic_container;
+ context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
type_token = klass->type_token;
}
* This is true since we don't do layout all over again for them, we simply inflate
* the layout of the parent.
*/
- mono_reflection_get_dynamic_overrides (klass, &overrides, &onum);
+ mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
+ if (!is_ok (&error)) {
+ mono_loader_unlock ();
+ g_list_remove (in_setup, klass);
+ mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error));
+ mono_error_cleanup (&error);
+ return;
+ }
} else {
/* The following call fails if there are missing methods in the type */
/* FIXME it's probably a good idea to avoid this for generic instances. */
if (ok)
mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
else
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load list of method overrides"));
+ mono_class_set_type_load_failure (klass, "Could not load list of method overrides");
g_free (overrides);
cmsig = mono_method_signature (cm);
imsig = mono_method_signature (im);
if (!cmsig || !imsig) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
+ mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
return FALSE;
}
if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
char *body_name = mono_method_full_name (cm, TRUE);
char *decl_name = mono_method_full_name (im, TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+ mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
g_free (body_name);
g_free (decl_name);
return FALSE;
cmsig = mono_method_signature (cm);
imsig = mono_method_signature (im);
if (!cmsig || !imsig) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
+ mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
return FALSE;
}
if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
char *body_name = mono_method_full_name (cm, TRUE);
char *decl_name = mono_method_full_name (im, TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+ mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
g_free (body_name);
g_free (decl_name);
return FALSE;
g_free (method_signature);
g_free (type_name);
mono_class_setup_methods (klass);
- if (klass->exception_type) {
+ if (mono_class_has_failure (klass)) {
char *name = mono_type_get_full_name (klass);
mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name);
g_free (name);
MonoMethod *body = overrides [i * 2 + 1];
if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
+ mono_class_set_type_load_failure (klass, "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 (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
+ mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
else
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
+ mono_class_set_type_load_failure (klass, "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 (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
+ mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
else
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
+ mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
return FALSE;
}
if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that is not extended or implemented by this type"));
+ mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
return FALSE;
}
if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
char *body_name = mono_method_full_name (body, TRUE);
char *decl_name = mono_method_full_name (decl, TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+ mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
g_free (body_name);
g_free (decl_name);
return FALSE;
ifaces = mono_class_get_implemented_interfaces (klass, &error);
if (!mono_error_ok (&error)) {
char *name = mono_type_get_full_name (klass);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error)));
+ mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error));
g_free (name);
mono_error_cleanup (&error);
return;
mono_class_init (klass->parent);
mono_class_setup_vtable_full (klass->parent, in_setup);
- if (klass->parent->exception_type) {
- char *name = mono_type_get_full_name (klass->parent);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Parent %s failed to load", name));
- g_free (name);
+ if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
return;
- }
max_vtsize += klass->parent->vtable_size;
cur_slot = klass->parent->vtable_size;
DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
/* Optimized version for generic instances */
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
MonoError error;
- MonoClass *gklass = klass->generic_class->container_class;
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
MonoMethod **tmp;
mono_class_setup_vtable_full (gklass, in_setup);
- if (gklass->exception_type != MONO_EXCEPTION_NONE) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
return;
- }
tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
klass->vtable_size = gklass->vtable_size;
if (gklass->vtable [i]) {
MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), &error);
if (!mono_error_ok (&error)) {
- char *err_msg = g_strdup_printf ("Could not inflate method due to %s", mono_error_get_message (&error));
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
- g_free (err_msg);
+ mono_class_set_type_load_failure (klass, "Could not inflate method due to %s", mono_error_get_message (&error));
mono_error_cleanup (&error);
return;
}
mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
- for (j = 0; j < parent_interface->method.count && !klass->exception_type; j++) {
+ for (j = 0; j < parent_interface->method.count && !mono_class_has_failure (klass); 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,
int dslot;
dslot = mono_method_get_vtable_slot (decl);
if (dslot == -1) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "");
return;
}
while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
virt_methods = g_slist_prepend (virt_methods, cm);
}
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
goto fail;
}
ic_offset = mono_class_interface_offset (klass, ic);
mono_class_setup_methods (ic);
- if (ic->exception_type)
+ if (mono_class_has_failure (ic))
goto fail;
// Check if this interface is explicitly implemented (instead of just inherited)
}
}
TRACE_INTERFACE_VTABLE (printf ("\n"));
- if (klass->exception_type) /*Might be set by check_interface_method_override*/
+ if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
goto fail;
}
}
break;
}
- if (klass->exception_type) /*Might be set by check_interface_method_override*/
+ if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
goto fail;
TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
}
// 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 (! (klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ if (!mono_class_is_abstract (klass)) {
for (i = 0; i < klass->interface_offsets_count; i++) {
int ic_offset;
int im_index;
m1sig = mono_method_signature (m1);
if (!cmsig || !m1sig) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ /* FIXME proper error message */
+ mono_class_set_type_load_failure (klass, "");
return;
}
if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
char *body_name = mono_method_full_name (cm, TRUE);
char *decl_name = mono_method_full_name (m1, TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+ mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
g_free (body_name);
g_free (decl_name);
goto fail;
break;
}
}
- if (k->exception_type)
+ if (mono_class_has_failure (k))
goto fail;
if (slot >= 0)
virt_methods = NULL;
/* Ensure that all vtable slots are filled with concrete instance methods */
- if (!(klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ if (!mono_class_is_abstract (klass)) {
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 (klass);
char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name));
+ mono_class_set_type_load_failure (klass, "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 (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_init (gklass);
fail:
{
char *name = mono_type_get_full_name (klass);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("VTable setup of type %s failed", name));
+ mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
g_free (name);
if (override_map)
g_hash_table_destroy (override_map);
{
if (method->slot == -1) {
mono_class_setup_vtable (method->klass);
- if (method->klass->exception_type)
+ if (mono_class_has_failure (method->klass))
return -1;
if (method->slot == -1) {
MonoClass *gklass;
int i;
- if (!method->klass->generic_class) {
+ if (!mono_class_is_ginst (method->klass)) {
g_assert (method->is_inflated);
return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
}
/* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
- g_assert (method->klass->generic_class);
- gklass = method->klass->generic_class->container_class;
+ g_assert (mono_class_is_ginst (method->klass));
+ gklass = mono_class_get_generic_class (method->klass)->container_class;
mono_class_setup_methods (method->klass);
g_assert (method->klass->methods);
for (i = 0; i < method->klass->method.count; ++i) {
if (generic_array_method_num)
return generic_array_method_num;
mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
- g_assert (!klass->parent->exception_type); /*So hitting this assert is a huge problem*/
+ g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
for (i = 0; i < klass->parent->method.count; i++) {
MonoMethod *m = klass->parent->methods [i];
if (!strncmp (m->name, "InternalArray__", 15)) {
int i;
tmp_context.class_inst = NULL;
- tmp_context.method_inst = iface->generic_class->context.class_inst;
+ tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
//g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
for (i = 0; i < generic_array_method_num; i++) {
return s;
}
-static void
-set_failure_from_loader_error (MonoClass *klass, MonoLoaderError *error)
-{
- gpointer exception_data = NULL;
-
- switch (error->exception_type) {
- case MONO_EXCEPTION_TYPE_LOAD:
- exception_data = concat_two_strings_with_zero (klass->image, error->class_name, error->assembly_name);
- break;
-
- case MONO_EXCEPTION_MISSING_METHOD:
- exception_data = concat_two_strings_with_zero (klass->image, error->class_name, error->member_name);
- break;
-
- case MONO_EXCEPTION_MISSING_FIELD: {
- const char *name_space = error->klass->name_space ? error->klass->name_space : NULL;
- const char *class_name;
-
- if (name_space)
- class_name = g_strdup_printf ("%s.%s", name_space, error->klass->name);
- else
- class_name = error->klass->name;
-
- exception_data = concat_two_strings_with_zero (klass->image, class_name, error->member_name);
-
- if (name_space)
- g_free ((void*)class_name);
- break;
- }
-
- case MONO_EXCEPTION_FILE_NOT_FOUND: {
- const char *msg;
-
- if (error->ref_only)
- msg = "Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.";
- else
- msg = "Could not load file or assembly '%s' or one of its dependencies.";
-
- exception_data = concat_two_strings_with_zero (klass->image, msg, error->assembly_name);
- break;
- }
-
- case MONO_EXCEPTION_BAD_IMAGE:
- exception_data = error->msg;
- break;
-
- default :
- g_assert_not_reached ();
- }
-
- mono_class_set_failure (klass, error->exception_type, exception_data);
-}
-
/**
* mono_class_init:
- * @class: the class to initialize
+ * @klass: the class to initialize
*
* Compute the instance_size, class_size and other infos that cannot be
* computed at mono_class_get() time. Also compute vtable_size if possible.
* Returns TRUE on success or FALSE if there was a problem in loading
- * the type (incorrect assemblies, missing assemblies, methods, etc).
+ * the type (incorrect assemblies, missing assemblies, methods, etc).
+ * Initializes the following fields in @klass:
+ * - all the fields initialized by mono_class_init_sizes ()
+ * - has_cctor
+ * - ghcimpl
+ * - inited
*
* LOCKING: Acquires the loader lock.
*/
gboolean
mono_class_init (MonoClass *klass)
{
- int i;
+ int i, vtable_size = 0, array_method_count = 0;
MonoCachedClassInfo cached_info;
gboolean has_cached_info;
+ gboolean locked = FALSE;
+ gboolean ghcimpl = FALSE;
+ gboolean has_cctor = FALSE;
+ int first_iface_slot = 0;
g_assert (klass);
/* Double-checking locking pattern */
- if (klass->inited || klass->exception_type)
- return klass->exception_type == MONO_EXCEPTION_NONE;
+ if (klass->inited || mono_class_has_failure (klass))
+ return !mono_class_has_failure (klass);
/*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
- /* We do everything inside the lock to prevent races */
- mono_loader_lock ();
-
- if (klass->inited || klass->exception_type) {
- mono_loader_unlock ();
- /* Somebody might have gotten in before us */
- return klass->exception_type == MONO_EXCEPTION_NONE;
- }
-
- if (klass->init_pending) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Recursive type definition detected"));
+ /*
+ * This function can recursively call itself.
+ */
+ GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
+ if (g_slist_find (init_list, klass)) {
+ mono_class_set_type_load_failure (klass, "Recursive type definition detected");
goto leave;
}
+ init_list = g_slist_prepend (init_list, klass);
+ mono_native_tls_set_value (init_pending_tls_id, init_list);
- klass->init_pending = 1;
+ /*
+ * We want to avoid doing complicated work inside locks, so we compute all the required
+ * information and write it to @klass inside a lock.
+ */
if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
+ mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
goto leave;
}
-
if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
MonoClass *element_class = klass->element_class;
if (!element_class->inited)
mono_class_init (element_class);
- if (element_class->exception_type != MONO_EXCEPTION_NONE) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
goto leave;
- }
}
mono_stats.initialized_class_count++;
- if (klass->generic_class && !klass->generic_class->is_dynamic) {
- MonoClass *gklass = klass->generic_class->container_class;
-
- mono_stats.generic_class_count++;
-
- klass->method = gklass->method;
- klass->field = gklass->field;
+ if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_init (gklass);
- // FIXME: Why is this needed ?
- if (!gklass->exception_type)
- mono_class_setup_methods (gklass);
- if (gklass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic Type Defintion failed to init"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
goto leave;
- }
- if (MONO_CLASS_IS_INTERFACE (klass))
- klass->interface_id = mono_get_unique_iid (klass);
+ mono_class_setup_interface_id (klass);
}
if (klass->parent && !klass->parent->inited)
has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
- if (klass->generic_class || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
- klass->nested_classes_inited = TRUE;
-
- /*
- * Computes the size used by the fields, and their locations
- */
- if (has_cached_info) {
- klass->instance_size = cached_info.instance_size;
- klass->sizes.class_size = cached_info.class_size;
- klass->packing_size = cached_info.packing_size;
- klass->min_align = cached_info.min_align;
- klass->blittable = cached_info.blittable;
- klass->has_references = cached_info.has_references;
- klass->has_static_refs = cached_info.has_static_refs;
- klass->no_special_static_fields = cached_info.no_special_static_fields;
- }
- else
- if (!klass->size_inited){
- mono_class_setup_fields (klass);
- if (klass->exception_type || mono_loader_get_last_error ())
- goto leave;
- }
-
- /* Initialize arrays */
- if (klass->rank) {
- klass->method.count = 3 + (klass->rank > 1? 2: 1);
-
- if (klass->interface_count) {
- int count_generic = generic_array_methods (klass);
- klass->method.count += klass->interface_count * count_generic;
- }
- }
+ /* Compute instance size etc. */
+ init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
+ if (mono_class_has_failure (klass))
+ goto leave;
mono_class_setup_supertypes (klass);
*/
if (has_cached_info) {
/* AOT case */
- klass->vtable_size = cached_info.vtable_size;
- klass->has_finalize = cached_info.has_finalize;
- klass->has_finalize_inited = TRUE;
- klass->ghcimpl = cached_info.ghcimpl;
- klass->has_cctor = cached_info.has_cctor;
+ vtable_size = cached_info.vtable_size;
+ ghcimpl = cached_info.ghcimpl;
+ has_cctor = cached_info.has_cctor;
} else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
/* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
* The first slot if for array with.
if (!szarray_vtable_size [slot]) {
mono_class_setup_vtable (klass);
szarray_vtable_size [slot] = klass->vtable_size;
+ vtable_size = klass->vtable_size;
} else {
- klass->vtable_size = szarray_vtable_size[slot];
+ vtable_size = szarray_vtable_size[slot];
}
- } else if (klass->generic_class && !MONO_CLASS_IS_INTERFACE (klass)) {
- MonoClass *gklass = klass->generic_class->container_class;
+ } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
/* Generic instance case */
- klass->ghcimpl = gklass->ghcimpl;
- klass->has_cctor = gklass->has_cctor;
+ ghcimpl = gklass->ghcimpl;
+ has_cctor = gklass->has_cctor;
mono_class_setup_vtable (gklass);
- if (gklass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
goto leave;
- }
- klass->vtable_size = gklass->vtable_size;
+ vtable_size = gklass->vtable_size;
} else {
/* General case */
if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) {
MonoMethod *cmethod = NULL;
- if (klass->type_token && !image_is_dynamic(klass->image)) {
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
+
+ /* Generic instance case */
+ ghcimpl = gklass->ghcimpl;
+ has_cctor = gklass->has_cctor;
+ } else if (klass->type_token && !image_is_dynamic(klass->image)) {
cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
/* The find_method function ignores the 'flags' argument */
if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
- klass->has_cctor = 1;
+ has_cctor = 1;
} else {
mono_class_setup_methods (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
goto leave;
for (i = 0; i < klass->method.count; ++i) {
MonoMethod *method = klass->methods [i];
if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
(strcmp (".cctor", method->name) == 0)) {
- klass->has_cctor = 1;
+ has_cctor = 1;
break;
}
}
}
}
- if (klass->parent) {
- int first_iface_slot;
- /* This will compute klass->parent->vtable_size for some classes */
- mono_class_init (klass->parent);
- if (klass->parent->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- goto leave;
+ if (klass->rank) {
+ array_method_count = 3 + (klass->rank > 1? 2: 1);
+
+ if (klass->interface_count) {
+ int count_generic = generic_array_methods (klass);
+ array_method_count += klass->interface_count * count_generic;
}
- if (mono_loader_get_last_error ())
- goto leave;
- if (!klass->parent->vtable_size) {
- /* FIXME: Get rid of this somehow */
+ }
+
+ if (klass->parent) {
+ if (!klass->parent->vtable_size)
mono_class_setup_vtable (klass->parent);
- if (klass->parent->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- goto leave;
- }
- if (mono_loader_get_last_error ())
- goto leave;
- }
+ if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
+ goto leave;
+ g_assert (klass->parent->vtable_size);
first_iface_slot = klass->parent->vtable_size;
if (mono_class_need_stelemref_method (klass))
++first_iface_slot;
- setup_interface_offsets (klass, first_iface_slot, TRUE);
- } else {
- setup_interface_offsets (klass, 0, TRUE);
}
+ /*
+ * Do the actual changes to @klass inside the loader lock
+ */
+ mono_loader_lock ();
+ locked = TRUE;
+
+ if (klass->inited || mono_class_has_failure (klass)) {
+ mono_loader_unlock ();
+ /* Somebody might have gotten in before us */
+ return !mono_class_has_failure (klass);
+ }
+
+ mono_stats.initialized_class_count++;
+
+ if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
+
+ mono_stats.generic_class_count++;
+
+ klass->method = gklass->method;
+ klass->field = gklass->field;
+ }
+
+ if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
+ klass->nested_classes_inited = TRUE;
+ klass->ghcimpl = ghcimpl;
+ klass->has_cctor = has_cctor;
+ if (vtable_size)
+ klass->vtable_size = vtable_size;
+ if (has_cached_info) {
+ klass->has_finalize = cached_info.has_finalize;
+ klass->has_finalize_inited = TRUE;
+ }
+ if (klass->rank)
+ klass->method.count = array_method_count;
+
+ mono_loader_unlock ();
+ locked = FALSE;
+
+ setup_interface_offsets (klass, first_iface_slot, TRUE);
+
if (mono_security_core_clr_enabled ())
mono_security_core_clr_check_inheritance (klass);
- if (mono_loader_get_last_error ()) {
- if (klass->exception_type == MONO_EXCEPTION_NONE) {
- set_failure_from_loader_error (klass, mono_loader_get_last_error ());
- }
- mono_loader_clear_error ();
- }
-
- if (klass->generic_class && !mono_verifier_class_is_valid_generic_instantiation (klass))
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Invalid generic instantiation"));
+ if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
+ mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
goto leave;
leave:
+ init_list = g_slist_remove (init_list, klass);
+ mono_native_tls_set_value (init_pending_tls_id, init_list);
+
/* Because of the double-checking locking pattern */
mono_memory_barrier ();
klass->inited = 1;
- klass->init_pending = 0;
- mono_loader_unlock ();
+ if (locked)
+ mono_loader_unlock ();
- return klass->exception_type == MONO_EXCEPTION_NONE;
+ return !mono_class_has_failure (klass);
}
/*
MonoMethod *cmethod = NULL;
if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
- } else if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ } else if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
has_finalize = mono_class_has_finalizer (gklass);
} else if (klass->parent && klass->parent->has_finalize) {
* ignores overrides.
*/
mono_class_setup_vtable (klass);
- if (klass->exception_type || mono_loader_get_last_error ())
+ if (mono_class_has_failure (klass))
cmethod = NULL;
else
cmethod = klass->vtable [finalize_slot];
gboolean
mono_is_corlib_image (MonoImage *image)
{
- /* FIXME: allow the dynamic case for our compilers and with full trust */
- if (image_is_dynamic (image))
- return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib");
- else
- return image == mono_defaults.corlib;
+ return image == mono_defaults.corlib;
}
/*
if (MONO_CLASS_IS_INTERFACE (klass))
klass->interface_id = mono_get_unique_iid (klass);
-
}
#ifndef DISABLE_COM
/* 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 (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "");
return;
}
}
if (!parent) {
/* set the parent to something useful and safe, but mark the type as broken */
parent = mono_defaults.object_class;
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "");
+ g_assert (parent);
}
klass->parent = parent;
- if (parent->generic_class && !parent->name) {
+ if (mono_class_is_ginst (parent) && !parent->name) {
/*
* If the parent is a generic instance, we may get
* called before it is fully initialized, especially
{
MonoClass *gtd = (MonoClass*)user_data;
/* Only try to fix generic instances of @gtd */
- if (gclass->generic_class->container_class != gtd)
+ if (mono_class_get_generic_class (gclass)->container_class != gtd)
return FALSE;
/* Check if the generic instance has no parent. */
static void
mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
{
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (msg));
- mono_error_set_type_load_class (error, klass, msg);
-}
-
-static void
-mono_class_set_failure_from_loader_error (MonoClass *klass, MonoError *error, char *msg)
-{
- MonoLoaderError *lerror = mono_loader_get_last_error ();
-
- if (lerror) {
- set_failure_from_loader_error (klass, lerror);
- mono_error_set_from_loader_error (error);
- if (msg)
- g_free (msg);
- } else {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, msg);
- mono_error_set_type_load_class (error, klass, msg);
- }
+ mono_class_set_type_load_failure (klass, "%s", msg);
+ mono_error_set_type_load_class (error, klass, "%s", msg);
}
/**
if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
- mono_loader_assert_no_error ();
return NULL;
}
if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
mono_loader_unlock ();
- mono_loader_assert_no_error ();
return klass;
}
name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
- klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
+ if (mono_metadata_has_generic_params (image, type_token)) {
+ klass = mono_image_alloc0 (image, sizeof (MonoClassGtd));
+ klass->class_kind = MONO_CLASS_GTD;
+ classes_size += sizeof (MonoClassGtd);
+ ++class_gtd_count;
+ } else {
+ klass = mono_image_alloc0 (image, sizeof (MonoClassDef));
+ klass->class_kind = MONO_CLASS_DEF;
+ classes_size += sizeof (MonoClassDef);
+ ++class_def_count;
+ }
klass->name = name;
klass->name_space = nspace;
klass->image = image;
klass->type_token = type_token;
- klass->flags = cols [MONO_TYPEDEF_FLAGS];
+ mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
- classes_size += sizeof (MonoClass);
-
/*
* Check whether we're a generic type definition.
*/
- klass->generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
- if (klass->generic_container) {
- klass->is_generic = 1;
- klass->generic_container->owner.klass = klass;
- klass->generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
- context = &klass->generic_container->context;
- }
-
- if (klass->generic_container)
+ if (mono_class_is_gtd (klass)) {
+ MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
+ generic_container->owner.klass = klass;
+ generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
+ context = &generic_container->context;
+ mono_class_set_generic_container (klass, generic_container);
enable_gclass_recording ();
+ }
if (cols [MONO_TYPEDEF_EXTENDS]) {
MonoClass *tmp;
parent = mono_class_inflate_generic_class_checked (parent, context, error);
if (parent == NULL) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
goto parent_failure;
}
mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
goto parent_failure;
}
- if (klass->generic_container && tmp->generic_class && tmp->generic_class->container_class == klass) {
+ if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
goto parent_failure;
}
/* uses ->valuetype, which is initialized by mono_class_setup_parent above */
mono_class_setup_mono_type (klass);
- if (klass->generic_container)
+ if (mono_class_is_gtd (klass))
disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
/*
klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
if (!mono_error_ok (error)) {
/*FIXME implement a mono_class_set_failure_from_mono_error */
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
- mono_loader_assert_no_error ();
return NULL;
}
}
- if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
+ if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
klass->unicode = 1;
#ifdef HOST_WIN32
- if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
+ if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
klass->unicode = 1;
#endif
if (!mono_metadata_interfaces_from_typedef_full (
image, type_token, &interfaces, &icount, FALSE, context, error)){
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
return NULL;
/*
* Compute the field and method lists
*/
- klass->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
- klass->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
+ int first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
+ mono_class_set_first_field_idx (klass, first_field_idx);
+ int first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
+ mono_class_set_first_method_idx (klass, first_method_idx);
if (tt->rows > tidx){
mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
if (cols [MONO_TYPEDEF_FIELD_LIST] &&
cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
- klass->field.count = field_last - klass->field.first;
+ klass->field.count = field_last - first_field_idx;
else
klass->field.count = 0;
if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
- klass->method.count = method_last - klass->method.first;
+ klass->method.count = method_last - first_method_idx;
else
klass->method.count = 0;
if (!enum_basetype) {
/*set it to a default value as the whole runtime can't handle this to be null*/
klass->cast_class = klass->element_class = mono_defaults.int32_class;
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
- mono_loader_assert_no_error ();
return NULL;
}
klass->cast_class = klass->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 (klass->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, klass->generic_container, error)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load generic parameter constrains due to %s", mono_error_get_message (error)));
+ if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
+ mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
- mono_loader_assert_no_error ();
return NULL;
}
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
- mono_loader_assert_no_error ();
return klass;
mono_class_setup_mono_type (klass);
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
- mono_loader_assert_no_error ();
return NULL;
}
gboolean
mono_class_is_nullable (MonoClass *klass)
{
- return klass->generic_class != NULL &&
- klass->generic_class->container_class == mono_defaults.generic_nullable_class;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
}
mono_class_get_nullable_param (MonoClass *klass)
{
g_assert (mono_class_is_nullable (klass));
- return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ return mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
}
static void
{
if (gtd->parent) {
MonoError error;
- MonoGenericClass *gclass = klass->generic_class;
+ MonoGenericClass *gclass = mono_class_get_generic_class (klass);
klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
if (!mono_error_ok (&error)) {
/*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
klass->parent = mono_defaults.object_class;
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (&error));
mono_error_cleanup (&error);
}
}
return gclass->cached_class;
}
- klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
+ klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
gklass = gclass->container_class;
mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
klass->image = gklass->image;
- klass->flags = gklass->flags;
klass->type_token = gklass->type_token;
klass->field.count = gklass->field.count;
- klass->is_inflated = 1;
- klass->generic_class = gclass;
+ klass->class_kind = MONO_CLASS_GINST;
+ //FIXME add setter
+ ((MonoClassGenericInst*)klass)->generic_class = gclass;
klass->byval_arg.type = MONO_TYPE_GENERICINST;
klass->this_arg.type = klass->byval_arg.type;
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
- inflated_classes ++;
- inflated_classes_size += sizeof (MonoClass);
+ ++class_ginst_count;
+ inflated_classes_size += sizeof (MonoClassGenericInst);
mono_loader_unlock ();
gboolean is_mvar = container->is_method;
gboolean is_anonymous = container->is_anonymous;
- klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
- classes_size += sizeof (MonoClass);
+ klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
+ klass->class_kind = MONO_CLASS_GPARAM;
+ classes_size += sizeof (MonoClassGenericParam);
+ ++class_gparam_count;
if (pinfo) {
CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
pos++;
} else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
- CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_from_name (mono_defaults.corlib, "System", "ValueType") );
+ CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
} else {
CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
}
klass->inited = TRUE;
CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
- klass->flags = TYPE_ATTRIBUTE_PUBLIC;
klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
klass->this_arg.type = klass->byval_arg.type;
klass->instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
mono_memory_barrier ();
klass->size_inited = 1;
- klass->setup_fields_called = 1;
mono_class_setup_supertypes (klass);
if (count - pos > 0) {
mono_class_setup_vtable (klass->parent);
- if (klass->parent->exception_type)
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
+ if (mono_class_has_failure (klass->parent))
+ mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
else
setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
}
}
mono_image_unlock (image);
- result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
+ result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
- classes_size += sizeof (MonoClass);
+ classes_size += sizeof (MonoClassPointer);
+ ++class_pointer_count;
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_image_strdup (image, name);
+ result->class_kind = MONO_CLASS_POINTER;
g_free (name);
mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
result->image = el_class->image;
result->inited = TRUE;
- result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
- /* Can pointers get boxed? */
- result->instance_size = sizeof (gpointer);
+ result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
result->cast_class = result->element_class = el_class;
result->blittable = TRUE;
}
result = g_new0 (MonoClass, 1);
+ classes_size += sizeof (MonoClassPointer);
+ ++class_pointer_count;
+
result->parent = NULL; /* no parent for PTR types */
result->name_space = "System";
result->name = "MonoFNPtrFakeClass";
+ result->class_kind = MONO_CLASS_POINTER;
mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
result->image = mono_defaults.corlib; /* need to fix... */
result->inited = TRUE;
- result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
- /* Can pointers get boxed? */
- result->instance_size = sizeof (gpointer);
+ result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
result->cast_class = result->element_class = result;
result->blittable = TRUE;
return result;
}
+/**
+ * mono_class_from_mono_type:
+ * @type: describes the type to return
+ *
+ * This returns a MonoClass for the specified MonoType, the value is never NULL.
+ */
MonoClass *
mono_class_from_mono_type (MonoType *type)
{
g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
g_assert_not_reached ();
}
-
+
+ // Yes, this returns NULL, even if it is documented as not doing so, but there
+ // is no way for the code to make it this far, due to the assert above.
return NULL;
}
MonoType *inflated = inflate_generic_type (NULL, t, context, error);
if (!mono_error_ok (error)) {
- mono_loader_assert_no_error ();
return NULL;
}
MonoClass *ret;
gboolean inflated = FALSE;
MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
ret = mono_class_from_mono_type (t);
if (inflated)
mono_metadata_free_type (t);
* @rank: the dimension of the array class
* @bounded: whenever the array has non-zero bounds
*
- * Returns: a class object describing the array with element type @element_type and
+ * Returns: A class object describing the array with element type @element_type and
* dimension @rank.
*/
MonoClass *
GSList *list, *rootlist = NULL;
int nsize;
char *name;
- gboolean corlib_type = FALSE;
g_assert (rank <= 255);
}
}
- /* for the building corlib use System.Array from it */
- if (image->assembly && assembly_is_dynamic (image->assembly) && image->assembly_name && strcmp (image->assembly_name, "mscorlib") == 0) {
- parent = mono_class_from_name (image, "System", "Array");
- corlib_type = TRUE;
- } else {
- parent = mono_defaults.array_class;
- if (!parent->inited)
- mono_class_init (parent);
- }
+ parent = mono_defaults.array_class;
+ if (!parent->inited)
+ mono_class_init (parent);
- klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
+ klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
klass->image = image;
klass->name_space = eclass->name_space;
+ klass->class_kind = MONO_CLASS_ARRAY;
+
nsize = strlen (eclass->name);
name = (char *)g_malloc (nsize + 2 + rank + 1);
memcpy (name, eclass->name, nsize);
mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
- classes_size += sizeof (MonoClass);
+ classes_size += sizeof (MonoClassArray);
+ ++class_array_count;
klass->type_token = 0;
- /* all arrays are marked serializable and sealed, bug #42779 */
- klass->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC;
klass->parent = parent;
klass->instance_size = mono_class_instance_size (klass->parent);
if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
/*Arrays of those two types are invalid.*/
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ MonoError prepared_error;
+ mono_error_init (&prepared_error);
+ mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
+ mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
+ mono_error_cleanup (&prepared_error);
} else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
if (!eclass->ref_info_handle || eclass->wastypebuilder) {
g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
mono_class_setup_supertypes (klass);
- if (eclass->generic_class)
+ if (mono_class_is_ginst (eclass))
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 (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
+ /*FIXME we fail the array type, but we have to let other fields be set.*/
klass->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
}
klass->this_arg = klass->byval_arg;
klass->this_arg.byref = 1;
- if (corlib_type) {
- klass->inited = 1;
- }
- klass->generic_container = eclass->generic_container;
+ //WTF was this? it's wrong
+ // klass->generic_container = eclass->generic_container;
if (rank == 1 && !bounded) {
MonoClass *prev_class;
* @element_class: element class
* @rank: the dimension of the array class
*
- * Returns: a class object describing the array with element type @element_type and
+ * Returns: A class object describing the array with element type @element_type and
* dimension @rank.
*/
MonoClass *
/**
* mono_class_instance_size:
* @klass: a class
- *
- * Returns: the size of an object instance
+ *
+ * Use to get the size of a class in bytes.
+ *
+ * Returns: The size of an object instance
*/
gint32
mono_class_instance_size (MonoClass *klass)
/**
* mono_class_min_align:
* @klass: a class
- *
- * Returns: minimm alignment requirements
+ *
+ * Use to get the computed minimum alignment requirements for the specified class.
+ *
+ * Returns: minimum alignment requirements
*/
gint32
mono_class_min_align (MonoClass *klass)
* Returns: the size of a value of kind @klass
*/
gint32
-mono_class_value_size (MonoClass *klass, guint32 *align)
+mono_class_value_size (MonoClass *klass, guint32 *align)
{
gint32 size;
* mono_class_data_size:
* @klass: a class
*
- * Returns: the size of the static class data
+ * Returns: The size of the static class data
*/
gint32
mono_class_data_size (MonoClass *klass)
mono_class_init (klass);
/* This can happen with dynamically created types */
if (!klass->fields_inited)
- mono_class_setup_fields_locking (klass);
+ mono_class_setup_fields (klass);
/* in arrays, sizes.class_size is unioned with element_size
* and arrays have no static fields
static MonoClassField *
mono_class_get_field_idx (MonoClass *klass, int idx)
{
- mono_class_setup_fields_locking (klass);
- if (klass->exception_type)
+ mono_class_setup_fields (klass);
+ if (mono_class_has_failure (klass))
return NULL;
while (klass) {
+ int first_field_idx = mono_class_get_first_field_idx (klass);
if (klass->image->uncompressed_metadata) {
/*
- * klass->field.first points to the FieldPtr table, while idx points into the
+ * first_field_idx 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.*/
g_assert_not_reached ();
} else {
if (klass->field.count) {
- if ((idx >= klass->field.first) && (idx < klass->field.first + klass->field.count)){
- return &klass->fields [idx - klass->field.first];
+ if ((idx >= first_field_idx) && (idx < first_field_idx + klass->field.count)){
+ return &klass->fields [idx - first_field_idx];
}
}
}
*
* Search the class @klass and it's parents for a field with the name @name.
*
- * Returns: the MonoClassField pointer of the named field or NULL
+ * Returns: The MonoClassField pointer of the named field or NULL
*/
MonoClassField *
mono_class_get_field_from_name (MonoClass *klass, const char *name)
* 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
+ * 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)
+ mono_class_setup_fields (klass);
+ if (mono_class_has_failure (klass))
return NULL;
while (klass) {
* Get the token of a field. Note that the tokesn is only valid for the image
* the field was loaded from. Don't use this function for fields in dynamic types.
*
- * Returns: the token representing the field in the image it was loaded from.
+ * Returns: The token representing the field in the image it was loaded from.
*/
guint32
mono_class_get_field_token (MonoClassField *field)
MonoClass *klass = field->parent;
int i;
- mono_class_setup_fields_locking (klass);
+ mono_class_setup_fields (klass);
while (klass) {
if (!klass->fields)
return 0;
+ int first_field_idx = mono_class_get_first_field_idx (klass);
for (i = 0; i < klass->field.count; ++i) {
if (&klass->fields [i] == field) {
- int idx = klass->field.first + i + 1;
+ int idx = first_field_idx + i + 1;
if (klass->image->uncompressed_metadata)
idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
return 0;
}
+/**
+ * mono_class_get_property_from_name:
+ * @klass: a class
+ * @name: name of the property to lookup in the specified class
+ *
+ * Use this method to lookup a property in a class
+ * Returns: the MonoProperty with the given name, or NULL if the property
+ * does not exist on the @klass.
+ */
MonoProperty*
mono_class_get_property_from_name (MonoClass *klass, const char *name)
{
return NULL;
}
+/**
+ * mono_class_get_property_token:
+ * @prop: MonoProperty to query
+ *
+ * Returns: The ECMA token for the specified property.
+ */
guint32
mono_class_get_property_token (MonoProperty *prop)
{
* @context: the generic context used to evaluate generic instantiations in
* @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0
*
- * Returns: the MonoClass that represents @type_token in @image
+ * Returns: The MonoClass that represents @type_token in @image
*/
MonoClass *
mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
* @type_token: the token for the class
* @error: error object to return any error
*
- * Returns: the MonoClass that represents @type_token in @image
+ * Returns: The MonoClass that represents @type_token in @image, or NULL on error.
*/
MonoClass *
mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
return NULL;
}
- klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL); /*FIXME proper error handling*/
+ klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
goto done;
}
*
* This functions exists to fullfill the fact that sometimes it's desirable to have access to the
*
- * Returns: the MonoType that represents @type_token in @image
+ * Returns: The MonoType that represents @type_token in @image
*/
MonoType *
mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
mono_error_init (error);
//FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
- if (image_is_dynamic (image))
- return mono_class_get_type ((MonoClass *)mono_lookup_dynamic_token (image, type_token, context));
+ if (image_is_dynamic (image)) {
+ MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
+ return_val_if_nok (error, NULL);
+ return mono_class_get_type (klass);
+ }
if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
MonoClass *klass = mono_class_get_checked (image, type_token, error);
if (!klass) {
- mono_loader_assert_no_error ();
return NULL;
}
type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
if (!type) {
- mono_loader_assert_no_error ();
return NULL;
}
return type;
}
-
+/**
+ * mono_class_get:
+ * @image: image where the class token will be looked up.
+ * @type_token: a type token from the image
+ *
+ * Returns the MonoClass with the given @type_token on the @image
+ */
MonoClass *
mono_class_get (MonoImage *image, guint32 type_token)
{
* @image: The MonoImage where the type is looked up in
* @name_space: the type namespace
* @name: the type short name.
- * @deprecated: use the _checked variant
+ * @deprecated: use the mono_class_from_name_case_checked variant instead.
*
* Obtains a MonoClass with a given namespace and a given name which
* is located in the given MonoImage. The namespace and name
{
MonoError error;
MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
- g_assert (!mono_error_ok (&error));
+ mono_error_cleanup (&error);
+
return res;
}
+/**
+ * mono_class_from_name_case:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ * @error: if
+ *
+ * Obtains a MonoClass with a given namespace and a given name which
+ * is located in the given MonoImage. The namespace and name
+ * lookups are case insensitive.
+ *
+ * Returns: The MonoClass if the given namespace and name were found, or NULL if it
+ * was not found. The @error object will contain information about the problem
+ * in that case.
+ */
MonoClass *
-mono_class_from_name_case_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
+mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
{
MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
guint32 cols [MONO_TYPEDEF_SIZE];
}
static MonoClass*
-search_modules (MonoImage *image, const char *name_space, const char *name)
+search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error)
{
MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
MonoImage *file_image;
MonoClass *klass;
int i;
+ mono_error_init (error);
+
/*
* The EXPORTEDTYPES table only contains public types, so have to search the
* modules as well.
if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
continue;
- file_image = mono_image_load_file_for_image (image, i + 1);
+ file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
if (file_image) {
- klass = mono_class_from_name (file_image, name_space, name);
- if (klass)
+ klass = mono_class_from_name_checked (file_image, name_space, name, error);
+ if (klass || !is_ok (error))
return klass;
}
}
}
static MonoClass *
-mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, MonoError *error, GHashTable* visited_images)
+mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error)
{
GHashTable *nspace_table;
MonoImage *loaded_image;
if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
gboolean res = get_class_from_name (image, name_space, name, &klass);
if (res) {
- if (!klass)
- klass = search_modules (image, name_space, name);
+ if (!klass) {
+ klass = search_modules (image, name_space, name, error);
+ if (!is_ok (error))
+ return NULL;
+ }
if (nested)
return klass ? return_nested_in (klass, nested) : NULL;
else
for (i = 0; i < image->module_count; ++i) {
MonoImage *module = image->modules [i];
- klass = mono_class_from_name (module, name_space, name);
- if (klass)
+ klass = mono_class_from_name_checked (module, name_space, name, error);
+ if (klass || !is_ok (error))
return klass;
}
}
if (!token) {
- klass = search_modules (image, name_space, name);
- if (klass)
+ klass = search_modules (image, name_space, name, error);
+ if (klass || !is_ok (error))
return klass;
- }
-
- if (!token)
return NULL;
+ }
if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
- loaded_image = mono_assembly_load_module (image->assembly, impl >> MONO_IMPLEMENTATION_BITS);
+ loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
if (!loaded_image)
return NULL;
- klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, error, visited_images);
+ klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error);
if (nested)
return klass ? return_nested_in (klass, nested) : NULL;
return klass;
g_assert (image->references [assembly_idx - 1]);
if (image->references [assembly_idx - 1] == (gpointer)-1)
return NULL;
- klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, error, visited_images);
+ klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error);
if (nested)
- return return_nested_in (klass, nested);
+ return klass ? return_nested_in (klass, nested) : NULL;
return klass;
} else {
g_assert_not_reached ();
return klass;
}
+/**
+ * mono_class_from_name_checked:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * Obtains a MonoClass with a given namespace and a given name which
+ * is located in the given MonoImage.
+ *
+ * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
+ * set if the class was not found or it will return NULL and set the error if there was a loading error.
+ */
MonoClass *
mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
{
visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
- klass = mono_class_from_name_checked_aux (image, name_space, name, error, visited_images);
+ klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error);
g_hash_table_destroy (visited_images);
MonoClass *klass;
klass = mono_class_from_name_checked (image, name_space, name, &error);
- if (!mono_error_ok (&error)) {
- mono_loader_set_error_from_mono_error (&error);
- mono_error_cleanup (&error); /* FIXME Don't swallow the error */
- }
+ mono_error_cleanup (&error); /* FIXME Don't swallow the error */
+
+ return klass;
+}
+
+/**
+ * mono_class_load_from_name:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * This function works exactly like mono_class_from_name but it will abort if the class is not found.
+ * This function should be used by the runtime for critical types to which there's no way to recover but crash
+ * If they are missing. Thing of System.Object or System.String.
+ */
+MonoClass *
+mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
+{
+ MonoError error;
+ MonoClass *klass;
+
+ klass = mono_class_from_name_checked (image, name_space, name, &error);
+ if (!klass)
+ g_error ("Runtime critical type %s.%s not found", name_space, name);
+ if (!mono_error_ok (&error))
+ g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
+ return klass;
+}
+
+/**
+ * mono_class_try_load_from_name:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * This function tries to load a type, returning the class was found or NULL otherwise.
+ * This function should be used by the runtime when probing for optional types, those that could have being linked out.
+ *
+ * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
+ * a type that we would otherwise assume to be available but was not due some error.
+ *
+ */
+MonoClass*
+mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
+{
+ MonoError error;
+ MonoClass *klass;
+
+ klass = mono_class_from_name_checked (image, name_space, name, &error);
+ if (!mono_error_ok (&error))
+ g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
return klass;
}
+
/**
* mono_class_is_subclass_of:
* @klass: class to probe if it is a subclass of another one
* This method determines whether @klass is a subclass of @klassc.
*
* If the @check_interfaces flag is set, then if @klassc is an interface
- * this method return true if the @klass implements the interface or
+ * this method return TRUE if the @klass implements the interface or
* if @klass is an interface, if one of its base classes is @klass.
*
* If @check_interfaces is false then, then if @klass is not an interface
- * then it returns true if the @klass is a subclass of @klassc.
+ * then it returns TRUE if the @klass is a subclass of @klassc.
*
* if @klass is an interface and @klassc is System.Object, then this function
* return true.
mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
gboolean check_interfaces)
{
-/*FIXME test for interfaces with variant generic arguments*/
+ /* FIXME test for interfaces with variant generic arguments */
+ mono_class_init (klass);
+ mono_class_init (klassc);
if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
int i;
MonoGenericContainer *container;
- if (!klass->generic_class)
+ if (!mono_class_is_ginst (klass))
return FALSE;
- container = klass->generic_class->container_class->generic_container;
+ container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
for (i = 0; i < container->type_argc; ++i)
if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
* @klass: the class to be assigned to
* @oklass: the source class
*
- * Both klass and oklass must be instances of the same generic interface.
- * Return true if @klass can be assigned to a @klass variable
+ * Both @klass and @oklass must be instances of the same generic interface.
+ *
+ * Returns: TRUE if @klass can be assigned to a @klass variable
*/
gboolean
mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
int j;
MonoType **klass_argv, **oklass_argv;
MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
- MonoGenericContainer *container = klass_gtd->generic_container;
+ MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
if (klass == oklass)
return TRUE;
if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
return FALSE;
- klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
- oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
+ klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+ oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
for (j = 0; j < container->type_argc; ++j) {
MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
* @klass: the class to be assigned to
* @oklass: the source class
*
- * Return: true if an instance of object oklass can be assigned to an
+ * Returns: TRUE if an instance of object oklass can be assigned to an
* instance of object @klass
*/
gboolean
mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
{
+ MonoError error;
/*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
if (!klass->inited)
mono_class_init (klass);
if (!oklass->inited)
mono_class_init (oklass);
- if (klass->exception_type || oklass->exception_type)
+ if (mono_class_has_failure (klass) || mono_class_has_failure (oklass))
return FALSE;
if (mono_type_is_generic_argument (&klass->byval_arg)) {
}
/* interface_offsets might not be set for dynamic classes */
- if (oklass->ref_info_handle && !oklass->interface_bitmap)
+ if (oklass->ref_info_handle && !oklass->interface_bitmap) {
/*
* oklass might be a generic type parameter but they have
* interface_offsets set.
*/
- return mono_reflection_call_is_assignable_to (oklass, klass);
+ gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error);
+ return FALSE;
+ }
+ return result;
+ }
if (!oklass->interface_bitmap)
/* Happens with generic instances of not-yet created dynamic types */
return FALSE;
return TRUE;
if (mono_class_has_variant_generic_params (klass)) {
- MonoError error;
int i;
mono_class_setup_interfaces (oklass, &error);
if (!mono_error_ok (&error)) {
int j;
MonoType **klass_argv, **oklass_argv;
MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
- MonoGenericContainer *container = klass_gtd->generic_container;
+ MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
/*Viable candidates are instances of the same generic interface*/
if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
return FALSE;
- klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
- oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
+ klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+ oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
for (j = 0; j < container->type_argc; ++j) {
MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
* mono_class_get_cctor:
* @klass: A MonoClass pointer
*
- * Returns: the static constructor of @klass if it exists, NULL otherwise.
+ * Returns: The static constructor of @klass if it exists, NULL otherwise.
*/
MonoMethod*
mono_class_get_cctor (MonoClass *klass)
return result;
}
- if (klass->generic_class && !klass->methods)
- return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
+ if (mono_class_is_ginst (klass) && !klass->methods)
+ return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class));
return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
}
* mono_class_get_finalizer:
* @klass: The MonoClass pointer
*
- * Returns: the finalizer method of @klass if it exists, NULL otherwise.
+ * Returns: The finalizer method of @klass if it exists, NULL otherwise.
*/
MonoMethod*
mono_class_get_finalizer (MonoClass *klass)
* mono_class_array_element_size:
* @klass:
*
- * Returns: the number of bytes an element of type @klass
+ * Returns: The number of bytes an element of type @klass
* uses when stored into an array.
*/
gint32
* mono_array_element_size:
* @ac: pointer to a #MonoArrayClass
*
- * Returns: the size of single array element.
+ * Returns: The size of single array element.
*/
gint32
mono_array_element_size (MonoClass *ac)
if (image_is_dynamic (image)) {
MonoClass *tmp_handle_class;
- gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
+ gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
+ mono_error_assert_ok (error);
g_assert (tmp_handle_class);
if (handle_class)
*handle_class = tmp_handle_class;
return NULL;
}
-/**
- * This function might need to call runtime functions so it can't be part
- * of the metadata library.
- */
-static MonoLookupDynamicToken lookup_dynamic = NULL;
-
-void
-mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
-{
- lookup_dynamic = func;
-}
-
gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
{
MonoClass *handle_class;
-
- return lookup_dynamic (image, token, TRUE, &handle_class, context);
+ mono_error_init (error);
+ return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
}
gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
{
- return lookup_dynamic (image, token, valid_token, handle_class, context);
+ return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
}
static MonoGetCachedClassInfo get_cached_class_info = NULL;
get_class_from_name = func;
}
+/**
+ * mono_class_get_image:
+ *
+ * Use this method to get the `MonoImage*` where this class came from.
+ *
+ * Returns: The image where this class is defined.
+ */
MonoImage*
mono_class_get_image (MonoClass *klass)
{
* mono_class_get_element_class:
* @klass: the MonoClass to act on
*
- * Returns: the element class of an array or an enumeration.
+ * Use this function to get the element class of an array.
+ *
+ * Returns: The element class of an array.
*/
MonoClass*
mono_class_get_element_class (MonoClass *klass)
* mono_class_is_valuetype:
* @klass: the MonoClass to act on
*
- * Returns: true if the MonoClass represents a ValueType.
+ * Use this method to determine if the provided `MonoClass*` represents a value type,
+ * or a reference type.
+ *
+ * Returns: TRUE if the MonoClass represents a ValueType, FALSE if it represents a reference type.
*/
gboolean
mono_class_is_valuetype (MonoClass *klass)
* mono_class_is_enum:
* @klass: the MonoClass to act on
*
- * Returns: true if the MonoClass represents an enumeration.
+ * Use this function to determine if the provided `MonoClass*` represents an enumeration.
+ *
+ * Returns: TRUE if the MonoClass represents an enumeration.
*/
gboolean
mono_class_is_enum (MonoClass *klass)
* mono_class_enum_basetype:
* @klass: the MonoClass to act on
*
- * Returns: the underlying type representation for an enumeration.
+ * Use this function to get the underlying type for an enumeration value.
+ *
+ * Returns: The underlying type representation for an enumeration.
*/
MonoType*
mono_class_enum_basetype (MonoClass *klass)
* mono_class_get_parent
* @klass: the MonoClass to act on
*
- * Returns: the parent class for this class.
+ * Returns: The parent class for this class.
*/
MonoClass*
mono_class_get_parent (MonoClass *klass)
}
/**
- * mono_class_get_nesting_type;
+ * mono_class_get_nesting_type:
* @klass: the MonoClass to act on
*
- * Returns: the container type where this type is nested or NULL if this type is not a nested type.
+ * Use this function to obtain the class that the provided `MonoClass*` is nested on.
+ *
+ * If the return is NULL, this indicates that this class is not nested.
+ *
+ * Returns: The container type where this type is nested or NULL if this type is not a nested type.
*/
MonoClass*
mono_class_get_nesting_type (MonoClass *klass)
* mono_class_get_rank:
* @klass: the MonoClass to act on
*
- * Returns: the rank for the array (the number of dimensions).
+ * Returns: The rank for the array (the number of dimensions).
*/
int
mono_class_get_rank (MonoClass *klass)
return klass->rank;
}
-/**
- * mono_class_get_flags:
- * @klass: the MonoClass to act on
- *
- * The type flags from the TypeDef table from the metadata.
- * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the
- * different values.
- *
- * Returns: the flags from the TypeDef table.
- */
-guint32
-mono_class_get_flags (MonoClass *klass)
-{
- return klass->flags;
-}
-
/**
* mono_class_get_name
* @klass: the MonoClass to act on
*
- * Returns: the name of the class.
+ * Returns: The name of the class.
*/
const char*
mono_class_get_name (MonoClass *klass)
* mono_class_get_namespace:
* @klass: the MonoClass to act on
*
- * Returns: the namespace of the class.
+ * Returns: The namespace of the class.
*/
const char*
mono_class_get_namespace (MonoClass *klass)
*
* This method returns the internal Type representation for the class.
*
- * Returns: the MonoType from the class.
+ * Returns: The MonoType from the class.
*/
MonoType*
mono_class_get_type (MonoClass *klass)
}
/**
- * mono_class_get_type_token
+ * mono_class_get_type_token:
* @klass: the MonoClass to act on
*
* This method returns type token for the class.
*
- * Returns: the type token for the class.
+ * Returns: The type token for the class.
*/
guint32
mono_class_get_type_token (MonoClass *klass)
* mono_class_num_fields:
* @klass: the MonoClass to act on
*
- * Returns: the number of static and instance fields in the class.
+ * Returns: The number of static and instance fields in the class.
*/
int
mono_class_num_fields (MonoClass *klass)
* mono_class_num_methods:
* @klass: the MonoClass to act on
*
- * Returns: the number of methods in the class.
+ * Returns: The number of methods in the class.
*/
int
mono_class_num_methods (MonoClass *klass)
* mono_class_num_properties
* @klass: the MonoClass to act on
*
- * Returns: the number of properties in the class.
+ * Returns: The number of properties in the class.
*/
int
mono_class_num_properties (MonoClass *klass)
* mono_class_num_events:
* @klass: the MonoClass to act on
*
- * Returns: the number of events in the class.
+ * Returns: The number of events in the class.
*/
int
mono_class_num_events (MonoClass *klass)
if (!iter)
return NULL;
if (!*iter) {
- mono_class_setup_fields_locking (klass);
- if (klass->exception_type)
+ mono_class_setup_fields (klass);
+ if (mono_class_has_failure (klass))
return NULL;
/* start from the first */
if (klass->field.count) {
start_index = GPOINTER_TO_UINT (*iter);
}
+ int first_idx = mono_class_get_first_method_idx (klass);
for (i = start_index; i < klass->method.count; ++i) {
guint32 flags;
- /* klass->method.first points into the methodptr table */
- flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
+ /* first_idx points into the methodptr table */
+ flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
if (flags & METHOD_ATTRIBUTE_VIRTUAL)
break;
if (i < klass->method.count) {
MonoError error;
- res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
+ res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
mono_error_cleanup (&error); /* FIXME don't swallow the error */
/* Add 1 here so the if (*iter) check fails */
* mono_class_is_delegate
* @klass: the MonoClass to act on
*
- * Returns: true if the MonoClass represents a System.Delegate.
+ * Returns: TRUE if the MonoClass represents a System.Delegate.
*/
mono_bool
mono_class_is_delegate (MonoClass *klass)
* @klass: The MonoClass to act on
* @interface: The interface to check if @klass implements.
*
- * Returns: true if @klass implements @interface.
+ * Returns: TRUE if @klass implements @interface.
*/
mono_bool
mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
* mono_field_get_name:
* @field: the MonoClassField to act on
*
- * Returns: the name of the field.
+ * Returns: The name of the field.
*/
const char*
mono_field_get_name (MonoClassField *field)
* The metadata flags for a field are encoded using the
* FIELD_ATTRIBUTE_* constants. See the tabledefs.h file for details.
*
- * Returns: the flags for the field.
+ * Returns: The flags for the field.
*/
guint32
mono_field_get_flags (MonoClassField *field)
}
/**
- * mono_field_get_offset;
+ * mono_field_get_offset:
* @field: the MonoClassField to act on
*
- * Returns: the field offset.
+ * Returns: The field offset.
*/
guint32
mono_field_get_offset (MonoClassField *field)
field_index = mono_field_get_index (field);
if (!klass->ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
- mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
+ int first_field_idx = mono_class_get_first_field_idx (klass);
+ mono_metadata_field_info (field->parent->image, first_field_idx + 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);
}
/**
- * mono_field_get_data;
+ * mono_field_get_data:
* @field: the MonoClassField to act on
*
- * Returns: pointer to the metadata constant value or to the field
+ * Returns: A pointer to the metadata constant value or to the field
* data if it has an RVA flag.
*/
const char *
* mono_property_get_name:
* @prop: the MonoProperty to act on
*
- * Returns: the name of the property
+ * Returns: The name of the property
*/
const char*
mono_property_get_name (MonoProperty *prop)
* mono_property_get_set_method
* @prop: the MonoProperty to act on.
*
- * Returns: the setter method of the property (A MonoMethod)
+ * Returns: The setter method of the property (A MonoMethod)
*/
MonoMethod*
mono_property_get_set_method (MonoProperty *prop)
* mono_property_get_get_method
* @prop: the MonoProperty to act on.
*
- * Returns: the setter method of the property (A MonoMethod)
+ * Returns: The setter method of the property (A MonoMethod)
*/
MonoMethod*
mono_property_get_get_method (MonoProperty *prop)
* mono_property_get_parent:
* @prop: the MonoProperty to act on.
*
- * Returns: the MonoClass where the property was defined.
+ * Returns: The MonoClass where the property was defined.
*/
MonoClass*
mono_property_get_parent (MonoProperty *prop)
* The metadata flags for a property are encoded using the
* PROPERTY_ATTRIBUTE_* constants. See the tabledefs.h file for details.
*
- * Returns: the flags for the property.
+ * Returns: The flags for the property.
*/
guint32
mono_property_get_flags (MonoProperty *prop)
* mono_event_get_name:
* @event: the MonoEvent to act on
*
- * Returns: the name of the event.
+ * Returns: The name of the event.
*/
const char*
mono_event_get_name (MonoEvent *event)
* mono_event_get_add_method:
* @event: The MonoEvent to act on.
*
- * Returns: the @add' method for the event (a MonoMethod).
+ * Returns: The @add' method for the event (a MonoMethod).
*/
MonoMethod*
mono_event_get_add_method (MonoEvent *event)
* mono_event_get_remove_method:
* @event: The MonoEvent to act on.
*
- * Returns: the @remove method for the event (a MonoMethod).
+ * Returns: The @remove method for the event (a MonoMethod).
*/
MonoMethod*
mono_event_get_remove_method (MonoEvent *event)
* mono_event_get_raise_method:
* @event: The MonoEvent to act on.
*
- * Returns: the @raise method for the event (a MonoMethod).
+ * Returns: The @raise method for the event (a MonoMethod).
*/
MonoMethod*
mono_event_get_raise_method (MonoEvent *event)
* mono_event_get_parent:
* @event: the MonoEvent to act on.
*
- * Returns: the MonoClass where the event is defined.
+ * Returns: The MonoClass where the event is defined.
*/
MonoClass*
mono_event_get_parent (MonoEvent *event)
* The metadata flags for an event are encoded using the
* EVENT_* constants. See the tabledefs.h file for details.
*
- * Returns: the flags for the event.
+ * Returns: The flags for the event.
*/
guint32
mono_event_get_flags (MonoEvent *event)
int i;
/* Search directly in the metadata to avoid calling setup_methods () */
+ int first_idx = mono_class_get_first_method_idx (klass);
for (i = 0; i < klass->method.count; ++i) {
MonoError error;
guint32 cols [MONO_METHOD_SIZE];
MonoMethod *method;
MonoMethodSignature *sig;
- /* klass->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);
+ /* first_idx points into the methodptr table */
+ mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
- method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
+ method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
if (!method) {
mono_error_cleanup (&error); /* FIXME don't swallow the error */
continue;
mono_class_init (klass);
- if (klass->generic_class && !klass->methods) {
- res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
+ if (mono_class_is_ginst (klass) && !klass->methods) {
+ res = mono_class_get_method_from_name_flags (mono_class_get_generic_class (klass)->container_class, name, param_count, flags);
if (res) {
MonoError error;
res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error);
*
* LOCKING: Acquires the loader lock.
*/
-gboolean
-mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
+static gboolean
+mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error)
{
- if (klass->exception_type)
+ g_assert (boxed_error != NULL);
+
+ if (mono_class_has_failure (klass))
return FALSE;
mono_loader_lock ();
- klass->exception_type = ex_type;
- if (ex_data)
- mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
+ klass->has_failure = 1;
+ mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, boxed_error);
mono_loader_unlock ();
return TRUE;
}
+gboolean
+mono_class_has_failure (const MonoClass *klass)
+{
+ g_assert (klass != NULL);
+ return klass->has_failure != 0;
+}
+
+
+/**
+ * mono_class_set_type_load_failure:
+ * @klass: class in which the failure was detected
+ * @fmt: Printf-style error message string.
+ *
+ * Collect detected failure informaion in the class for later processing.
+ * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class ()
+ * Note that only the first failure is kept.
+ *
+ * Returns FALSE if a failure was already set on the class, or TRUE otherwise.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
+gboolean
+mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
+{
+ MonoError prepare_error;
+ va_list args;
+
+ if (mono_class_has_failure (klass))
+ return FALSE;
+
+ mono_error_init (&prepare_error);
+
+ va_start (args, fmt);
+ mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
+ va_end (args);
+
+ MonoErrorBoxed *box = mono_error_box (&prepare_error, klass->image);
+ mono_error_cleanup (&prepare_error);
+ return mono_class_set_failure (klass, box);
+}
+
/*
* mono_class_get_exception_data:
*
*
* LOCKING: Acquires the loader lock.
*/
-gpointer
-mono_class_get_exception_data (MonoClass *klass)
+static gpointer
+mono_class_get_exception_data (const MonoClass *klass)
{
- return mono_image_property_lookup (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
+ return mono_image_property_lookup (klass->image, (MonoClass*)klass, MONO_CLASS_PROP_EXCEPTION_DATA);
}
/**
{
mono_os_mutex_init (&classes_mutex);
+ mono_native_tls_alloc (&setup_fields_tls_id, NULL);
+ mono_native_tls_alloc (&init_pending_tls_id, NULL);
+
+ mono_counters_register ("MonoClassDef count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
+ mono_counters_register ("MonoClassGtd count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
+ mono_counters_register ("MonoClassGenericInst count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
+ mono_counters_register ("MonoClassGenericParam count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
+ mono_counters_register ("MonoClassArray count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
+ mono_counters_register ("MonoClassPointer count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
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);
+
+ mono_counters_register ("MonoClassExt count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_count);
}
/**
void
mono_classes_cleanup (void)
{
+ mono_native_tls_free (setup_fields_tls_id);
+ mono_native_tls_free (init_pending_tls_id);
+
if (global_interface_bitset)
mono_bitset_free (global_interface_bitset);
global_interface_bitset = NULL;
MonoException*
mono_class_get_exception_for_failure (MonoClass *klass)
{
- gpointer exception_data = mono_class_get_exception_data (klass);
-
- switch (klass->exception_type) {
- case MONO_EXCEPTION_TYPE_LOAD: {
- MonoString *name;
- MonoException *ex;
- char *str = mono_type_get_full_name (klass);
- char *astr = klass->image->assembly? mono_stringify_assembly_name (&klass->image->assembly->aname): NULL;
- name = mono_string_new (mono_domain_get (), str);
- g_free (str);
- ex = mono_get_exception_type_load (name, astr);
- g_free (astr);
- return ex;
- }
- case MONO_EXCEPTION_MISSING_METHOD: {
- char *class_name = (char *)exception_data;
- char *assembly_name = class_name + strlen (class_name) + 1;
-
- return mono_get_exception_missing_method (class_name, assembly_name);
- }
- case MONO_EXCEPTION_MISSING_FIELD: {
- char *class_name = (char *)exception_data;
- char *member_name = class_name + strlen (class_name) + 1;
-
- return mono_get_exception_missing_field (class_name, member_name);
- }
- case MONO_EXCEPTION_FILE_NOT_FOUND: {
- char *msg_format = (char *)exception_data;
- char *assembly_name = msg_format + strlen (msg_format) + 1;
- char *msg = g_strdup_printf (msg_format, assembly_name);
- MonoException *ex;
-
- ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), assembly_name));
-
- g_free (msg);
-
- return ex;
- }
- case MONO_EXCEPTION_BAD_IMAGE: {
- return mono_get_exception_bad_image_format ((const char *)exception_data);
- }
- default: {
- MonoLoaderError *error;
- MonoException *ex;
-
- error = mono_loader_get_last_error ();
- if (error != NULL){
- ex = mono_loader_error_prepare_exception (error);
- return ex;
- }
-
- /* TODO - handle other class related failures */
+ if (!mono_class_has_failure (klass))
return NULL;
- }
- }
+ MonoError unboxed_error;
+ mono_error_init (&unboxed_error);
+ mono_error_set_for_class_failure (&unboxed_error, klass);
+ return mono_error_convert_to_exception (&unboxed_error);
}
static gboolean
MonoClass *
mono_class_get_generic_type_definition (MonoClass *klass)
{
- return klass->generic_class ? klass->generic_class->container_class : klass;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ return gklass ? gklass->container_class : klass;
}
/*
get_generic_definition_class (MonoClass *klass)
{
while (klass) {
- if (klass->generic_class && klass->generic_class->container_class)
- return klass->generic_class->container_class;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ if (gklass && gklass->container_class)
+ return gklass->container_class;
klass = klass->parent;
}
return NULL;
{
int access_level;
+ if (access_klass == member_klass)
+ return TRUE;
+
if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
return TRUE;
if (member_klass->element_class && !member_klass->enumtype)
member_klass = member_klass->element_class;
- access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+ access_level = mono_class_get_flags (member_klass) & 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))
+ if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
return FALSE;
if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
return TRUE;
- if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
- access_klass->generic_container) &&
+ MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
+ if (((access_gklass && access_gklass->container_class) ||
+ mono_class_is_gtd (access_klass)) &&
(member_generic_def = get_generic_definition_class (member_klass))) {
MonoClass *access_container;
- if (access_klass->generic_container)
+ if (mono_class_is_gtd (access_klass))
access_container = access_klass;
else
- access_container = access_klass->generic_class->container_class;
+ access_container = access_gklass->container_class;
if (can_access_member (access_container, member_generic_def, context_klass, access_level))
return TRUE;
return FALSE;
}
+/**
+ * mono_method_can_access_field:
+ * @method: Method that will attempt to access the field
+ * @field: the field to access
+ *
+ * Used to determine if a method is allowed to access the specified field.
+ *
+ * Returns: TRUE if the given @method is allowed to access the @field while following
+ * the accessibility rules of the CLI.
+ */
gboolean
mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
{
return can;
}
+/**
+ * mono_method_can_access_method:
+ * @method: Method that will attempt to access the other method
+ * @called: the method that we want to probe for accessibility.
+ *
+ * Used to determine if the @method is allowed to access the specified @called method.
+ *
+ * Returns: TRUE if the given @method is allowed to invoke the @called while following
+ * the accessibility rules of the CLI.
+ */
gboolean
mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
{
- int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
- if (!can) {
- MonoClass *nested = method->klass->nested_in;
- while (nested) {
- can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
- if (can)
- return TRUE;
- nested = nested->nested_in;
- }
- }
- /*
- * FIXME:
- * with generics calls to explicit interface implementations can be expressed
- * directly: the method is private, but we must allow it. This may be opening
- * a hole or the generics code should handle this differently.
- * Maybe just ensure the interface type is public.
- */
- if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
- return TRUE;
- return can;
+ method = mono_method_get_method_definition (method);
+ called = mono_method_get_method_definition (called);
+ return mono_method_can_access_method_full (method, called, NULL);
}
/*
gboolean
mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
{
+ /* Wrappers are except from access checks */
+ if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
+ return TRUE;
+
MonoClass *access_class = method->klass;
MonoClass *member_class = called->klass;
int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
* FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
* FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
*/
-gboolean mono_class_is_valid_enum (MonoClass *klass) {
+gboolean
+mono_class_is_valid_enum (MonoClass *klass)
+{
MonoClassField * field;
gpointer iter = NULL;
gboolean found_base_field = FALSE;
return FALSE;
}
- if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ if (!mono_class_is_auto_layout (klass))
return FALSE;
while ((field = mono_class_get_fields (klass, &iter))) {
gboolean
mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
{
- return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
+ return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
}
/*
if (!klass->ext)
klass->ext = ext;
class_ext_size += sizeof (MonoClassExt);
+ ++class_ext_count;
mono_image_unlock (klass->image);
}
if (interface_count > 1)
interfaces [1] = mono_class_bind_generic_parameters (
mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
- } else if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ } else if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_setup_interfaces (gklass, error);
if (!mono_error_ok (error)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
+ mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
return;
}
interface_count = gklass->interface_count;
interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
for (i = 0; i < interface_count; i++) {
- interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
+ interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
if (!mono_error_ok (error)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
+ mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
return;
}
}
{
MonoClass *klass = field->parent;
MonoImage *image = klass->image;
- MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+ MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
int field_idx = field - klass->fields;
mono_error_init (error);
MonoClassField *gfield = >d->fields [field_idx];
MonoType *gtype = mono_field_get_type_checked (gfield, error);
if (!mono_error_ok (error)) {
- char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
- g_free (err_msg);
+ char *full_name = mono_type_get_full_name (gtd);
+ mono_class_set_type_load_failure (klass, "Could not load generic type of field '%s:%s' (%d) due to: %s", full_name, gfield->name, field_idx, mono_error_get_message (error));
+ g_free (full_name);
}
field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
if (!mono_error_ok (error)) {
- char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
- g_free (err_msg);
+ char *full_name = mono_type_get_full_name (klass);
+ mono_class_set_type_load_failure (klass, "Could not load instantiated type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
+ g_free (full_name);
}
} else {
const char *sig;
guint32 cols [MONO_FIELD_SIZE];
MonoGenericContainer *container = NULL;
- int idx = klass->field.first + field_idx;
+ int idx = mono_class_get_first_field_idx (klass) + field_idx;
/*FIXME, in theory we do not lazy load SRE fields*/
g_assert (!image_is_dynamic (image));
- if (klass->generic_container) {
- container = klass->generic_container;
+ if (mono_class_is_gtd (klass)) {
+ container = mono_class_get_generic_container (klass);
} else if (gtd) {
- container = gtd->generic_container;
+ container = mono_class_get_generic_container (gtd);
g_assert (container);
}
- /* klass->field.first and idx points into the fieldptr table */
+ /* first_field_idx and idx points into the fieldptr table */
mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
- mono_error_set_type_load_class (error, klass, "Could not verify field %s signature", field->name);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ char *full_name = mono_type_get_full_name (klass);
+ mono_error_set_type_load_class (error, klass, "Could not verify field '%s:%s' signature", full_name, field->name);;
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
+ g_free (full_name);
return;
}
mono_metadata_decode_value (sig, &sig);
/* FIELD signature == 0x06 */
g_assert (*sig == 0x06);
- field->type = mono_metadata_parse_type_full (image, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
- if (!field->type)
- mono_class_set_failure_from_loader_error (klass, error, g_strdup_printf ("Could not load field %s type", field->name));
+
+ field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
+ if (!field->type) {
+ char *full_name = mono_type_get_full_name (klass);
+ mono_class_set_type_load_failure (klass, "Could not load type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
+ g_free (full_name);
+ }
}
}
{
MonoClass *klass = field->parent;
MonoImage *image = klass->image;
- MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+ MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
int field_idx = field - klass->fields;
MonoClassField *gfield = >d->fields [field_idx];
return mono_field_get_flags (gfield);
} else {
- int idx = klass->field.first + field_idx;
+ int idx = mono_class_get_first_field_idx (klass) + field_idx;
/*FIXME, in theory we do not lazy load SRE fields*/
g_assert (!image_is_dynamic (image));
}
}
-/**
- * mono_class_setup_basic_field_info:
- * @class: The class to initialize
- *
- * Initializes the klass->fields array of fields.
- * Aquires the loader lock.
- */
-static void
-mono_class_setup_basic_field_info_locking (MonoClass *klass)
-{
- mono_loader_lock ();
- mono_class_setup_basic_field_info (klass);
- mono_loader_unlock ();
-}
-
/**
* mono_class_get_fields_lazy:
* @klass: the MonoClass to act on
if (!iter)
return NULL;
if (!*iter) {
- mono_class_setup_basic_field_info_locking (klass);
+ mono_class_setup_basic_field_info (klass);
if (!klass->fields)
return NULL;
/* start from the first */
return mono_type_full_name (&klass->byval_arg);
}
+/* Declare all shared lazy type lookup functions */
+GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)