#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 <mono/utils/mono-error-internals.h>
+
+/* 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);
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);
/*
#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
#endif
-/* Auxiliary structure used for caching inflated signatures */
-typedef struct {
- MonoMethodSignature *sig;
- MonoGenericContext context;
-} MonoInflatedMethodSignature;
-
/**
* mono_meta_table_name:
* @table: table index
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:
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;
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;
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));
}
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;
}
const char *data;
g_assert (idx < t->rows);
+ g_assert (idx >= 0);
data = t->base + idx * t->row_size;
g_assert (res_size == count);
}
/*
- * 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;
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);
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)
{
#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);
{
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;
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]);
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;
}
/**
* @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,
*
* 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;
}
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 */
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;
/* 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.
*/
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];
}
}
{
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;
{
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);
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 *);
}
/*
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;
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++;
}
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
* 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;
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;
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;
// 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
(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 */
+ /*
+ * 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);
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
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 () */
{
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);
}
static void
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);
}
}
{
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 ();
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]))
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);
+ 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 ();
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;
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);
}
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 ();
* 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);
/*
* 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
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);
+ if (index >= generic_container->type_argc)
+ return NULL;
+
return mono_generic_container_get_param (generic_container, index);
}
* @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
*
*/
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);
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;
+ /* 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->byval_arg.type && class->byval_arg.type != type->type)
return FALSE;
break;
}
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)
#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 */
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);
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;
}
/*
*
* 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)
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;
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;
}
* @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);
+ }
}
/*
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;
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;
* 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;
++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) {
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)
{
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;
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)
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:
{
if (p1 == p2)
return TRUE;
- if (p1->num != p2->num)
+ if (mono_generic_param_num (p1) != mono_generic_param_num (p2))
return FALSE;
/*
* 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;
/*
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);
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;
}
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;
}
}
*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;
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;
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;
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);
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;
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 */
}
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;
}
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, &(mono_generic_container_get_param (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 */
}
/*
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)))
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;
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;
}
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)
{
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)
{