X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmetadata.c;h=da6ba91e1ac6b1d2872880dcba685d83be84ab60;hb=87f4f81d52ee965d3a242517300cf74e0c3810b8;hp=3a2dbd2e49eda5e35b1a17444144044d64486e53;hpb=36f31ed56de84ec41627e2d55bc550950eeb99bd;p=mono.git diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c index 3a2dbd2e49e..da6ba91e1ac 100644 --- a/mono/metadata/metadata.c +++ b/mono/metadata/metadata.c @@ -10,9 +10,6 @@ */ #include -#ifdef HAVE_ALLOCA_H -#include -#endif #include #include #include @@ -24,9 +21,19 @@ #include "tokentype.h" #include "metadata-internals.h" #include "class-internals.h" +#include "verify-internals.h" #include "class.h" +#include "marshal.h" +#include "debug-helpers.h" +#include + +/* Auxiliary structure used for caching inflated signatures */ +typedef struct { + MonoMethodSignature *sig; + MonoGenericContext context; +} MonoInflatedMethodSignature; -static gboolean do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container, +static gboolean do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container, gboolean transient, const char *ptr, const char **rptr); static gboolean do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only); @@ -37,6 +44,7 @@ static gboolean _mono_metadata_generic_class_equal (const MonoGenericClass *g1, static void free_generic_inst (MonoGenericInst *ginst); static void free_generic_class (MonoGenericClass *ginst); static void free_inflated_method (MonoMethodInflated *method); +static void free_inflated_signature (MonoInflatedMethodSignature *sig); static void mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva, MonoMarshalSpec **marshal_spec, gboolean alloc_from_image); /* @@ -180,7 +188,7 @@ const static unsigned char TableSchemas [] = { #define EVENT_SCHEMA_OFFSET EVENTMAP_SCHEMA_OFFSET + 3 MONO_MT_UINT16, /* "EventFlags#EventAttribute" }, */ MONO_MT_STRING_IDX, /* "Name" }, */ - MONO_MT_TABLE_IDX, /* "EventType" }, TypeDef or TypeRef */ + MONO_MT_TDOR_IDX, /* "EventType" }, TypeDef or TypeRef or TypeSpec */ MONO_MT_END, #define EVENT_POINTER_SCHEMA_OFFSET EVENT_SCHEMA_OFFSET + 4 @@ -440,12 +448,6 @@ mono_tables_names [] = { #endif -/* Auxiliary structure used for caching inflated signatures */ -typedef struct { - MonoMethodSignature *sig; - MonoGenericContext context; -} MonoInflatedMethodSignature; - /** * mono_meta_table_name: * @table: table index @@ -533,7 +535,7 @@ mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bit case MONO_TABLE_ASSEMBLYREFOS: g_assert (i == 3); field_size = idx_size (MONO_TABLE_ASSEMBLYREF); break; - case MONO_TABLE_ASSEMBLYPROCESSOR: + case MONO_TABLE_ASSEMBLYREFPROCESSOR: g_assert (i == 1); field_size = idx_size (MONO_TABLE_ASSEMBLYREF); break; case MONO_TABLE_CLASSLAYOUT: @@ -544,13 +546,6 @@ mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bit field_size = i ? idx_size (MONO_TABLE_EVENT): idx_size(MONO_TABLE_TYPEDEF); break; - case MONO_TABLE_EVENT: - g_assert (i == 2); - n = MAX (meta->tables [MONO_TABLE_TYPEDEF].rows, meta->tables [MONO_TABLE_TYPEREF].rows); - n = MAX (n, meta->tables [MONO_TABLE_TYPESPEC].rows); - /*This is a coded token for 3 tables, so takes 2 bits */ - field_size = rtsize (n, 16 - MONO_TYPEDEFORREF_BITS); - break; case MONO_TABLE_EVENT_POINTER: g_assert (i == 0); field_size = idx_size (MONO_TABLE_EVENT); break; @@ -605,24 +600,18 @@ mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bit idx_size(MONO_TABLE_METHOD); break; case MONO_TABLE_GENERICPARAM: - g_assert (i == 2 || i == 4 || i == 5); - if (i == 2) { - n = MAX (meta->tables [MONO_TABLE_METHOD].rows, meta->tables [MONO_TABLE_TYPEDEF].rows); - /*This is a coded token for 2 tables, so takes 1 bit */ - field_size = rtsize (n, 16 - MONO_TYPEORMETHOD_BITS); - } else if (i == 4) - field_size = idx_size (MONO_TABLE_TYPEDEF); - else if (i == 5) - field_size = idx_size (MONO_TABLE_TYPEDEF); + g_assert (i == 2); + n = MAX (meta->tables [MONO_TABLE_METHOD].rows, meta->tables [MONO_TABLE_TYPEDEF].rows); + /*This is a coded token for 2 tables, so takes 1 bit */ + field_size = rtsize (n, 16 - MONO_TYPEORMETHOD_BITS); break; - case MONO_TABLE_GENERICPARAMCONSTRAINT: g_assert (i == 0); field_size = idx_size (MONO_TABLE_GENERICPARAM); break; default: - g_assert_not_reached (); + g_error ("Can't handle MONO_MT_TABLE_IDX for table %d element %d", tableindex, i); } break; @@ -865,7 +854,7 @@ const char * mono_metadata_locate (MonoImage *meta, int table, int idx) { /* idx == 0 refers always to NULL */ - g_return_val_if_fail (idx > 0 && idx <= meta->tables [table].rows, ""); + g_return_val_if_fail (idx > 0 && idx <= meta->tables [table].rows, ""); /*FIXME shouldn't we return NULL here?*/ return meta->tables [table].base + (meta->tables [table].row_size * (idx - 1)); } @@ -922,7 +911,7 @@ mono_metadata_user_string (MonoImage *meta, guint32 index) const char * mono_metadata_blob_heap (MonoImage *meta, guint32 index) { - g_return_val_if_fail (index < meta->heap_blob.size, ""); + g_return_val_if_fail (index < meta->heap_blob.size, "");/*FIXME shouldn't we return NULL and check for index == 0?*/ return meta->heap_blob.data + index; } @@ -969,6 +958,7 @@ mono_metadata_decode_row (const MonoTableInfo *t, int idx, guint32 *res, int res const char *data; g_assert (idx < t->rows); + g_assert (idx >= 0); data = t->base + idx * t->row_size; g_assert (res_size == count); @@ -1251,27 +1241,29 @@ mono_metadata_parse_custom_mod (MonoImage *m, MonoCustomMod *dest, const char *p } /* - * mono_metadata_parse_array_full: + * mono_metadata_parse_array_internal: * @m: a metadata context. + * @transient: whenever to allocate data from the heap * @ptr: a pointer to an encoded array description. * @rptr: pointer updated to match the end of the decoded stream * * Decodes the compressed array description found in the metadata @m at @ptr. * * Returns: a #MonoArrayType structure describing the array type - * and dimensions. Memory is allocated from the image mempool. + * and dimensions. Memory is allocated from the heap or from the image mempool, depending + * on the value of @transient. * * LOCKING: Acquires the loader lock */ -MonoArrayType * -mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container, - const char *ptr, const char **rptr) +static MonoArrayType * +mono_metadata_parse_array_internal (MonoImage *m, MonoGenericContainer *container, + gboolean transient, const char *ptr, const char **rptr) { int i; MonoArrayType *array; MonoType *etype; - array = mono_image_alloc0 (m, sizeof (MonoArrayType)); + array = transient ? g_malloc0 (sizeof (MonoArrayType)) : mono_image_alloc0 (m, sizeof (MonoArrayType)); etype = mono_metadata_parse_type_full (m, container, MONO_PARSE_TYPE, 0, ptr, &ptr); if (!etype) return NULL; @@ -1280,13 +1272,13 @@ mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container, array->numsizes = mono_metadata_decode_value (ptr, &ptr); if (array->numsizes) - array->sizes = g_new0 (int, array->numsizes); + array->sizes = transient ? g_malloc0 (sizeof (int) * array->numsizes) : mono_image_alloc0 (m, sizeof (int) * array->numsizes); for (i = 0; i < array->numsizes; ++i) array->sizes [i] = mono_metadata_decode_value (ptr, &ptr); array->numlobounds = mono_metadata_decode_value (ptr, &ptr); if (array->numlobounds) - array->lobounds = g_new0 (int, array->numlobounds); + array->lobounds = transient ? g_malloc0 (sizeof (int) * array->numlobounds) : mono_image_alloc0 (m, sizeof (int) * array->numlobounds); for (i = 0; i < array->numlobounds; ++i) array->lobounds [i] = mono_metadata_decode_signed_value (ptr, &ptr); @@ -1295,6 +1287,13 @@ mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container, return array; } +MonoArrayType * +mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container, + const char *ptr, const char **rptr) +{ + return mono_metadata_parse_array_internal (m, container, FALSE, ptr, rptr); +} + MonoArrayType * mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr) { @@ -1366,22 +1365,10 @@ builtin_types[] = { #define NBUILTIN_TYPES() (sizeof (builtin_types) / sizeof (builtin_types [0])) static GHashTable *type_cache = NULL; -static GHashTable *generic_inst_cache = NULL; -static GHashTable *generic_class_cache = NULL; static int next_generic_inst_id = 0; -/* - * Protected by the loader lock. - * It has a MonoMethodInflated* as key and value. - * The key lookup will just access the declaring and context fields - */ -static GHashTable *generic_method_cache = NULL; - -/* - * Protected by the loader lock. - * It has a MonoInflatedMethodSignature* as key and value. - */ -static GHashTable *generic_signature_cache = NULL; +static MonoImageSet *mscorlib_image_set; +static GPtrArray *image_sets; static guint mono_generic_class_hash (gconstpointer data); @@ -1430,12 +1417,14 @@ mono_generic_inst_equal_full (const MonoGenericInst *a, const MonoGenericInst *b { int i; +#ifndef MONO_SMALL_CONFIG if (a->id && b->id) { if (a->id == b->id) return TRUE; if (!signature_only) return FALSE; } +#endif if (a->is_open != b->is_open || a->type_argc != b->type_argc) return FALSE; @@ -1489,8 +1478,6 @@ mono_metadata_init (void) int i; type_cache = g_hash_table_new (mono_type_hash, mono_type_equal); - generic_inst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst); - generic_class_cache = g_hash_table_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class); for (i = 0; i < NBUILTIN_TYPES (); ++i) g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]); @@ -1506,17 +1493,9 @@ void mono_metadata_cleanup (void) { g_hash_table_destroy (type_cache); - g_hash_table_destroy (generic_inst_cache); - g_hash_table_destroy (generic_class_cache); - if (generic_method_cache) - g_hash_table_destroy (generic_method_cache); - if (generic_signature_cache) - g_hash_table_destroy (generic_signature_cache); type_cache = NULL; - generic_inst_cache = NULL; - generic_class_cache = NULL; - generic_method_cache = NULL; - generic_signature_cache = NULL; + g_ptr_array_free (image_sets, TRUE); + image_sets = NULL; } /** @@ -1526,6 +1505,7 @@ mono_metadata_cleanup (void) * @opt_attrs: optional attributes to store in the returned type * @ptr: pointer to the type representation * @rptr: pointer updated to match the end of the decoded stream + * @transient: whenever to allocate the result from the heap or from a mempool * * Decode a compressed type description found at @ptr in @m. * @mode can be one of MONO_PARSE_MOD_TYPE, MONO_PARSE_PARAM, MONO_PARSE_RET, @@ -1535,18 +1515,17 @@ mono_metadata_cleanup (void) * * To parse a generic type, `generic_container' points to the current class'es * (the `generic_container' field in the MonoClass) or the current generic method's - * (the `generic_container' field in the MonoMethodNormal) generic container. + * (stored in image->property_hash) generic container. * When we encounter any MONO_TYPE_VAR or MONO_TYPE_MVAR's, they're looked up in * this MonoGenericContainer. - * This is a Mono runtime internal function. * * LOCKING: Acquires the loader lock. * * Returns: a #MonoType structure representing the decoded type. */ -MonoType* -mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, MonoParseTypeMode mode, - short opt_attrs, const char *ptr, const char **rptr) +static MonoType* +mono_metadata_parse_type_internal (MonoImage *m, MonoGenericContainer *container, MonoParseTypeMode mode, + short opt_attrs, gboolean transient, const char *ptr, const char **rptr) { MonoType *type, *cached; MonoType stype; @@ -1588,13 +1567,16 @@ mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, Mo } if (count) { - type = mono_image_alloc0 (m, sizeof (MonoType) + ((gint32)count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoCustomMod)); + int size; + + size = MONO_SIZEOF_TYPE + ((gint32)count) * sizeof (MonoCustomMod); + type = transient ? g_malloc0 (size) : mono_image_alloc0 (m, size); type->num_mods = count; if (count > 64) g_warning ("got more than 64 modifiers in type"); } else { type = &stype; - memset (type, 0, sizeof (MonoType)); + memset (type, 0, MONO_SIZEOF_TYPE); } /* Parse pinned, byref and custom modifiers */ @@ -1624,14 +1606,14 @@ mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, Mo type->byref = byref; type->pinned = pinned ? 1 : 0; - if (!do_mono_metadata_parse_type (type, m, container, ptr, &ptr)) { + if (!do_mono_metadata_parse_type (type, m, container, transient, ptr, &ptr)) { return NULL; } if (rptr) *rptr = ptr; - if (!type->num_mods) { + if (!type->num_mods && !transient) { /* no need to free type here, because it is on the stack */ if ((type->type == MONO_TYPE_CLASS || type->type == MONO_TYPE_VALUETYPE) && !type->pinned && !type->attrs) { MonoType *ret = type->byref ? &type->data.klass->this_arg : &type->data.klass->byval_arg; @@ -1667,12 +1649,19 @@ mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, Mo /* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */ if (type == &stype) { - type = mono_image_alloc (m, sizeof (MonoType)); - memcpy (type, &stype, sizeof (MonoType)); + type = transient ? g_malloc (MONO_SIZEOF_TYPE) : mono_image_alloc (m, MONO_SIZEOF_TYPE); + memcpy (type, &stype, MONO_SIZEOF_TYPE); } return type; } +MonoType* +mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, MonoParseTypeMode mode, + short opt_attrs, const char *ptr, const char **rptr) +{ + return mono_metadata_parse_type_internal (m, container, mode, opt_attrs, FALSE, ptr, rptr); +} + /* * LOCKING: Acquires the loader lock. */ @@ -1683,32 +1672,62 @@ mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs, return mono_metadata_parse_type_full (m, NULL, mode, opt_attrs, ptr, rptr); } +gboolean +mono_metadata_method_has_param_attrs (MonoImage *m, int def) +{ + MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM]; + MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD]; + guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST); + + if (def < methodt->rows) + lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST); + else + lastp = m->tables [MONO_TABLE_PARAM].rows + 1; + + for (i = param_index; i < lastp; ++i) { + guint32 flags = mono_metadata_decode_row_col (paramt, i - 1, MONO_PARAM_FLAGS); + if (flags) + return TRUE; + } + + return FALSE; +} + /* * mono_metadata_get_param_attrs: * + * @m The image to loader parameter attributes from + * @def method def token (one based) + * @param_count number of params to decode including the return value + * * Return the parameter attributes for the method whose MethodDef index is DEF. The * returned memory needs to be freed by the caller. If all the param attributes are * 0, then NULL is returned. */ int* -mono_metadata_get_param_attrs (MonoImage *m, int def) +mono_metadata_get_param_attrs (MonoImage *m, int def, int param_count) { MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM]; MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD]; guint32 cols [MONO_PARAM_SIZE]; - guint lastp, i, param_index = mono_metadata_decode_row_col (&m->tables [MONO_TABLE_METHOD], def - 1, MONO_METHOD_PARAMLIST); + guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST); int *pattrs = NULL; if (def < methodt->rows) - lastp = mono_metadata_decode_row_col (&m->tables [MONO_TABLE_METHOD], def, MONO_METHOD_PARAMLIST); + lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST); else lastp = paramt->rows + 1; for (i = param_index; i < lastp; ++i) { - mono_metadata_decode_row (&m->tables [MONO_TABLE_PARAM], i - 1, cols, MONO_PARAM_SIZE); + mono_metadata_decode_row (paramt, i - 1, cols, MONO_PARAM_SIZE); if (cols [MONO_PARAM_FLAGS]) { if (!pattrs) - pattrs = g_new0 (int, 1 + (lastp - param_index)); + pattrs = g_new0 (int, param_count); + /* at runtime we just ignore this kind of malformed file: + * the verifier can signal the error to the user + */ + if (cols [MONO_PARAM_SEQUENCE] >= param_count) + continue; pattrs [cols [MONO_PARAM_SEQUENCE]] = cols [MONO_PARAM_FLAGS]; } } @@ -1782,7 +1801,7 @@ mono_metadata_signature_alloc (MonoImage *m, guint32 nparams) { MonoMethodSignature *sig; - sig = mono_image_alloc0 (m, sizeof (MonoMethodSignature) + ((gint32)nparams - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType*)); + sig = mono_image_alloc0 (m, MONO_SIZEOF_METHOD_SIGNATURE + ((gint32)nparams) * sizeof (MonoType*)); sig->param_count = nparams; sig->sentinelpos = -1; @@ -1794,7 +1813,7 @@ mono_metadata_signature_dup_internal (MonoImage *image, MonoMemPool *mp, MonoMet { int sigsize; MonoMethodSignature *ret; - sigsize = sizeof (MonoMethodSignature) + (sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *); + sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *); if (image) { ret = mono_image_alloc (image, sigsize); @@ -1843,7 +1862,7 @@ mono_metadata_signature_dup (MonoMethodSignature *sig) guint32 mono_metadata_signature_size (MonoMethodSignature *sig) { - return sizeof (MonoMethodSignature) + (sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *); + return MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *); } /* @@ -1884,7 +1903,8 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c param_count = mono_metadata_decode_value (ptr, &ptr); if (def) - pattrs = mono_metadata_get_param_attrs (m, def); + pattrs = mono_metadata_get_param_attrs (m, def, param_count + 1); /*Must be + 1 since signature's param count doesn't account for the return value */ + method = mono_metadata_signature_alloc (m, param_count); method->hasthis = hasthis; method->explicit_this = explicit_this; @@ -1903,10 +1923,16 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c for (i = 0; i < method->param_count; ++i) { if (*ptr == MONO_TYPE_SENTINEL) { - if (method->call_convention != MONO_CALL_VARARG || def) - g_error ("found sentinel for methoddef or no vararg method"); - if (method->sentinelpos >= 0) - g_error ("found sentinel twice in the same signature"); + if (method->call_convention != MONO_CALL_VARARG || def) { + g_warning ("found sentinel for methoddef or no vararg method 0x%08x on image %s", def, m->name); + g_free (pattrs); + return NULL; + } + if (method->sentinelpos >= 0) { + g_warning ("found sentinel twice in the same signature for method 0x%08x on image %s", def, m->name); + g_free (pattrs); + return NULL; + } method->sentinelpos = i; ptr++; } @@ -2109,9 +2135,10 @@ retry: goto retry; case MONO_TYPE_FNPTR: return signature_in_image (type->data.method, image); - case MONO_TYPE_VAR: - if (type->data.generic_param->owner) { - g_assert (!type->data.generic_param->owner->is_method); + case MONO_TYPE_VAR: { + MonoGenericContainer *container = mono_type_get_generic_param_owner (type); + if (container) { + g_assert (!container->is_method); /* * FIXME: The following check is here solely * for monodis, which uses the internal @@ -2124,28 +2151,365 @@ retry: * however, so a crash results without this * check. */ - if (!type->data.generic_param->owner->owner.klass) - return FALSE; - return type->data.generic_param->owner->owner.klass->image == image; + if (!container->owner.klass) + return container->image == image; + return container->owner.klass->image == image; } else { return type->data.generic_param->image == image; } - case MONO_TYPE_MVAR: - if (type->data.generic_param->owner) { - g_assert (type->data.generic_param->owner->is_method); - if (!type->data.generic_param->owner->owner.method) + } + case MONO_TYPE_MVAR: { + MonoGenericContainer *container = mono_type_get_generic_param_owner (type); + if (type->data.generic_param->image == image) + return TRUE; + if (container) { + g_assert (container->is_method); + if (!container->owner.method) /* RefEmit created generic param whose method is not finished */ - return FALSE; - return type->data.generic_param->owner->owner.method->klass->image == image; + return container->image == image; + return container->owner.method->klass->image == image; } else { return type->data.generic_param->image == image; } + } default: /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type () */ return image == mono_class_from_mono_type (type)->image; } } +/* + * get_image_set: + * + * Return a MonoImageSet representing the set of images in IMAGES. + * + * LOCKING: Assumes the loader lock is held. + */ +static MonoImageSet* +get_image_set (MonoImage **images, int nimages) +{ + int i, j, k; + MonoImageSet *set; + GSList *l; + + if (!image_sets) + image_sets = g_ptr_array_new (); + + /* Common case */ + if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set) + return mscorlib_image_set; + + /* Happens with empty generic instances */ + if (nimages == 0) + return mscorlib_image_set; + + if (images [0] == mono_defaults.corlib && nimages > 1) + l = images [1]->image_sets; + else + l = images [0]->image_sets; + + set = NULL; + for (; l; l = l->next) { + set = l->data; + + if (set->nimages == nimages) { + for (j = 0; j < nimages; ++j) { + for (k = 0; k < nimages; ++k) + if (set->images [k] == images [j]) + break; + if (k == nimages) + /* Not found */ + break; + } + if (j == nimages) + /* Found */ + break; + } + } + + if (!l) { + /* Not found */ + set = g_new0 (MonoImageSet, 1); + set->nimages = nimages; + set->images = g_new0 (MonoImage*, nimages); + InitializeCriticalSection (&set->lock); + for (i = 0; i < nimages; ++i) + set->images [i] = images [i]; + set->gclass_cache = g_hash_table_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class); + set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst); + set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method); + set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature); + + for (i = 0; i < nimages; ++i) + set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set); + + g_ptr_array_add (image_sets, set); + } + + if (nimages == 1 && images [0] == mono_defaults.corlib) + mscorlib_image_set = set; + + return set; +} + +static void +delete_image_set (MonoImageSet *set) +{ + int i; + + g_hash_table_destroy (set->gclass_cache); + g_hash_table_destroy (set->ginst_cache); + g_hash_table_destroy (set->gmethod_cache); + g_hash_table_destroy (set->gsignature_cache); + + for (i = 0; i < set->nimages; ++i) + set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set); + + g_ptr_array_remove (image_sets, set); + + if (set->mempool) + mono_mempool_destroy (set->mempool); + g_free (set->images); + DeleteCriticalSection (&set->lock); + g_free (set); +} + +static void +mono_image_set_lock (MonoImageSet *set) +{ + EnterCriticalSection (&set->lock); +} + +static void +mono_image_set_unlock (MonoImageSet *set) +{ + LeaveCriticalSection (&set->lock); +} + +gpointer +mono_image_set_alloc (MonoImageSet *set, guint size) +{ + gpointer res; + + mono_image_set_lock (set); + if (!set->mempool) + set->mempool = mono_mempool_new_size (1024); + res = mono_mempool_alloc (set->mempool, size); + mono_image_set_unlock (set); + + return res; +} + +gpointer +mono_image_set_alloc0 (MonoImageSet *set, guint size) +{ + gpointer res; + + mono_image_set_lock (set); + if (!set->mempool) + set->mempool = mono_mempool_new_size (1024); + res = mono_mempool_alloc0 (set->mempool, size); + mono_image_set_unlock (set); + + return res; +} + +char* +mono_image_set_strdup (MonoImageSet *set, const char *s) +{ + char *res; + + mono_image_set_lock (set); + if (!set->mempool) + set->mempool = mono_mempool_new_size (1024); + res = mono_mempool_strdup (set->mempool, s); + mono_image_set_unlock (set); + + return res; +} + +/* + * Structure used by the collect_..._images functions to store the image list. + */ +typedef struct { + MonoImage *image_buf [64]; + MonoImage **images; + int nimages, images_len; +} CollectData; + +static void +collect_data_init (CollectData *data) +{ + data->images = data->image_buf; + data->images_len = 64; + data->nimages = 0; +} + +static void +collect_data_free (CollectData *data) +{ + if (data->images != data->image_buf) + g_free (data->images); +} + +static void +enlarge_data (CollectData *data) +{ + int new_len = data->images_len < 16 ? 16 : data->images_len * 2; + MonoImage **d = g_new (MonoImage *, new_len); + + // FIXME: test this + g_assert_not_reached (); + memcpy (d, data->images, data->images_len); + if (data->images != data->image_buf) + g_free (data->images); + data->images = d; + data->images_len = new_len; +} + +static inline void +add_image (MonoImage *image, CollectData *data) +{ + int i; + + /* The arrays are small, so use a linear search instead of a hash table */ + for (i = 0; i < data->nimages; ++i) + if (data->images [i] == image) + return; + + if (data->nimages == data->images_len) + enlarge_data (data); + + data->images [data->nimages ++] = image; +} + +static void +collect_type_images (MonoType *type, CollectData *data); + +static void +collect_ginst_images (MonoGenericInst *ginst, CollectData *data) +{ + int i; + + for (i = 0; i < ginst->type_argc; ++i) { + collect_type_images (ginst->type_argv [i], data); + } +} + +static void +collect_gclass_images (MonoGenericClass *gclass, CollectData *data) +{ + add_image (gclass->container_class->image, data); + if (gclass->context.class_inst) + collect_ginst_images (gclass->context.class_inst, data); +} + +static void +collect_signature_images (MonoMethodSignature *sig, CollectData *data) +{ + gpointer iter = NULL; + MonoType *p; + + collect_type_images (mono_signature_get_return_type (sig), data); + while ((p = mono_signature_get_params (sig, &iter)) != NULL) + collect_type_images (p, data); +} + +static void +collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData *data) +{ + collect_signature_images (sig->sig, data); + if (sig->context.class_inst) + collect_ginst_images (sig->context.class_inst, data); + if (sig->context.method_inst) + collect_ginst_images (sig->context.method_inst, data); +} + +static void +collect_method_images (MonoMethodInflated *method, CollectData *data) +{ + add_image (method->declaring->klass->image, data); + if (method->context.class_inst) + collect_ginst_images (method->context.class_inst, data); + if (method->context.method_inst) + collect_ginst_images (method->context.method_inst, data); + /* + if (((MonoMethod*)method)->signature) + collect_signature_images (mono_method_signature ((MonoMethod*)method), data); + */ +} + +static void +collect_type_images (MonoType *type, CollectData *data) +{ +retry: + switch (type->type) { + case MONO_TYPE_GENERICINST: + collect_gclass_images (type->data.generic_class, data); + break; + case MONO_TYPE_PTR: + type = type->data.type; + goto retry; + case MONO_TYPE_SZARRAY: + type = &type->data.klass->byval_arg; + goto retry; + case MONO_TYPE_ARRAY: + type = &type->data.array->eklass->byval_arg; + goto retry; + case MONO_TYPE_FNPTR: + //return signature_in_image (type->data.method, image); + g_assert_not_reached (); + case MONO_TYPE_VAR: { + MonoGenericContainer *container = mono_type_get_generic_param_owner (type); + if (container) { + g_assert (!container->is_method); + /* + * FIXME: The following check is here solely + * for monodis, which uses the internal + * function + * mono_metadata_load_generic_params(). The + * caller of that function needs to fill in + * owner->klass or owner->method of the + * returned struct, but monodis doesn't do + * that. The image unloading depends on that, + * however, so a crash results without this + * check. + */ + if (!container->owner.klass) + add_image (container->image, data); + else + add_image (container->owner.klass->image, data); + } else { + add_image (type->data.generic_param->image, data); + } + } + break; + case MONO_TYPE_MVAR: { + MonoGenericContainer *container = mono_type_get_generic_param_owner (type); + if (type->data.generic_param->image) + add_image (type->data.generic_param->image, data); + if (container) { + if (!container->owner.method) { + /* RefEmit created generic param whose method is not finished */ + add_image (container->image, data); + } else { + g_assert (container->is_method); + add_image (container->owner.method->klass->image, data); + } + } else { + add_image (type->data.generic_param->image, data); + } + } + break; + case MONO_TYPE_CLASS: + case MONO_TYPE_VALUETYPE: + add_image (mono_class_from_mono_type (type)->image, data); + break; + default: + add_image (mono_defaults.corlib, data); + } +} + typedef struct { MonoImage *image; GSList *list; @@ -2157,8 +2521,7 @@ steal_gclass_in_image (gpointer key, gpointer value, gpointer data) MonoGenericClass *gclass = key; CleanForImageUserData *user_data = data; - if (!gclass_in_image (gclass, user_data->image)) - return FALSE; + g_assert (gclass_in_image (gclass, user_data->image)); user_data->list = g_slist_prepend (user_data->list, gclass); return TRUE; @@ -2170,8 +2533,8 @@ steal_ginst_in_image (gpointer key, gpointer value, gpointer data) MonoGenericInst *ginst = key; CleanForImageUserData *user_data = data; - if (!ginst_in_image (ginst, user_data->image)) - return FALSE; + // This doesn't work during corlib compilation + //g_assert (ginst_in_image (ginst, user_data->image)); user_data->list = g_slist_prepend (user_data->list, ginst); return TRUE; @@ -2185,9 +2548,11 @@ inflated_method_in_image (gpointer key, gpointer value, gpointer data) // FIXME: // https://bugzilla.novell.com/show_bug.cgi?id=458168 - return method->declaring->klass->image == image || + g_assert (method->declaring->klass->image == image || (method->context.class_inst && ginst_in_image (method->context.class_inst, image)) || - (method->context.method_inst && ginst_in_image (method->context.method_inst, image)) || (((MonoMethod*)method)->signature && signature_in_image (mono_method_signature ((MonoMethod*)method), image)); + (method->context.method_inst && ginst_in_image (method->context.method_inst, image)) || (((MonoMethod*)method)->signature && signature_in_image (mono_method_signature ((MonoMethod*)method), image))); + + return TRUE; } static gboolean @@ -2201,24 +2566,70 @@ inflated_signature_in_image (gpointer key, gpointer value, gpointer data) (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image)); } -void +static void +check_gmethod (gpointer key, gpointer value, gpointer data) +{ + MonoMethodInflated *method = key; + MonoImage *image = data; + + if (method->context.class_inst) + g_assert (!ginst_in_image (method->context.class_inst, image)); + if (method->context.method_inst) + g_assert (!ginst_in_image (method->context.method_inst, image)); + if (((MonoMethod*)method)->signature) + g_assert (!signature_in_image (mono_method_signature ((MonoMethod*)method), image)); +} + +/* + * check_image_sets: + * + * Run a consistency check on the image set data structures. + */ +static G_GNUC_UNUSED void +check_image_sets (MonoImage *image) +{ + int i; + GSList *l = image->image_sets; + + if (!image_sets) + return; + + for (i = 0; i < image_sets->len; ++i) { + MonoImageSet *set = g_ptr_array_index (image_sets, i); + + if (!g_slist_find (l, set)) { + g_hash_table_foreach (set->gmethod_cache, check_gmethod, image); + } + } +} + +GSList* mono_metadata_clean_for_image (MonoImage *image) { CleanForImageUserData ginst_data, gclass_data; - GSList *l; + GSList *l, *set_list, *free_list = NULL; - /* The data structures could reference each other so we delete them in two phases */ + //check_image_sets (image); + + /* + * The data structures could reference each other so we delete them in two phases. + * This is required because of the hashing functions in gclass/ginst_cache. + */ ginst_data.image = gclass_data.image = image; ginst_data.list = gclass_data.list = NULL; + mono_loader_lock (); + + /* Collect the items to delete */ + /* delete_image_set () modifies the lists so make a copy */ + for (l = image->image_sets; l; l = l->next) { + MonoImageSet *set = l->data; + + g_hash_table_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data); + g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data); + g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image); + g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image); + } - mono_loader_lock (); - /* Collect the items to delete and remove them from the hash table */ - g_hash_table_foreach_steal (generic_inst_cache, steal_ginst_in_image, &ginst_data); - g_hash_table_foreach_steal (generic_class_cache, steal_gclass_in_image, &gclass_data); - if (generic_method_cache) - g_hash_table_foreach_remove (generic_method_cache, inflated_method_in_image, image); - if (generic_signature_cache) - g_hash_table_foreach_remove (generic_signature_cache, inflated_signature_in_image, image); /* Delete the removed items */ for (l = ginst_data.list; l; l = l->next) free_generic_inst (l->data); @@ -2226,8 +2637,18 @@ mono_metadata_clean_for_image (MonoImage *image) free_generic_class (l->data); g_slist_free (ginst_data.list); g_slist_free (gclass_data.list); - mono_class_unregister_image_generic_subclasses (image); + /* delete_image_set () modifies the lists so make a copy */ + set_list = g_slist_copy (image->image_sets); + for (l = set_list; l; l = l->next) { + MonoImageSet *set = l->data; + + delete_image_set (set); + } + g_slist_free (set_list); + mono_loader_unlock (); + + return free_list; } static void @@ -2236,12 +2657,13 @@ free_inflated_method (MonoMethodInflated *imethod) int i; MonoMethod *method = (MonoMethod*)imethod; + mono_marshal_free_inflated_wrappers (method); + if (method->signature) mono_metadata_free_inflated_signature (method->signature); if (!((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))) { - MonoMethodNormal* mn = (MonoMethodNormal*) method; - MonoMethodHeader *header = mn->header; + MonoMethodHeader *header = imethod->header; if (header) { /* Allocated in inflate_generic_header () */ @@ -2260,56 +2682,19 @@ free_generic_inst (MonoGenericInst *ginst) { int i; + /* The ginst itself is allocated from the image set mempool */ for (i = 0; i < ginst->type_argc; ++i) mono_metadata_free_type (ginst->type_argv [i]); - g_free (ginst); } - static void free_generic_class (MonoGenericClass *gclass) { - int i; - - /* FIXME: The dynamic case */ - if (gclass->cached_class && !gclass->cached_class->image->dynamic && !mono_generic_class_is_generic_type_definition (gclass)) { - MonoClass *class = gclass->cached_class; - - /* Allocated in mono_class_init () */ - g_free (class->methods); - if (class->ext) - g_free (class->ext->properties); - /* Allocated in mono_generic_class_get_class () */ - g_free (class->interfaces); - g_free (class); - } else if (gclass->is_dynamic) { - MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass *)gclass; - - for (i = 0; i < dgclass->count_fields; ++i) { - MonoClassField *field = dgclass->fields + i; - mono_metadata_free_type (field->type); - g_free ((char*)field->name); - } - for (i = 0; i < dgclass->count_properties; ++i) { - MonoProperty *property = dgclass->properties + i; - g_free ((char*)property->name); - } - for (i = 0; i < dgclass->count_events; ++i) { - MonoEvent *event = dgclass->events + i; - g_free ((char*)event->name); - } - - g_free (dgclass->methods); - g_free (dgclass->ctors); - g_free (dgclass->fields); - g_free (dgclass->properties); - g_free (dgclass->events); - g_free (dgclass->field_objects); - g_free (dgclass->field_generic_types); - if (!mono_generic_class_is_generic_type_definition (gclass)) - g_free (gclass->cached_class); - } - g_free (gclass); + /* The gclass itself is allocated from the image set mempool */ + if (gclass->is_dynamic) + mono_reflection_free_dynamic_generic_class (gclass); + if (gclass->cached_class && gclass->cached_class->interface_id) + mono_unload_interface_id (gclass->cached_class); } static void @@ -2325,15 +2710,23 @@ free_inflated_signature (MonoInflatedMethodSignature *sig) MonoMethodInflated* mono_method_inflated_lookup (MonoMethodInflated* method, gboolean cache) { + CollectData data; + MonoImageSet *set; + + collect_data_init (&data); + + collect_method_images (method, &data); + + set = get_image_set (data.images, data.nimages); + + collect_data_free (&data); + if (cache) { - if (!generic_method_cache) - generic_method_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method); - g_hash_table_insert (generic_method_cache, method, method); + g_hash_table_insert (set->gmethod_cache, method, method); + return method; } else { - if (generic_method_cache) - return g_hash_table_lookup (generic_method_cache, method); - return NULL; + return g_hash_table_lookup (set->gmethod_cache, method); } } @@ -2348,21 +2741,30 @@ mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericConte { MonoInflatedMethodSignature helper; MonoInflatedMethodSignature *res; + CollectData data; + MonoImageSet *set; mono_loader_lock (); - if (!generic_signature_cache) - generic_signature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature); helper.sig = sig; helper.context.class_inst = context->class_inst; helper.context.method_inst = context->method_inst; - res = g_hash_table_lookup (generic_signature_cache, &helper); + + collect_data_init (&data); + + collect_inflated_signature_images (&helper, &data); + + set = get_image_set (data.images, data.nimages); + + collect_data_free (&data); + + res = g_hash_table_lookup (set->gsignature_cache, &helper); if (!res) { res = g_new0 (MonoInflatedMethodSignature, 1); res->sig = sig; res->context.class_inst = context->class_inst; res->context.method_inst = context->method_inst; - g_hash_table_insert (generic_signature_cache, res, res); + g_hash_table_insert (set->gsignature_cache, res, res); } mono_loader_unlock (); @@ -2383,32 +2785,44 @@ mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv) MonoGenericInst *ginst; gboolean is_open; int i; - int size = sizeof (MonoGenericInst) + (type_argc - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *); + int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *); + CollectData data; + MonoImageSet *set; for (i = 0; i < type_argc; ++i) if (mono_class_is_open_constructed_type (type_argv [i])) break; is_open = (i < type_argc); - ginst = alloca (size); - ginst->id = 0; + ginst = g_alloca (size); + memset (ginst, 0, sizeof (MonoGenericInst)); ginst->is_open = is_open; ginst->type_argc = type_argc; memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *)); mono_loader_lock (); - ginst = g_hash_table_lookup (generic_inst_cache, ginst); + collect_data_init (&data); + + collect_ginst_images (ginst, &data); + + set = get_image_set (data.images, data.nimages); + + collect_data_free (&data); + + ginst = g_hash_table_lookup (set->ginst_cache, ginst); if (!ginst) { - ginst = g_malloc (size); + ginst = mono_image_set_alloc0 (set, size); +#ifndef MONO_SMALL_CONFIG ginst->id = ++next_generic_inst_id; +#endif ginst->is_open = is_open; ginst->type_argc = type_argc; for (i = 0; i < type_argc; ++i) ginst->type_argv [i] = mono_metadata_type_dup (NULL, type_argv [i]); - g_hash_table_insert (generic_inst_cache, ginst, ginst); + g_hash_table_insert (set->ginst_cache, ginst, ginst); } mono_loader_unlock (); @@ -2437,6 +2851,8 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst MonoGenericClass *gclass; MonoGenericClass helper; gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic); + MonoImageSet *set; + CollectData data; helper.container_class = container_class; helper.context.class_inst = inst; @@ -2447,7 +2863,15 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst mono_loader_lock (); - gclass = g_hash_table_lookup (generic_class_cache, &helper); + collect_data_init (&data); + + collect_gclass_images (&helper, &data); + + set = get_image_set (data.images, data.nimages); + + collect_data_free (&data); + + gclass = g_hash_table_lookup (set->gclass_cache, &helper); /* A tripwire just to keep us honest */ g_assert (!helper.cached_class); @@ -2458,21 +2882,22 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst } if (is_dynamic) { - MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1); + MonoDynamicGenericClass *dgclass = mono_image_set_new0 (set, MonoDynamicGenericClass, 1); gclass = &dgclass->generic_class; gclass->is_dynamic = 1; } else { - gclass = g_new0 (MonoGenericClass, 1); + gclass = mono_image_set_new0 (set, MonoGenericClass, 1); } gclass->is_tb_open = is_tb_open; gclass->container_class = container_class; gclass->context.class_inst = inst; gclass->context.method_inst = NULL; + gclass->owner = set; if (inst == container_class->generic_container->context.class_inst && !is_tb_open) gclass->cached_class = container_class; - g_hash_table_insert (generic_class_cache, gclass, gclass); + g_hash_table_insert (set->gclass_cache, gclass, gclass); mono_loader_unlock (); @@ -2483,26 +2908,34 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst * mono_metadata_inflate_generic_inst: * * Instantiate the generic instance @ginst with the context @context. + * Check @error for success. * */ MonoGenericInst * -mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context) +mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context, MonoError *error) { MonoType **type_argv; - MonoGenericInst *nginst; - int i; + MonoGenericInst *nginst = NULL; + int i, count = 0; + + mono_error_init (error); if (!ginst->is_open) return ginst; type_argv = g_new0 (MonoType*, ginst->type_argc); - for (i = 0; i < ginst->type_argc; i++) - type_argv [i] = mono_class_inflate_generic_type (ginst->type_argv [i], context); + for (i = 0; i < ginst->type_argc; i++) { + type_argv [i] = mono_class_inflate_generic_type_checked (ginst->type_argv [i], context, error); + if (!mono_error_ok (error)) + goto cleanup; + ++count; + } nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv); - for (i = 0; i < ginst->type_argc; i++) +cleanup: + for (i = 0; i < count; i++) mono_metadata_free_type (type_argv [i]); g_free (type_argv); @@ -2596,7 +3029,7 @@ select_container (MonoGenericContainer *gc, MonoTypeEnum type) /* * mono_metadata_parse_generic_param: - * @generic_container: Our MonoClass's or MonoMethodNormal's MonoGenericContainer; + * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer; * see mono_metadata_parse_type_full() for details. * Internal routine to parse a generic type parameter. * LOCKING: Acquires the loader lock @@ -2615,16 +3048,16 @@ mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_c MonoGenericParam *param; param = mono_image_alloc0 (m, sizeof (MonoGenericParam)); - param->name = mono_image_alloc0 (m, 8); - sprintf ((char*)param->name, "%d", index); param->num = index; param->image = m; return param; } - g_assert (index < generic_container->type_argc); - return &generic_container->type_params [index]; + if (index >= generic_container->type_argc) + return NULL; + + return mono_generic_container_get_param (generic_container, index); } /* @@ -2659,11 +3092,29 @@ mono_metadata_get_shared_type (MonoType *type) return NULL; } +static gboolean +compare_type_literals (int class_type, int type_type) +{ + /* byval_arg.type can be zero if we're decoding a type that references a class been loading. + * See mcs/test/gtest-440. and #650936. + * FIXME This better be moved to the metadata verifier as it can catch more cases. + */ + if (!class_type) + return TRUE; + /* NET 1.1 assemblies might encode string and object in a denormalized way. + * See #675464. + */ + if (type_type == MONO_TYPE_CLASS && (class_type == MONO_TYPE_STRING || class_type == MONO_TYPE_OBJECT)) + return TRUE; + return class_type == type_type; +} + /* * do_mono_metadata_parse_type: * @type: MonoType to be filled in with the return value * @m: image context * @generic_context: generics_context + * @transient: whenever to allocate data from the heap * @ptr: pointer to the encoded type * @rptr: pointer where the end of the encoded type is saved * @@ -2681,7 +3132,7 @@ mono_metadata_get_shared_type (MonoType *type) */ static gboolean do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container, - const char *ptr, const char **rptr) + gboolean transient, const char *ptr, const char **rptr) { gboolean ok = TRUE; type->type = mono_metadata_decode_value (ptr, &ptr); @@ -2709,9 +3160,13 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer case MONO_TYPE_VALUETYPE: case MONO_TYPE_CLASS: { guint32 token; + MonoClass *class; token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr); - type->data.klass = mono_class_get (m, token); - if (!type->data.klass) + class = mono_class_get (m, token); + type->data.klass = class; + if (!class) + return FALSE; + if (!compare_type_literals (class->byval_arg.type, type->type)) return FALSE; break; } @@ -2720,28 +3175,39 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer if (!etype) return FALSE; type->data.klass = mono_class_from_mono_type (etype); + if (!type->data.klass) + return FALSE; break; } case MONO_TYPE_PTR: - type->data.type = mono_metadata_parse_type_full (m, container, MONO_PARSE_MOD_TYPE, 0, ptr, &ptr); + type->data.type = mono_metadata_parse_type_internal (m, container, MONO_PARSE_MOD_TYPE, 0, transient, ptr, &ptr); if (!type->data.type) return FALSE; break; case MONO_TYPE_FNPTR: type->data.method = mono_metadata_parse_method_signature_full (m, container, 0, ptr, &ptr); + if (!type->data.method) + return FALSE; break; case MONO_TYPE_ARRAY: - type->data.array = mono_metadata_parse_array_full (m, container, ptr, &ptr); + type->data.array = mono_metadata_parse_array_internal (m, container, transient, ptr, &ptr); + if (!type->data.array) + return FALSE; break; case MONO_TYPE_MVAR: + if (container && !container->is_method) + return FALSE; case MONO_TYPE_VAR: type->data.generic_param = mono_metadata_parse_generic_param (m, container, type->type, ptr, &ptr); + if (!type->data.generic_param) + return FALSE; break; case MONO_TYPE_GENERICINST: ok = do_mono_metadata_parse_generic_class (type, m, container, ptr, &ptr); break; default: - g_error ("type 0x%02x not handled in do_mono_metadata_parse_type", type->type); + g_warning ("type 0x%02x not handled in do_mono_metadata_parse_type on image %s", type->type, m->name); + return FALSE; } if (rptr) @@ -2810,16 +3276,16 @@ hex_dump (const char *buffer, int base, int count) #endif /** - * @mh: The Method header * @ptr: Points to the beginning of the Section Data (25.3) */ -static void -parse_section_data (MonoImage *m, MonoMethodHeader *mh, const unsigned char *ptr) +static MonoExceptionClause* +parse_section_data (MonoImage *m, int *num_clauses, const unsigned char *ptr) { unsigned char sect_data_flags; const unsigned char *sptr; int is_fat; guint32 sect_data_len; + MonoExceptionClause* clauses = NULL; while (1) { /* align on 32-bit boundary */ @@ -2846,11 +3312,11 @@ parse_section_data (MonoImage *m, MonoMethodHeader *mh, const unsigned char *ptr if (sect_data_flags & METHOD_HEADER_SECTION_EHTABLE) { const unsigned char *p = dword_align (ptr); int i; - mh->num_clauses = is_fat ? sect_data_len / 24: sect_data_len / 12; + *num_clauses = is_fat ? sect_data_len / 24: sect_data_len / 12; /* we could just store a pointer if we don't need to byteswap */ - mh->clauses = mono_image_alloc0 (m, sizeof (MonoExceptionClause) * mh->num_clauses); - for (i = 0; i < mh->num_clauses; ++i) { - MonoExceptionClause *ec = &mh->clauses [i]; + clauses = g_malloc0 (sizeof (MonoExceptionClause) * (*num_clauses)); + for (i = 0; i < *num_clauses; ++i) { + MonoExceptionClause *ec = &clauses [i]; guint32 tof_value; if (is_fat) { ec->flags = read32 (p); @@ -2883,8 +3349,79 @@ parse_section_data (MonoImage *m, MonoMethodHeader *mh, const unsigned char *ptr if (sect_data_flags & METHOD_HEADER_SECTION_MORE_SECTS) ptr += sect_data_len - 4; /* LAMESPEC: it seems the size includes the header */ else - return; + return clauses; + } +} + +/* + * mono_method_get_header_summary: + * @method: The method to get the header. + * @summary: Where to store the header + * + * + * Returns: true if the header was properly decoded. + */ +gboolean +mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *summary) +{ + int idx; + guint32 rva; + MonoImage* img; + const char *ptr; + unsigned char flags, format; + guint16 fat_flags; + + /*Only the GMD has a pointer to the metadata.*/ + while (method->is_inflated) + method = ((MonoMethodInflated*)method)->declaring; + + summary->code_size = 0; + summary->has_clauses = FALSE; + + /*FIXME extract this into a MACRO and share it with mono_method_get_header*/ + if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) + return FALSE; + + if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) { + MonoMethodHeader *header = ((MonoMethodWrapper *)method)->header; + if (!header) + return FALSE; + summary->code_size = header->code_size; + summary->has_clauses = header->num_clauses > 0; + return TRUE; + } + + + idx = mono_metadata_token_index (method->token); + img = method->klass->image; + rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA); + + /*We must run the verifier since we'll be decoding it.*/ + if (!mono_verifier_verify_method_header (img, rva, NULL)) + return FALSE; + + ptr = mono_image_rva_map (img, rva); + g_assert (ptr); + + flags = *(const unsigned char *)ptr; + format = flags & METHOD_HEADER_FORMAT_MASK; + + switch (format) { + case METHOD_HEADER_TINY_FORMAT: + ptr++; + summary->code_size = flags >> 2; + break; + case METHOD_HEADER_FAT_FORMAT: + fat_flags = read16 (ptr); + ptr += 4; + summary->code_size = read32 (ptr); + if (fat_flags & METHOD_HEADER_MORE_SECTS) + summary->has_clauses = TRUE; + break; + default: + return FALSE; } + return TRUE; } /* @@ -2899,7 +3436,7 @@ parse_section_data (MonoImage *m, MonoMethodHeader *mh, const unsigned char *ptr * * LOCKING: Acquires the loader lock. * - * Returns: a MonoMethodHeader allocated from the image mempool. + * Returns: a transient MonoMethodHeader allocated from the heap. */ MonoMethodHeader * mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr) @@ -2910,29 +3447,20 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons guint16 fat_flags; guint32 local_var_sig_tok, max_stack, code_size, init_locals; const unsigned char *code; - int hsize; - + MonoExceptionClause* clauses = NULL; + int hsize, num_clauses = 0; + MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG]; + guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE]; + g_return_val_if_fail (ptr != NULL, NULL); switch (format) { case METHOD_HEADER_TINY_FORMAT: - mh = mono_image_alloc0 (m, sizeof (MonoMethodHeader)); - ptr++; - mh->max_stack = 8; - local_var_sig_tok = 0; - mh->code_size = flags >> 2; - mh->code = (unsigned char*)ptr; - return mh; - case METHOD_HEADER_TINY_FORMAT1: - mh = mono_image_alloc0 (m, sizeof (MonoMethodHeader)); + mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER); ptr++; mh->max_stack = 8; + mh->is_transient = TRUE; local_var_sig_tok = 0; - - /* - * The spec claims 3 bits, but the Beta2 is - * incorrect - */ mh->code_size = flags >> 2; mh->code = (unsigned char*)ptr; return mh; @@ -2965,38 +3493,54 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons default: return NULL; } - + + if (local_var_sig_tok) { + int idx = (local_var_sig_tok & 0xffffff)-1; + if (idx >= t->rows || idx < 0) + return NULL; + mono_metadata_decode_row (t, idx, cols, 1); + + if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], NULL)) + return NULL; + } + if (fat_flags & METHOD_HEADER_MORE_SECTS) + clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr); if (local_var_sig_tok) { - MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG]; const char *locals_ptr; - guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE]; int len=0, i, bsize; - mono_metadata_decode_row (t, (local_var_sig_tok & 0xffffff)-1, cols, 1); locals_ptr = mono_metadata_blob_heap (m, cols [MONO_STAND_ALONE_SIGNATURE]); bsize = mono_metadata_decode_blob_size (locals_ptr, &locals_ptr); if (*locals_ptr != 0x07) g_warning ("wrong signature for locals blob"); locals_ptr++; len = mono_metadata_decode_value (locals_ptr, &locals_ptr); - mh = mono_image_alloc0 (m, sizeof (MonoMethodHeader) + (len - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType*)); + mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER + len * sizeof (MonoType*) + num_clauses * sizeof (MonoExceptionClause)); mh->num_locals = len; for (i = 0; i < len; ++i) { - mh->locals [i] = mono_metadata_parse_type_full ( - m, container, MONO_PARSE_LOCAL, 0, locals_ptr, &locals_ptr); + mh->locals [i] = mono_metadata_parse_type_internal (m, container, + MONO_PARSE_LOCAL, 0, TRUE, locals_ptr, &locals_ptr); if (!mh->locals [i]) { + g_free (clauses); + g_free (mh); return NULL; } } } else { - mh = mono_image_alloc0 (m, sizeof (MonoMethodHeader)); + mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause)); } mh->code = code; mh->code_size = code_size; mh->max_stack = max_stack; + mh->is_transient = TRUE; mh->init_locals = init_locals; - if (fat_flags & METHOD_HEADER_MORE_SECTS) - parse_section_data (m, mh, (const unsigned char*)ptr); + if (clauses) { + MonoExceptionClause* clausesp = (MonoExceptionClause*)&mh->locals [mh->num_locals]; + memcpy (clausesp, clauses, num_clauses * sizeof (MonoExceptionClause)); + g_free (clauses); + mh->clauses = clausesp; + mh->num_clauses = num_clauses; + } return mh; } @@ -3030,12 +3574,21 @@ mono_metadata_parse_mh (MonoImage *m, const char *ptr) * @mh: a method header * * Free the memory allocated for the method header. - * This is a Mono runtime internal function. */ void mono_metadata_free_mh (MonoMethodHeader *mh) { - /* Allocated from the mempool */ + int i; + + /* If it is not transient it means it's part of a wrapper method, + * or a SRE-generated method, so the lifetime in that case is + * dictated by the method's own lifetime + */ + if (mh->is_transient) { + for (i = 0; i < mh->num_locals; ++i) + mono_metadata_free_type (mh->locals [i]); + g_free (mh); + } } /* @@ -3360,7 +3913,7 @@ mono_metadata_typedef_from_field (MonoImage *meta, guint32 index) loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx); if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator)) - g_assert_not_reached (); + return 0; /* loc_result is 0..1, needs to be mapped to table index (that is +1) */ return loc.result + 1; @@ -3391,7 +3944,7 @@ mono_metadata_typedef_from_method (MonoImage *meta, guint32 index) loc.idx = search_ptr_table (meta, MONO_TABLE_METHOD_POINTER, loc.idx); if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, typedef_locator)) - g_assert_not_reached (); + return 0; /* loc_result is 0..1, needs to be mapped to table index (that is +1) */ return loc.result + 1; @@ -3401,16 +3954,20 @@ mono_metadata_typedef_from_method (MonoImage *meta, guint32 index) * mono_metadata_interfaces_from_typedef_full: * @meta: metadata context * @index: typedef token + * @interfaces: Out parameter used to store the interface array + * @count: Out parameter used to store the number of interfaces + * @heap_alloc_result: if TRUE the result array will be g_malloc'd + * @context: The generic context * * The array of interfaces that the @index typedef token implements is returned in - * @interfaces. The number of elemnts in the array is returned in @count. + * @interfaces. The number of elements in the array is returned in @count. * * LOCKING: Assumes the loader lock is held. * * Returns: TRUE on success, FALSE on failure. */ gboolean -mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, MonoClass ***interfaces, guint *count, MonoGenericContext *context) +mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, MonoClass ***interfaces, guint *count, gboolean heap_alloc_result, MonoGenericContext *context) { MonoTableInfo *tdef = &meta->tables [MONO_TABLE_INTERFACEIMPL]; locator_t loc; @@ -3449,7 +4006,10 @@ mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, Mono ++pos; } - result = mono_image_alloc0 (meta, sizeof (MonoClass*) * (pos - start)); + if (heap_alloc_result) + result = g_new0 (MonoClass*, pos - start); + else + result = mono_image_alloc0 (meta, sizeof (MonoClass*) * (pos - start)); pos = start; while (pos < tdef->rows) { @@ -3470,6 +4030,20 @@ mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, Mono return TRUE; } +/* + * @meta: metadata context + * @index: typedef token + * @count: Out parameter used to store the number of interfaces + * + * The array of interfaces that the @index typedef token implements is returned in + * @interfaces. The number of elements in the array is returned in @count. The returned + * array is g_malloc'd and the caller must free it. + * + * LOCKING: Acquires the loader lock . + * + * Returns: the interface array on success, NULL on failure. + */ + MonoClass** mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *count) { @@ -3477,7 +4051,7 @@ mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *co gboolean rv; mono_loader_lock (); - rv = mono_metadata_interfaces_from_typedef_full (meta, index, &interfaces, count, NULL); + rv = mono_metadata_interfaces_from_typedef_full (meta, index, &interfaces, count, TRUE, NULL); mono_loader_unlock (); if (rv) return interfaces; @@ -3954,11 +4528,34 @@ mono_metadata_generic_context_equal (const MonoGenericContext *g1, const MonoGen return g1->class_inst == g2->class_inst && g1->method_inst == g2->method_inst; } +/* + * mono_metadata_str_hash: + * + * This should be used instead of g_str_hash for computing hash codes visible + * outside this module, since g_str_hash () is not guaranteed to be stable + * (its not the same in eglib for example). + */ +guint +mono_metadata_str_hash (gconstpointer v1) +{ + /* Same as g_str_hash () in glib */ + char *p = (char *) v1; + guint hash = *p; + + while (*p++) { + if (*p) + hash = (hash << 5) - hash + *p; + } + + return hash; +} + /* * mono_metadata_type_hash: * @t1: a type * * Computes an hash value for @t1 to be used in GHashTable. + * The returned hash is guaranteed to be the same across executions. */ guint mono_metadata_type_hash (MonoType *t1) @@ -3969,9 +4566,20 @@ mono_metadata_type_hash (MonoType *t1) switch (t1->type) { case MONO_TYPE_VALUETYPE: case MONO_TYPE_CLASS: - case MONO_TYPE_SZARRAY: - /* check if the distribution is good enough */ - return ((hash << 5) - hash) ^ g_str_hash (t1->data.klass->name); + case MONO_TYPE_SZARRAY: { + MonoClass *class = t1->data.klass; + /* + * Dynamic classes must not be hashed on their type since it can change + * during runtime. For example, if we hash a reference type that is + * later made into a valuetype. + * + * This is specially problematic with generic instances since they are + * inserted in a bunch of hash tables before been finished. + */ + if (class->image->dynamic) + return (t1->byref << 6) | mono_metadata_str_hash (class->name); + return ((hash << 5) - hash) ^ mono_metadata_str_hash (class->name); + } case MONO_TYPE_PTR: return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type); case MONO_TYPE_ARRAY: @@ -3987,7 +4595,7 @@ mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2, g { if (p1 == p2) return TRUE; - if (p1->num != p2->num) + if (mono_generic_param_num (p1) != mono_generic_param_num (p2)) return FALSE; /* @@ -4002,7 +4610,8 @@ mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2, g * The AOT runtime doesn't set the image when it's decoding * types, so we only compare it when the owner is NULL. */ - if (p1->owner == p2->owner && (p1->owner || p1->image == p2->image)) + if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2) && + (mono_generic_param_owner (p1) || p1->image == p2->image)) return TRUE; /* @@ -4209,9 +4818,9 @@ MonoType * mono_metadata_type_dup (MonoImage *image, const MonoType *o) { MonoType *r = NULL; - int sizeof_o = sizeof (MonoType); + int sizeof_o = MONO_SIZEOF_TYPE; if (o->num_mods) - sizeof_o += (o->num_mods - MONO_ZERO_LEN_ARRAY) * sizeof (MonoCustomMod); + sizeof_o += o->num_mods * sizeof (MonoCustomMod); r = image ? mono_image_alloc0 (image, sizeof_o) : g_malloc (sizeof_o); @@ -4629,16 +5238,16 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec) mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE); ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]); - len = mono_metadata_decode_value (ptr, &ptr); - - type = mono_image_alloc0 (image, sizeof (MonoType)); - if (*ptr == MONO_TYPE_BYREF) { - type->byref = 1; - ptr++; + if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, NULL)) { + mono_loader_unlock (); + return NULL; } - if (!do_mono_metadata_parse_type (type, image, NULL, ptr, &ptr)) { + len = mono_metadata_decode_value (ptr, &ptr); + + type = mono_metadata_parse_type_internal (image, NULL, MONO_PARSE_TYPE, 0, TRUE, ptr, &ptr); + if (!type) { mono_loader_unlock (); return NULL; } @@ -4650,11 +5259,13 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec) return type2; } - g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type); + type2 = mono_metadata_type_dup (image, type); + g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2); + mono_metadata_free_type (type); mono_loader_unlock (); - return type; + return type2; } @@ -4810,7 +5421,17 @@ handle_enum: } *conv = MONO_MARSHAL_CONV_BOOL_I4; return MONO_NATIVE_BOOLEAN; - case MONO_TYPE_CHAR: return MONO_NATIVE_U2; + case MONO_TYPE_CHAR: + if (mspec) { + switch (mspec->native) { + case MONO_NATIVE_U2: + case MONO_NATIVE_U1: + return mspec->native; + default: + g_error ("cant marshal char to native type %02x", mspec->native); + } + } + return unicode ? MONO_NATIVE_U2 : MONO_NATIVE_U1; case MONO_TYPE_I1: return MONO_NATIVE_I1; case MONO_TYPE_U1: return MONO_NATIVE_U1; case MONO_TYPE_I2: return MONO_NATIVE_I2; @@ -4972,7 +5593,7 @@ mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field) return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE)); } -static MonoMethod* +MonoMethod* method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context) { guint32 idx = tok >> MONO_METHODDEFORREF_BITS; @@ -4999,6 +5620,7 @@ gboolean mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, MonoGenericContext *generic_context) { + MonoError error; locator_t loc; MonoTableInfo *tdef = &image->tables [MONO_TABLE_METHODIMPL]; guint32 start, end; @@ -5043,6 +5665,12 @@ mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod for (i = 0; i < num; ++i) { MonoMethod *method; + if (!mono_verifier_verify_methodimpl_row (image, start + i, &error)) { + mono_error_cleanup (&error); + ok = FALSE; + break; + } + mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE); method = method_from_method_def_or_ref ( image, cols [MONO_METHODIMPL_DECLARATION], generic_context); @@ -5085,7 +5713,7 @@ get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGene guint32 cols [MONO_GENPARCONSTRAINT_SIZE]; guint32 i, token, found; MonoClass *klass, **res; - GList *cons = NULL, *tmp; + GSList *cons = NULL, *tmp; MonoGenericContext *context = &container->context; *constraints = NULL; @@ -5095,7 +5723,11 @@ get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGene if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) { token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]); klass = mono_class_get_full (image, token, context); - cons = g_list_append (cons, klass); + if (!klass) { + g_slist_free (cons); + return FALSE; + } + cons = g_slist_append (cons, klass); ++found; } else { /* contiguous list finished */ @@ -5105,11 +5737,11 @@ get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGene } if (!found) return TRUE; - res = g_new0 (MonoClass*, found + 1); + res = mono_image_alloc0 (image, sizeof (MonoClass*) * (found + 1)); for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) { res [i] = tmp->data; } - g_list_free (cons); + g_slist_free (cons); *constraints = res; return TRUE; } @@ -5165,22 +5797,42 @@ mono_metadata_has_generic_params (MonoImage *image, guint32 token) return mono_metadata_get_generic_param_row (image, token, &owner); } +/* + * Memory is allocated from IMAGE's mempool. + */ +gboolean +mono_metadata_load_generic_param_constraints_full (MonoImage *image, guint32 token, + MonoGenericContainer *container) +{ + + guint32 start_row, i, owner; + if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner))) + return TRUE; + for (i = 0; i < container->type_argc; i++) { + if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container)) + return FALSE; + } + return TRUE; +} + /* * mono_metadata_load_generic_param_constraints: * + * @image: metadata context + * @token: metadata token to load the contraints, can be methodef or typedef. + * @container: generic container to load into. + * * Load the generic parameter constraints for the newly created generic type or method * represented by @token and @container. The @container is the new container which has * been returned by a call to mono_metadata_load_generic_params() with this @token. + * Memory is allocated from IMAGE's mempool. */ void mono_metadata_load_generic_param_constraints (MonoImage *image, guint32 token, MonoGenericContainer *container) { - guint32 start_row, i, owner; - if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner))) - return; - for (i = 0; i < container->type_argc; i++) - get_constraints (image, start_row + i, &container->type_params [i].constraints, container); + mono_metadata_load_generic_param_constraints_full (image, token, container); + /*FIXME this function can potentially exit with a pending loader error and cause all sort of havok */ } /* @@ -5207,7 +5859,7 @@ mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericC guint32 cols [MONO_GENERICPARAM_SIZE]; guint32 i, owner = 0, n; MonoGenericContainer *container; - MonoGenericParam *params; + MonoGenericParamFull *params; MonoGenericContext *context; if (!(i = mono_metadata_get_generic_param_row (image, token, &owner))) @@ -5216,22 +5868,26 @@ mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericC params = NULL; n = 0; container = mono_image_alloc0 (image, sizeof (MonoGenericContainer)); + container->image = image; do { n++; - params = g_realloc (params, sizeof (MonoGenericParam) * n); - memset (¶ms [n - 1], 0, sizeof (MonoGenericParam)); - params [n - 1].owner = container; - params [n - 1].flags = cols [MONO_GENERICPARAM_FLAGS]; - params [n - 1].num = cols [MONO_GENERICPARAM_NUMBER]; - params [n - 1].name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]); + params = g_realloc (params, sizeof (MonoGenericParamFull) * n); + memset (¶ms [n - 1], 0, sizeof (MonoGenericParamFull)); + params [n - 1].param.owner = container; + params [n - 1].param.num = cols [MONO_GENERICPARAM_NUMBER]; + params [n - 1].info.token = i | MONO_TOKEN_GENERIC_PARAM; + params [n - 1].info.flags = cols [MONO_GENERICPARAM_FLAGS]; + params [n - 1].info.name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]); + if (params [n - 1].param.num != n - 1) + g_warning ("GenericParam table unsorted or hole in generic param sequence: token %d", i); if (++i > tdef->rows) break; mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE); } while (cols [MONO_GENERICPARAM_OWNER] == owner); container->type_argc = n; - container->type_params = mono_image_alloc0 (image, sizeof (MonoGenericParam) * n); - memcpy (container->type_params, params, sizeof (MonoGenericParam) * n); + container->type_params = mono_image_alloc0 (image, sizeof (MonoGenericParamFull) * n); + memcpy (container->type_params, params, sizeof (MonoGenericParamFull) * n); g_free (params); container->parent = parent_container; @@ -5266,7 +5922,7 @@ mono_get_shared_generic_inst (MonoGenericContainer *container) MonoType *t = &helper [i]; t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR; - t->data.generic_param = &container->type_params [i]; + t->data.generic_param = mono_generic_container_get_param (container, i); type_argv [i] = t; } @@ -5279,43 +5935,95 @@ mono_get_shared_generic_inst (MonoGenericContainer *container) return nginst; } +/** + * mono_type_is_byref: + * @type: the MonoType operated on + * + * Returns: #TRUE if @type represents a type passed by reference, + * #FALSE otherwise. + */ gboolean mono_type_is_byref (MonoType *type) { return type->byref; } +/** + * mono_type_get_type: + * @type: the MonoType operated on + * + * Returns: the IL type value for @type. This is one of the MonoTypeEnum + * enum members like MONO_TYPE_I4 or MONO_TYPE_STRING. + */ int mono_type_get_type (MonoType *type) { return type->type; } -/* For MONO_TYPE_FNPTR */ +/** + * mono_type_get_signature: + * @type: the MonoType operated on + * + * It is only valid to call this function if @type is a MONO_TYPE_FNPTR. + * + * Returns: the MonoMethodSignature pointer that describes the signature + * of the function pointer @type represents. + */ MonoMethodSignature* mono_type_get_signature (MonoType *type) { + g_assert (type->type == MONO_TYPE_FNPTR); return type->data.method; } -/* For MONO_TYPE_CLASS, VALUETYPE */ +/** + * mono_type_get_class: + * @type: the MonoType operated on + * + * It is only valid to call this function if @type is a MONO_TYPE_CLASS or a + * MONO_TYPE_VALUETYPE. For more general functionality, use mono_class_from_mono_type (), + * instead + * + * Returns: the MonoClass pointer that describes the class that @type represents. + */ MonoClass* mono_type_get_class (MonoType *type) { + /* FIXME: review the runtime users before adding the assert here */ return type->data.klass; } -/* For MONO_TYPE_ARRAY */ +/** + * mono_type_get_array_type: + * @type: the MonoType operated on + * + * It is only valid to call this function if @type is a MONO_TYPE_ARRAY. + * + * Returns: a MonoArrayType struct describing the array type that @type + * represents. The info includes details such as rank, array element type + * and the sizes and bounds of multidimensional arrays. + */ MonoArrayType* mono_type_get_array_type (MonoType *type) { return type->data.array; } -/* For MONO_TYPE_PTR */ +/** + * mono_type_get_ptr_type: + * @type: the MonoType operated on + * + * It is only valid to call this function if @type is a MONO_TYPE_PTR. + * instead + * + * Returns: the MonoType pointer that describes the type that @type + * represents a pointer to. + */ MonoType* mono_type_get_ptr_type (MonoType *type) { + g_assert (type->type == MONO_TYPE_PTR); return type->data.type; } @@ -5326,12 +6034,92 @@ mono_type_get_modifiers (MonoType *type, gboolean *is_required, gpointer *iter) return NULL; } +/** + * mono_type_is_struct: + * @type: the MonoType operated on + * + * Returns: #TRUE is @type is a struct, that is a ValueType but not en enum + * or a basic type like System.Int32. #FALSE otherwise. + */ +mono_bool +mono_type_is_struct (MonoType *type) +{ + return (!type->byref && ((type->type == MONO_TYPE_VALUETYPE && + !type->data.klass->enumtype) || (type->type == MONO_TYPE_TYPEDBYREF) || + ((type->type == MONO_TYPE_GENERICINST) && + mono_metadata_generic_class_is_valuetype (type->data.generic_class) && + !type->data.generic_class->container_class->enumtype))); +} + +/** + * mono_type_is_void: + * @type: the MonoType operated on + * + * Returns: #TRUE is @type is System.Void. #FALSE otherwise. + */ +mono_bool +mono_type_is_void (MonoType *type) +{ + return (type && (type->type == MONO_TYPE_VOID) && !type->byref); +} + +/** + * mono_type_is_pointer: + * @type: the MonoType operated on + * + * Returns: #TRUE is @type is a managed or unmanaged pointer type. #FALSE otherwise. + */ +mono_bool +mono_type_is_pointer (MonoType *type) +{ + return (type && ((type->byref || (type->type == MONO_TYPE_I) || type->type == MONO_TYPE_STRING) + || (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) || + (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_OBJECT) || + (type->type == MONO_TYPE_ARRAY) || (type->type == MONO_TYPE_PTR) || + (type->type == MONO_TYPE_FNPTR))); +} + +/** + * mono_type_is_reference: + * @type: the MonoType operated on + * + * Returns: #TRUE is @type represents an object reference . #FALSE otherwise. + */ +mono_bool +mono_type_is_reference (MonoType *type) +{ + return (type && (((type->type == MONO_TYPE_STRING) || + (type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) || + (type->type == MONO_TYPE_OBJECT) || (type->type == MONO_TYPE_ARRAY)) || + ((type->type == MONO_TYPE_GENERICINST) && + !mono_metadata_generic_class_is_valuetype (type->data.generic_class)))); +} + +/** + * mono_signature_get_return_type: + * @sig: the method signature inspected + * + * Returns: the return type of the method signature @sig + */ MonoType* mono_signature_get_return_type (MonoMethodSignature *sig) { return sig->ret; } +/** + * mono_signature_get_params: + * @sig: the method signature inspected + * #iter: pointer to an iterator + * + * Iterates over the parameters for the method signature @sig. + * A void* pointer must be initualized to #NULL to start the iteration + * and it's address is passed to this function repeteadly until it returns + * #NULL. + * + * Returns: the next parameter type of the method signature @sig, + * #NULL when finished. + */ MonoType* mono_signature_get_params (MonoMethodSignature *sig, gpointer *iter) { @@ -5357,30 +6145,63 @@ mono_signature_get_params (MonoMethodSignature *sig, gpointer *iter) return NULL; } +/** + * mono_signature_get_param_count: + * @sig: the method signature inspected + * + * Returns: the number of parameters in the method signature @sig. + */ guint32 mono_signature_get_param_count (MonoMethodSignature *sig) { return sig->param_count; } +/** + * mono_signature_get_call_conv: + * @sig: the method signature inspected + * + * Returns: the call convention of the method signature @sig. + */ guint32 mono_signature_get_call_conv (MonoMethodSignature *sig) { return sig->call_convention; } +/** + * mono_signature_vararg_start: + * @sig: the method signature inspected + * + * Returns: the number of the first vararg parameter in the + * method signature @sig. -1 if this is not a vararg signature. + */ int mono_signature_vararg_start (MonoMethodSignature *sig) { return sig->sentinelpos; } +/** + * mono_signature_is_instance: + * @sig: the method signature inspected + * + * Returns: #TRUE if this the method signature @sig has an implicit + * first instance argument. #FALSE otherwise. + */ gboolean mono_signature_is_instance (MonoMethodSignature *sig) { return sig->hasthis; } +/** + * mono_signature_explicit_this: + * @sig: the method signature inspected + * + * Returns: #TRUE if this the method signature @sig has an explicit + * instance argument. #FALSE otherwise. + */ gboolean mono_signature_explicit_this (MonoMethodSignature *sig) {