X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmetadata.c;h=aafcbb55e121991306c9cc99078ec3dfe264769c;hb=6963bb4a65b95aa2716bce869696cde13abb8732;hp=3ac1a5a54f6c6c719b818aab1a562d39f0b3d989;hpb=93ad323a224c62fd0eb1aa535de438828208d49c;p=mono.git diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c index 3ac1a5a54f6..aafcbb55e12 100644 --- a/mono/metadata/metadata.c +++ b/mono/metadata/metadata.c @@ -27,8 +27,16 @@ #include "verify-internals.h" #include "class.h" #include "marshal.h" +#include "gc-internal.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); @@ -36,9 +44,12 @@ static gboolean mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolea static gboolean mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only); static gboolean _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only); +static GSList* free_generic_inst_dependents (MonoGenericInst *ginst); static void free_generic_inst (MonoGenericInst *ginst); +static GSList* free_generic_class_dependents (MonoGenericClass *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); /* @@ -182,7 +193,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 @@ -442,12 +453,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 @@ -535,7 +540,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: @@ -546,13 +551,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; @@ -607,24 +605,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; @@ -867,7 +859,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)); } @@ -924,7 +916,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; } @@ -1253,27 +1245,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; @@ -1282,13 +1276,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); @@ -1297,6 +1291,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) { @@ -1368,23 +1369,8 @@ 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 guint mono_generic_class_hash (gconstpointer data); /* @@ -1432,12 +1418,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; @@ -1491,8 +1479,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]); @@ -1507,19 +1493,8 @@ mono_metadata_init (void) void mono_metadata_cleanup (void) { - /* Has to free this first, as it could reference data in the other caches */ - if (generic_method_cache) - g_hash_table_destroy (generic_method_cache); g_hash_table_destroy (type_cache); - g_hash_table_destroy (generic_inst_cache); - g_hash_table_destroy (generic_class_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; } /** @@ -1529,6 +1504,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, @@ -1538,18 +1514,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; @@ -1591,13 +1566,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 */ @@ -1627,14 +1605,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; @@ -1670,12 +1648,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. */ @@ -1686,32 +1671,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]; } } @@ -1785,7 +1800,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; @@ -1797,7 +1812,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); @@ -1846,7 +1861,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 *); } /* @@ -1887,7 +1902,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; @@ -1906,10 +1922,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++; } @@ -2155,6 +2177,287 @@ retry: } } +static MonoImageSet *mscorlib_image_set; +static GPtrArray *image_sets; + +/* + * 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); +} + +/* + * 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; @@ -2166,8 +2469,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; @@ -2179,8 +2481,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; @@ -2194,9 +2496,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 @@ -2210,33 +2514,86 @@ 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; + + //check_image_sets (image); /* The data structures could reference each other so we delete them in two phases */ 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); + free_list = g_slist_concat (free_generic_inst_dependents (l->data), free_list); for (l = gclass_data.list; l; l = l->next) - free_generic_class (l->data); + free_list = g_slist_concat (free_generic_class_dependents (l->data), free_list); 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 @@ -2251,8 +2608,7 @@ free_inflated_method (MonoMethodInflated *imethod) 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 () */ @@ -2267,19 +2623,34 @@ free_inflated_method (MonoMethodInflated *imethod) } static void -free_generic_inst (MonoGenericInst *ginst) +free_list_with_data (GSList *l) +{ + while (l) { + g_free (l->data); + l = g_slist_delete_link (l, l); + } +} + +static GSList* +free_generic_inst_dependents (MonoGenericInst *ginst) { int i; for (i = 0; i < ginst->type_argc; ++i) mono_metadata_free_type (ginst->type_argv [i]); - g_free (ginst); + return g_slist_prepend (NULL, ginst); } - static void -free_generic_class (MonoGenericClass *gclass) +free_generic_inst (MonoGenericInst *ginst) +{ + free_list_with_data (free_generic_inst_dependents (ginst)); +} + +static GSList* +free_generic_class_dependents (MonoGenericClass *gclass) { + GSList *l = NULL; int i; /* FIXME: The dynamic case */ @@ -2288,11 +2659,23 @@ free_generic_class (MonoGenericClass *gclass) /* Allocated in mono_class_init () */ g_free (class->methods); - if (class->ext) + if (class->ext) { g_free (class->ext->properties); + g_free (class->ext->field_def_values); + } + /* Allocated in mono_class_setup_fields () */ + g_free (class->fields); + /* Allocated in mono_class_setup_vtable_general () */ + g_free (class->vtable); /* Allocated in mono_generic_class_get_class () */ g_free (class->interfaces); - g_free (class); + /* Allocated in setup_interface_offsets () */ + g_free (class->interfaces_packed); + g_free (class->interface_offsets_packed); + g_free (class->interface_bitmap); + /* Allocated in mono_class_setup_supertypes () */ + g_free (class->supertypes); + l = g_slist_prepend (l, class); } else if (gclass->is_dynamic) { MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass *)gclass; @@ -2300,27 +2683,26 @@ free_generic_class (MonoGenericClass *gclass) MonoClassField *field = dgclass->fields + i; mono_metadata_free_type (field->type); g_free ((char*)field->name); +#if HAVE_SGEN_GC + MONO_GC_UNREGISTER_ROOT (dgclass->field_objects [i]); +#endif } - 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); + l = g_slist_prepend (l, gclass->cached_class); } - g_free (gclass); + return g_slist_prepend (l, gclass); +} + +static void +free_generic_class (MonoGenericClass *gclass) +{ + free_list_with_data (free_generic_class_dependents (gclass)); } static void @@ -2336,15 +2718,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); } } @@ -2359,21 +2749,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 (); @@ -2394,7 +2793,9 @@ 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])) @@ -2402,24 +2803,36 @@ mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv) is_open = (i < type_argc); ginst = alloca (size); +#ifndef MONO_SMALL_CONFIG ginst->id = 0; +#endif 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); +#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 (); @@ -2448,6 +2861,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; @@ -2458,7 +2873,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); @@ -2483,7 +2906,7 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst 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 (); @@ -2494,26 +2917,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); @@ -2607,7 +3038,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 @@ -2632,7 +3063,9 @@ mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_c return param; } - g_assert (index < generic_container->type_argc); + if (index >= generic_container->type_argc) + return NULL; + return mono_generic_container_get_param (generic_container, index); } @@ -2673,6 +3106,7 @@ mono_metadata_get_shared_type (MonoType *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 * @@ -2690,7 +3124,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); @@ -2729,30 +3163,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) @@ -2821,16 +3264,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 */ @@ -2857,11 +3300,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); @@ -2894,10 +3337,81 @@ 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; +} + /* * mono_metadata_parse_mh_full: * @m: metadata context @@ -2910,7 +3424,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) @@ -2921,32 +3435,23 @@ 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)); + mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER); ptr++; mh->max_stack = 8; + mh->is_transient = TRUE; 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)); - ptr++; - mh->max_stack = 8; - 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; case METHOD_HEADER_FAT_FORMAT: fat_flags = read16 (ptr); ptr += 2; @@ -2976,17 +3481,21 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons default: return NULL; } - - 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); + if (local_var_sig_tok) { + int idx = (local_var_sig_tok & 0xffffff)-1; + if (idx >= t->rows) + 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) { + const char *locals_ptr; + int len=0, i, bsize; locals_ptr = mono_metadata_blob_heap (m, cols [MONO_STAND_ALONE_SIGNATURE]); bsize = mono_metadata_decode_blob_size (locals_ptr, &locals_ptr); @@ -2994,24 +3503,32 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons 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; } @@ -3045,12 +3562,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); + } } /* @@ -3375,7 +3901,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; @@ -3406,7 +3932,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; @@ -3416,16 +3942,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; @@ -3464,7 +3994,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) { @@ -3485,6 +4018,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) { @@ -3492,7 +4039,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; @@ -3969,11 +4516,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) @@ -3984,9 +4554,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: @@ -4225,9 +4806,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); @@ -4632,6 +5213,7 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec) const char *ptr; guint32 len; MonoType *type, *type2; + MonoType stack_type; mono_loader_lock (); @@ -4646,21 +5228,22 @@ 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]); - if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], NULL)) { + if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, NULL)) { mono_loader_unlock (); return NULL; } len = mono_metadata_decode_value (ptr, &ptr); - type = mono_image_alloc0 (image, sizeof (MonoType)); + type = &stack_type; + memset (type, 0, MONO_SIZEOF_TYPE); if (*ptr == MONO_TYPE_BYREF) { type->byref = 1; ptr++; } - if (!do_mono_metadata_parse_type (type, image, NULL, ptr, &ptr)) { + if (!do_mono_metadata_parse_type (type, image, NULL, FALSE, ptr, &ptr)) { mono_loader_unlock (); return NULL; } @@ -4672,11 +5255,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_image_alloc (image, MONO_SIZEOF_TYPE); + memcpy (type2, type, MONO_SIZEOF_TYPE); + g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2); mono_loader_unlock (); - return type; + return type2; } @@ -5107,7 +5692,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; @@ -5117,7 +5702,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 */ @@ -5131,7 +5720,7 @@ get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGene 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; } @@ -5187,9 +5776,28 @@ mono_metadata_has_generic_params (MonoImage *image, guint32 token) return mono_metadata_get_generic_param_row (image, token, &owner); } +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. @@ -5198,11 +5806,8 @@ 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, &mono_generic_container_get_param_info (container, 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 */ } /* @@ -5305,43 +5910,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; } @@ -5352,12 +6009,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) { @@ -5383,30 +6120,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) {