static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
static int generic_array_methods (MonoClass *klass);
-static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos);
+static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
MonoClass *res = NULL;
MonoImage *module;
- mono_error_init (error);
+ error_init (error);
if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
return NULL;
static MonoType*
inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
{
- mono_error_init (error);
+ error_init (error);
switch (type->type) {
case MONO_TYPE_MVAR: {
mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
{
MonoType *inflated = NULL;
- mono_error_init (error);
+ error_init (error);
if (context)
inflated = inflate_generic_type (image, type, context, error);
{
MonoType *inflated = NULL;
- mono_error_init (error);
+ error_init (error);
if (context) {
inflated = inflate_generic_type (image, type, context, error);
return_val_if_nok (error, NULL);
MonoGenericInst *method_inst = NULL;
MonoGenericContext res = { NULL, NULL };
- mono_error_init (error);
+ error_init (error);
if (context->class_inst) {
class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
MonoMethodSignature *sig;
MonoGenericContext tmp_context;
- mono_error_init (error);
+ error_init (error);
/* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
while (method->is_inflated) {
g_assert (klass->enumtype);
- mono_error_init (error);
+ error_init (error);
container = mono_class_try_get_generic_container (klass);
if (mono_class_is_ginst (klass)) {
{
if (mono_class_has_failure (caused_by)) {
MonoError cause_error;
- mono_error_init (&cause_error);
+ 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);
init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
{
if (cached_info) {
+ mono_loader_lock ();
klass->instance_size = cached_info->instance_size;
klass->sizes.class_size = cached_info->class_size;
klass->packing_size = cached_info->packing_size;
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;
+ mono_loader_unlock ();
}
else {
if (!klass->size_inited)
mono_class_setup_fields (field_class);
if (mono_class_has_failure (field_class)) {
MonoError field_error;
- mono_error_init (&field_error);
+ 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);
amethod = create_array_method (klass, "Set", sig);
methods [method_num++] = amethod;
+ GHashTable *cache = g_hash_table_new (NULL, NULL);
for (i = 0; i < klass->interface_count; i++)
- setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
+ setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
+ g_hash_table_destroy (cache);
} else if (mono_class_has_static_metadata (klass)) {
MonoError error;
int first_idx = mono_class_get_first_method_idx (klass);
MonoEvent *event = &events [i];
MonoEvent *gevent = &ginfo->events [i];
- mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok
+ error_init (&error); //since we do conditional calls, we must ensure the default value is ok
event->parent = klass;
event->name = gevent->name;
}
static void
-setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos)
+setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
{
MonoGenericContext tmp_context;
int i;
for (i = 0; i < generic_array_method_num; i++) {
MonoError error;
MonoMethod *m = generic_array_method_info [i].array_method;
- MonoMethod *inflated;
+ MonoMethod *inflated, *helper;
inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, &error);
- g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
- methods [pos++] = mono_marshal_get_generic_array_helper (klass, iface, generic_array_method_info [i].name, inflated);
+ mono_error_assert_ok (&error);
+ helper = g_hash_table_lookup (cache, inflated);
+ if (!helper) {
+ helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
+ g_hash_table_insert (cache, inflated, helper);
+ }
+ methods [pos ++] = helper;
}
}
}
}
- mono_image_lock (klass->image);
-
+ mono_loader_lock ();
if (!klass->has_finalize_inited) {
klass->has_finalize = has_finalize ? 1 : 0;
mono_memory_barrier ();
klass->has_finalize_inited = TRUE;
}
-
- mono_image_unlock (klass->image);
+ mono_loader_unlock ();
return klass->has_finalize;
}
guint32 field_last, method_last;
guint32 nesting_tokeen;
- mono_error_init (error);
+ error_init (error);
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_error_cleanup (&error);
}
}
+ mono_loader_lock ();
if (klass->parent)
mono_class_setup_parent (klass, klass->parent);
klass->cast_class = gtd->cast_class;
klass->element_class = gtd->element_class;
}
+ mono_loader_unlock ();
}
gboolean
if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
/*Arrays of those two types are invalid.*/
MonoError prepared_error;
- mono_error_init (&prepared_error);
+ 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);
{
MonoClass *klass;
- mono_error_init (error);
+ error_init (error);
klass = mono_class_get_checked (image, type_token, error);
if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
{
MonoClass *klass = NULL;
- mono_error_init (error);
+ error_init (error);
if (image_is_dynamic (image)) {
int table = mono_metadata_token_table (type_token);
MonoType *type = NULL;
gboolean inflated = FALSE;
- mono_error_init (error);
+ 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)) {
const char *nspace;
guint32 i, visib;
- mono_error_init (error);
+ error_init (error);
if (image_is_dynamic (image)) {
guint32 token = 0;
MonoClass *klass;
int i;
- mono_error_init (error);
+ error_init (error);
/*
* The EXPORTEDTYPES table only contains public types, so have to search the
char *nested;
char buf [1024];
- mono_error_init (error);
+ error_init (error);
// Checking visited images avoids stack overflows when cyclic references exist.
if (g_hash_table_lookup (visited_images, image))
/*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
if (image_is_dynamic (candidate->image) && !candidate->wastypebuilder) {
- MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info (candidate);
+ MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info_raw (candidate); /* FIXME use handles */
int j;
if (tb && tb->interfaces) {
for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
MonoGenericContext *context, MonoError *error)
{
- mono_error_init (error);
+ error_init (error);
if (image_is_dynamic (image)) {
MonoClass *tmp_handle_class;
mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
{
MonoClass *handle_class;
- mono_error_init (error);
+ error_init (error);
return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
}
if (klass->nested_classes_inited)
return;
- if (!klass->type_token)
+ if (!klass->type_token) {
+ mono_loader_lock ();
klass->nested_classes_inited = TRUE;
+ mono_loader_unlock ();
+ return;
+ }
i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
classes = NULL;
MonoType*
mono_field_get_type_checked (MonoClassField *field, MonoError *error)
{
- mono_error_init (error);
+ error_init (error);
if (!field->type)
mono_field_resolve_type (field, error);
return field->type;
if (mono_class_has_failure (klass))
return FALSE;
- mono_error_init (&prepare_error);
+ error_init (&prepare_error);
va_start (args, fmt);
mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
if (!mono_class_has_failure (klass))
return NULL;
MonoError unboxed_error;
- mono_error_init (&unboxed_error);
+ error_init (&unboxed_error);
mono_error_set_for_class_failure (&unboxed_error, klass);
return mono_error_convert_to_exception (&unboxed_error);
}
int i, interface_count;
MonoClass **interfaces;
- mono_error_init (error);
+ error_init (error);
if (klass->interfaces_inited)
return;
MonoType *args [1];
/* generic IList, ICollection, IEnumerable */
- interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
+ interface_count = 2;
interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
args [0] = &klass->element_class->byval_arg;
interfaces [0] = mono_class_bind_generic_parameters (
mono_defaults.generic_ilist_class, 1, args, FALSE);
- if (interface_count > 1)
- interfaces [1] = mono_class_bind_generic_parameters (
+ interfaces [1] = mono_class_bind_generic_parameters (
mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
} else if (mono_class_is_ginst (klass)) {
MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
interfaces = NULL;
}
- mono_image_lock (klass->image);
-
+ mono_loader_lock ();
if (!klass->interfaces_inited) {
klass->interface_count = interface_count;
klass->interfaces = interfaces;
klass->interfaces_inited = TRUE;
}
-
- mono_image_unlock (klass->image);
+ mono_loader_unlock ();
}
static void
MonoType *ftype;
int field_idx = field - klass->fields;
- mono_error_init (error);
+ error_init (error);
if (gtd) {
MonoClassField *gfield = >d->fields [field_idx];
MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
int field_idx = field - klass->fields;
-
if (gtd) {
MonoClassField *gfield = >d->fields [field_idx];
return mono_field_get_flags (gfield);
}
/* Declare all shared lazy type lookup functions */
-GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)
+GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, "System.Runtime.InteropServices", "SafeHandle")
+
+/**
+ * mono_method_get_base_method:
+ * @method: a method
+ * @definition: if true, get the definition
+ * @error: set on failure
+ *
+ * Given a virtual method associated with a subclass, return the corresponding
+ * method from an ancestor. If @definition is FALSE, returns the method in the
+ * superclass of the given method. If @definition is TRUE, return the method
+ * in the ancestor class where it was first declared. The type arguments will
+ * be inflated in the ancestor classes. If the method is not associated with a
+ * class, or isn't virtual, returns the method itself. On failure returns NULL
+ * and sets @error.
+ */
+MonoMethod*
+mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error)
+{
+ MonoClass *klass, *parent;
+ MonoGenericContext *generic_inst = NULL;
+ MonoMethod *result = NULL;
+ int slot;
+
+ if (method->klass == NULL)
+ return method;
+
+ if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
+ MONO_CLASS_IS_INTERFACE (method->klass) ||
+ method->flags & METHOD_ATTRIBUTE_NEW_SLOT)
+ return method;
+
+ slot = mono_method_get_vtable_slot (method);
+ if (slot == -1)
+ return method;
+
+ klass = method->klass;
+ if (mono_class_is_ginst (klass)) {
+ generic_inst = mono_class_get_context (klass);
+ klass = mono_class_get_generic_class (klass)->container_class;
+ }
+
+retry:
+ if (definition) {
+ /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */
+ for (parent = klass->parent; parent != NULL; parent = parent->parent) {
+ /* on entry, klass is either a plain old non-generic class and generic_inst == NULL
+ or klass is the generic container class and generic_inst is the instantiation.
+
+ when we go to the parent, if the parent is an open constructed type, we need to
+ replace the type parameters by the definitions from the generic_inst, and then take it
+ apart again into the klass and the generic_inst.
+
+ For cases like this:
+ class C<T> : B<T, int> {
+ public override void Foo () { ... }
+ }
+ class B<U,V> : A<HashMap<U,V>> {
+ public override void Foo () { ... }
+ }
+ class A<X> {
+ public virtual void Foo () { ... }
+ }
+
+ if at each iteration the parent isn't open, we can skip inflating it. if at some
+ iteration the parent isn't generic (after possible inflation), we set generic_inst to
+ NULL;
+ */
+ MonoGenericContext *parent_inst = NULL;
+ if (mono_class_is_open_constructed_type (mono_class_get_type (parent))) {
+ parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error);
+ return_val_if_nok (error, NULL);
+ }
+ if (mono_class_is_ginst (parent)) {
+ parent_inst = mono_class_get_context (parent);
+ parent = mono_class_get_generic_class (parent)->container_class;
+ }
+
+ mono_class_setup_vtable (parent);
+ if (parent->vtable_size <= slot)
+ break;
+ klass = parent;
+ generic_inst = parent_inst;
+ }
+ } else {
+ klass = klass->parent;
+ if (!klass)
+ return method;
+ if (mono_class_is_open_constructed_type (mono_class_get_type (klass))) {
+ klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
+ return_val_if_nok (error, NULL);
+
+ generic_inst = NULL;
+ }
+ if (mono_class_is_ginst (klass)) {
+ generic_inst = mono_class_get_context (klass);
+ klass = mono_class_get_generic_class (klass)->container_class;
+ }
+
+ }
+
+ if (generic_inst) {
+ klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
+ return_val_if_nok (error, NULL);
+ }
+
+ if (klass == method->klass)
+ return method;
+
+ /*This is possible if definition == FALSE.
+ * Do it here to be really sure we don't read invalid memory.
+ */
+ if (slot >= klass->vtable_size)
+ return method;
+
+ mono_class_setup_vtable (klass);
+
+ result = klass->vtable [slot];
+ if (result == NULL) {
+ /* It is an abstract method */
+ gboolean found = FALSE;
+ gpointer iter = NULL;
+ while ((result = mono_class_get_methods (klass, &iter))) {
+ if (result->slot == slot) {
+ found = TRUE;
+ break;
+ }
+ }
+ /* found might be FALSE if we looked in an abstract class
+ * that doesn't override an abstract method of its
+ * parent:
+ * abstract class Base {
+ * public abstract void Foo ();
+ * }
+ * abstract class Derived : Base { }
+ * class Child : Derived {
+ * public override void Foo () { }
+ * }
+ *
+ * if m was Child.Foo and we ask for the base method,
+ * then we get here with klass == Derived and found == FALSE
+ */
+ /* but it shouldn't be the case that if we're looking
+ * for the definition and didn't find a result; the
+ * loop above should've taken us as far as we could
+ * go! */
+ g_assert (!(definition && !found));
+ if (!found)
+ goto retry;
+ }
+
+ g_assert (result != NULL);
+ return result;
+}