Handle more cases of gtd encoded as ginst over itself.
[mono.git] / mono / metadata / metadata.c
index 13f978a5205dd86e4155559e0dfc224fbc4b16f4..3d872b2e6280290e4a4eecf2b043429701f19020 100644 (file)
 #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);
@@ -37,6 +47,7 @@ static gboolean _mono_metadata_generic_class_equal (const MonoGenericClass *g1,
 static void free_generic_inst (MonoGenericInst *ginst);
 static void free_generic_class (MonoGenericClass *ginst);
 static void free_inflated_method (MonoMethodInflated *method);
+static void free_inflated_signature (MonoInflatedMethodSignature *sig);
 static void mono_metadata_field_info_full (MonoImage *meta, guint32 index, guint32 *offset, guint32 *rva, MonoMarshalSpec **marshal_spec, gboolean alloc_from_image);
 
 /*
@@ -180,7 +191,7 @@ const static unsigned char TableSchemas [] = {
 #define EVENT_SCHEMA_OFFSET EVENTMAP_SCHEMA_OFFSET + 3
        MONO_MT_UINT16,     /* "EventFlags#EventAttribute" }, */
        MONO_MT_STRING_IDX, /* "Name" }, */
-       MONO_MT_TABLE_IDX,  /* "EventType" }, TypeDef or TypeRef  */
+       MONO_MT_TDOR_IDX,  /* "EventType" }, TypeDef or TypeRef or TypeSpec  */
        MONO_MT_END,
 
 #define EVENT_POINTER_SCHEMA_OFFSET EVENT_SCHEMA_OFFSET + 4
@@ -440,12 +451,6 @@ mono_tables_names [] = {
 
 #endif
 
-/* Auxiliary structure used for caching inflated signatures */
-typedef struct {
-       MonoMethodSignature *sig;
-       MonoGenericContext context;
-} MonoInflatedMethodSignature;
-
 /**
  * mono_meta_table_name:
  * @table: table index
@@ -533,7 +538,7 @@ mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bit
                        case MONO_TABLE_ASSEMBLYREFOS:
                                g_assert (i == 3);
                                field_size = idx_size (MONO_TABLE_ASSEMBLYREF); break;
-                       case MONO_TABLE_ASSEMBLYPROCESSOR:
+                       case MONO_TABLE_ASSEMBLYREFPROCESSOR:
                                g_assert (i == 1);
                                field_size = idx_size (MONO_TABLE_ASSEMBLYREF); break;
                        case MONO_TABLE_CLASSLAYOUT:
@@ -544,13 +549,6 @@ mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bit
                                field_size = i ? idx_size (MONO_TABLE_EVENT):
                                        idx_size(MONO_TABLE_TYPEDEF); 
                                break;
-                       case MONO_TABLE_EVENT:
-                               g_assert (i == 2);
-                               n = MAX (meta->tables [MONO_TABLE_TYPEDEF].rows, meta->tables [MONO_TABLE_TYPEREF].rows);
-                               n = MAX (n, meta->tables [MONO_TABLE_TYPESPEC].rows);
-                               /*This is a coded token for 3 tables, so takes 2 bits */
-                               field_size = rtsize (n, 16 - MONO_TYPEDEFORREF_BITS);
-                               break;
                        case MONO_TABLE_EVENT_POINTER:
                                g_assert (i == 0);
                                field_size = idx_size (MONO_TABLE_EVENT); break;
@@ -605,24 +603,18 @@ mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bit
                                        idx_size(MONO_TABLE_METHOD);
                                break;
                        case MONO_TABLE_GENERICPARAM:
-                               g_assert (i == 2 || i == 4 || i == 5);
-                               if (i == 2) {
-                                       n = MAX (meta->tables [MONO_TABLE_METHOD].rows, meta->tables [MONO_TABLE_TYPEDEF].rows);
-                                       /*This is a coded token for 2 tables, so takes 1 bit */
-                                       field_size = rtsize (n, 16 - MONO_TYPEORMETHOD_BITS);
-                               } else if (i == 4)
-                                       field_size = idx_size (MONO_TABLE_TYPEDEF);
-                               else if (i == 5)
-                                       field_size = idx_size (MONO_TABLE_TYPEDEF);
+                               g_assert (i == 2);
+                               n = MAX (meta->tables [MONO_TABLE_METHOD].rows, meta->tables [MONO_TABLE_TYPEDEF].rows);
+                               /*This is a coded token for 2 tables, so takes 1 bit */
+                               field_size = rtsize (n, 16 - MONO_TYPEORMETHOD_BITS);
                                break;
-
                        case MONO_TABLE_GENERICPARAMCONSTRAINT:
                                g_assert (i == 0);
                                field_size = idx_size (MONO_TABLE_GENERICPARAM);
                                break;
                                
                        default:
-                               g_assert_not_reached ();
+                               g_error ("Can't handle MONO_MT_TABLE_IDX for table %d element %d", tableindex, i);
                        }
                        break;
 
@@ -865,7 +857,7 @@ const char *
 mono_metadata_locate (MonoImage *meta, int table, int idx)
 {
        /* idx == 0 refers always to NULL */
-       g_return_val_if_fail (idx > 0 && idx <= meta->tables [table].rows, "");
+       g_return_val_if_fail (idx > 0 && idx <= meta->tables [table].rows, ""); /*FIXME shouldn't we return NULL here?*/
           
        return meta->tables [table].base + (meta->tables [table].row_size * (idx - 1));
 }
@@ -922,7 +914,7 @@ mono_metadata_user_string (MonoImage *meta, guint32 index)
 const char *
 mono_metadata_blob_heap (MonoImage *meta, guint32 index)
 {
-       g_return_val_if_fail (index < meta->heap_blob.size, "");
+       g_return_val_if_fail (index < meta->heap_blob.size, "");/*FIXME shouldn't we return NULL and check for index == 0?*/
        return meta->heap_blob.data + index;
 }
 
@@ -969,6 +961,7 @@ mono_metadata_decode_row (const MonoTableInfo *t, int idx, guint32 *res, int res
        const char *data;
 
        g_assert (idx < t->rows);
+       g_assert (idx >= 0);
        data = t->base + idx * t->row_size;
        
        g_assert (res_size == count);
@@ -1251,27 +1244,29 @@ mono_metadata_parse_custom_mod (MonoImage *m, MonoCustomMod *dest, const char *p
 }
 
 /*
- * mono_metadata_parse_array_full:
+ * mono_metadata_parse_array_internal:
  * @m: a metadata context.
+ * @transient: whenever to allocate data from the heap
  * @ptr: a pointer to an encoded array description.
  * @rptr: pointer updated to match the end of the decoded stream
  *
  * Decodes the compressed array description found in the metadata @m at @ptr.
  *
  * Returns: a #MonoArrayType structure describing the array type
- * and dimensions. Memory is allocated from the image mempool.
+ * and dimensions. Memory is allocated from the heap or from the image mempool, depending
+ * on the value of @transient.
  *
  * LOCKING: Acquires the loader lock
  */
-MonoArrayType *
-mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container,
-                               const char *ptr, const char **rptr)
+static MonoArrayType *
+mono_metadata_parse_array_internal (MonoImage *m, MonoGenericContainer *container,
+                                                                       gboolean transient, const char *ptr, const char **rptr)
 {
        int i;
        MonoArrayType *array;
        MonoType *etype;
        
-       array = mono_image_alloc0 (m, sizeof (MonoArrayType));
+       array = transient ? g_malloc0 (sizeof (MonoArrayType)) : mono_image_alloc0 (m, sizeof (MonoArrayType));
        etype = mono_metadata_parse_type_full (m, container, MONO_PARSE_TYPE, 0, ptr, &ptr);
        if (!etype)
                return NULL;
@@ -1280,13 +1275,13 @@ mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container,
 
        array->numsizes = mono_metadata_decode_value (ptr, &ptr);
        if (array->numsizes)
-               array->sizes = g_new0 (int, array->numsizes);
+               array->sizes = transient ? g_malloc0 (sizeof (int) * array->numsizes) : mono_image_alloc0 (m, sizeof (int) * array->numsizes);
        for (i = 0; i < array->numsizes; ++i)
                array->sizes [i] = mono_metadata_decode_value (ptr, &ptr);
 
        array->numlobounds = mono_metadata_decode_value (ptr, &ptr);
        if (array->numlobounds)
-               array->lobounds = g_new0 (int, array->numlobounds);
+               array->lobounds = transient ? g_malloc0 (sizeof (int) * array->numlobounds) : mono_image_alloc0 (m, sizeof (int) * array->numlobounds);
        for (i = 0; i < array->numlobounds; ++i)
                array->lobounds [i] = mono_metadata_decode_signed_value (ptr, &ptr);
 
@@ -1295,6 +1290,13 @@ mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container,
        return array;
 }
 
+MonoArrayType *
+mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container,
+                                                               const char *ptr, const char **rptr)
+{
+       return mono_metadata_parse_array_internal (m, container, FALSE, ptr, rptr);
+}
+
 MonoArrayType *
 mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
 {
@@ -1366,22 +1368,10 @@ builtin_types[] = {
 #define NBUILTIN_TYPES() (sizeof (builtin_types) / sizeof (builtin_types [0]))
 
 static GHashTable *type_cache = NULL;
-static GHashTable *generic_inst_cache = NULL;
-static GHashTable *generic_class_cache = NULL;
 static int next_generic_inst_id = 0;
 
-/*
- * Protected by the loader lock.
- * It has a MonoMethodInflated* as key and value.
- * The key lookup will just access the declaring and context fields
- */
-static GHashTable *generic_method_cache = NULL;
-
-/*
- * Protected by the loader lock.
- * It has a MonoInflatedMethodSignature* as key and value.
- */
-static GHashTable *generic_signature_cache = NULL;
+static MonoImageSet *mscorlib_image_set;
+static GPtrArray *image_sets;
 
 static guint mono_generic_class_hash (gconstpointer data);
 
@@ -1430,12 +1420,14 @@ mono_generic_inst_equal_full (const MonoGenericInst *a, const MonoGenericInst *b
 {
        int i;
 
+#ifndef MONO_SMALL_CONFIG
        if (a->id && b->id) {
                if (a->id == b->id)
                        return TRUE;
                if (!signature_only)
                        return FALSE;
        }
+#endif
 
        if (a->is_open != b->is_open || a->type_argc != b->type_argc)
                return FALSE;
@@ -1489,8 +1481,6 @@ mono_metadata_init (void)
        int i;
 
        type_cache = g_hash_table_new (mono_type_hash, mono_type_equal);
-       generic_inst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
-       generic_class_cache = g_hash_table_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
 
        for (i = 0; i < NBUILTIN_TYPES (); ++i)
                g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
@@ -1506,17 +1496,9 @@ void
 mono_metadata_cleanup (void)
 {
        g_hash_table_destroy (type_cache);
-       g_hash_table_destroy (generic_inst_cache);
-       g_hash_table_destroy (generic_class_cache);
-       if (generic_method_cache)
-               g_hash_table_destroy (generic_method_cache);
-       if (generic_signature_cache)
-               g_hash_table_destroy (generic_signature_cache);
        type_cache = NULL;
-       generic_inst_cache = NULL;
-       generic_class_cache = NULL;
-       generic_method_cache = NULL;
-       generic_signature_cache = NULL;
+       g_ptr_array_free (image_sets, TRUE);
+       image_sets = NULL;
 }
 
 /**
@@ -1526,6 +1508,7 @@ mono_metadata_cleanup (void)
  * @opt_attrs: optional attributes to store in the returned type
  * @ptr: pointer to the type representation
  * @rptr: pointer updated to match the end of the decoded stream
+ * @transient: whenever to allocate the result from the heap or from a mempool
  * 
  * Decode a compressed type description found at @ptr in @m.
  * @mode can be one of MONO_PARSE_MOD_TYPE, MONO_PARSE_PARAM, MONO_PARSE_RET,
@@ -1535,18 +1518,17 @@ mono_metadata_cleanup (void)
  *
  * To parse a generic type, `generic_container' points to the current class'es
  * (the `generic_container' field in the MonoClass) or the current generic method's
- * (the `generic_container' field in the MonoMethodNormal) generic container.
+ * (stored in image->property_hash) generic container.
  * When we encounter any MONO_TYPE_VAR or MONO_TYPE_MVAR's, they're looked up in
  * this MonoGenericContainer.
- * This is a Mono runtime internal function.
  *
  * LOCKING: Acquires the loader lock.
  *
  * Returns: a #MonoType structure representing the decoded type.
  */
-MonoType*
-mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, MonoParseTypeMode mode,
-                              short opt_attrs, const char *ptr, const char **rptr)
+static MonoType*
+mono_metadata_parse_type_internal (MonoImage *m, MonoGenericContainer *container, MonoParseTypeMode mode,
+                                                                  short opt_attrs, gboolean transient, const char *ptr, const char **rptr)
 {
        MonoType *type, *cached;
        MonoType stype;
@@ -1588,13 +1570,16 @@ mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, Mo
        }
 
        if (count) {
-               type = mono_image_alloc0 (m, sizeof (MonoType) + ((gint32)count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoCustomMod));
+               int size;
+
+               size = MONO_SIZEOF_TYPE + ((gint32)count) * sizeof (MonoCustomMod);
+               type = transient ? g_malloc0 (size) : mono_image_alloc0 (m, size);
                type->num_mods = count;
                if (count > 64)
                        g_warning ("got more than 64 modifiers in type");
        } else {
                type = &stype;
-               memset (type, 0, sizeof (MonoType));
+               memset (type, 0, MONO_SIZEOF_TYPE);
        }
 
        /* Parse pinned, byref and custom modifiers */
@@ -1624,14 +1609,14 @@ mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, Mo
        type->byref = byref;
        type->pinned = pinned ? 1 : 0;
 
-       if (!do_mono_metadata_parse_type (type, m, container, ptr, &ptr)) {
+       if (!do_mono_metadata_parse_type (type, m, container, transient, ptr, &ptr)) {
                return NULL;
        }
 
        if (rptr)
                *rptr = ptr;
 
-       if (!type->num_mods) {
+       if (!type->num_mods && !transient) {
                /* no need to free type here, because it is on the stack */
                if ((type->type == MONO_TYPE_CLASS || type->type == MONO_TYPE_VALUETYPE) && !type->pinned && !type->attrs) {
                        MonoType *ret = type->byref ? &type->data.klass->this_arg : &type->data.klass->byval_arg;
@@ -1667,12 +1652,19 @@ mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, Mo
        /* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */
        
        if (type == &stype) {
-               type = mono_image_alloc (m, sizeof (MonoType));
-               memcpy (type, &stype, sizeof (MonoType));
+               type = transient ? g_malloc (MONO_SIZEOF_TYPE) : mono_image_alloc (m, MONO_SIZEOF_TYPE);
+               memcpy (type, &stype, MONO_SIZEOF_TYPE);
        }
        return type;
 }
 
+MonoType*
+mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, MonoParseTypeMode mode,
+                                                          short opt_attrs, const char *ptr, const char **rptr)
+{
+       return mono_metadata_parse_type_internal (m, container, mode, opt_attrs, FALSE, ptr, rptr);
+}
+
 /*
  * LOCKING: Acquires the loader lock.
  */
@@ -1683,32 +1675,62 @@ mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
        return mono_metadata_parse_type_full (m, NULL, mode, opt_attrs, ptr, rptr);
 }
 
+gboolean
+mono_metadata_method_has_param_attrs (MonoImage *m, int def)
+{
+       MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
+       MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
+       guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
+
+       if (def < methodt->rows)
+               lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
+       else
+               lastp = m->tables [MONO_TABLE_PARAM].rows + 1;
+
+       for (i = param_index; i < lastp; ++i) {
+               guint32 flags = mono_metadata_decode_row_col (paramt, i - 1, MONO_PARAM_FLAGS);
+               if (flags)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
 /*
  * mono_metadata_get_param_attrs:
  *
+ * @m The image to loader parameter attributes from
+ * @def method def token (one based)
+ * @param_count number of params to decode including the return value
+ *
  *   Return the parameter attributes for the method whose MethodDef index is DEF. The 
  * returned memory needs to be freed by the caller. If all the param attributes are
  * 0, then NULL is returned.
  */
 int*
-mono_metadata_get_param_attrs (MonoImage *m, int def)
+mono_metadata_get_param_attrs (MonoImage *m, int def, int param_count)
 {
        MonoTableInfo *paramt = &m->tables [MONO_TABLE_PARAM];
        MonoTableInfo *methodt = &m->tables [MONO_TABLE_METHOD];
        guint32 cols [MONO_PARAM_SIZE];
-       guint lastp, i, param_index = mono_metadata_decode_row_col (&m->tables [MONO_TABLE_METHOD], def - 1, MONO_METHOD_PARAMLIST);
+       guint lastp, i, param_index = mono_metadata_decode_row_col (methodt, def - 1, MONO_METHOD_PARAMLIST);
        int *pattrs = NULL;
 
        if (def < methodt->rows)
-               lastp = mono_metadata_decode_row_col (&m->tables [MONO_TABLE_METHOD], def, MONO_METHOD_PARAMLIST);
+               lastp = mono_metadata_decode_row_col (methodt, def, MONO_METHOD_PARAMLIST);
        else
                lastp = paramt->rows + 1;
 
        for (i = param_index; i < lastp; ++i) {
-               mono_metadata_decode_row (&m->tables [MONO_TABLE_PARAM], i - 1, cols, MONO_PARAM_SIZE);
+               mono_metadata_decode_row (paramt, i - 1, cols, MONO_PARAM_SIZE);
                if (cols [MONO_PARAM_FLAGS]) {
                        if (!pattrs)
-                               pattrs = g_new0 (int, 1 + (lastp - param_index));
+                               pattrs = g_new0 (int, param_count);
+                       /* at runtime we just ignore this kind of malformed file:
+                       * the verifier can signal the error to the user
+                       */
+                       if (cols [MONO_PARAM_SEQUENCE] >= param_count)
+                               continue;
                        pattrs [cols [MONO_PARAM_SEQUENCE]] = cols [MONO_PARAM_FLAGS];
                }
        }
@@ -1782,7 +1804,7 @@ mono_metadata_signature_alloc (MonoImage *m, guint32 nparams)
 {
        MonoMethodSignature *sig;
 
-       sig = mono_image_alloc0 (m, sizeof (MonoMethodSignature) + ((gint32)nparams - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType*));
+       sig = mono_image_alloc0 (m, MONO_SIZEOF_METHOD_SIGNATURE + ((gint32)nparams) * sizeof (MonoType*));
        sig->param_count = nparams;
        sig->sentinelpos = -1;
 
@@ -1794,7 +1816,7 @@ mono_metadata_signature_dup_internal (MonoImage *image, MonoMemPool *mp, MonoMet
 {
        int sigsize;
        MonoMethodSignature *ret;
-       sigsize = sizeof (MonoMethodSignature) + (sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *);
+       sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
 
        if (image) {
                ret = mono_image_alloc (image, sigsize);
@@ -1843,7 +1865,7 @@ mono_metadata_signature_dup (MonoMethodSignature *sig)
 guint32
 mono_metadata_signature_size (MonoMethodSignature *sig)
 {
-       return sizeof (MonoMethodSignature) + (sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *);
+       return MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
 }
 
 /*
@@ -1884,7 +1906,8 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c
        param_count = mono_metadata_decode_value (ptr, &ptr);
 
        if (def)
-               pattrs = mono_metadata_get_param_attrs (m, def);
+               pattrs = mono_metadata_get_param_attrs (m, def, param_count + 1); /*Must be + 1 since signature's param count doesn't account for the return value */
+
        method = mono_metadata_signature_alloc (m, param_count);
        method->hasthis = hasthis;
        method->explicit_this = explicit_this;
@@ -1903,10 +1926,16 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c
 
        for (i = 0; i < method->param_count; ++i) {
                if (*ptr == MONO_TYPE_SENTINEL) {
-                       if (method->call_convention != MONO_CALL_VARARG || def)
-                               g_error ("found sentinel for methoddef or no vararg method");
-                       if (method->sentinelpos >= 0)
-                               g_error ("found sentinel twice in the same signature");
+                       if (method->call_convention != MONO_CALL_VARARG || def) {
+                               g_warning ("found sentinel for methoddef or no vararg method 0x%08x on image %s", def, m->name);
+                               g_free (pattrs);
+                               return NULL;
+                       }
+                       if (method->sentinelpos >= 0) {
+                               g_warning ("found sentinel twice in the same signature for method 0x%08x on image %s", def, m->name);
+                               g_free (pattrs);
+                               return NULL;
+                       }
                        method->sentinelpos = i;
                        ptr++;
                }
@@ -2109,9 +2138,10 @@ retry:
                goto retry;
        case MONO_TYPE_FNPTR:
                return signature_in_image (type->data.method, image);
-       case MONO_TYPE_VAR:
-               if (type->data.generic_param->owner) {
-                       g_assert (!type->data.generic_param->owner->is_method);
+       case MONO_TYPE_VAR: {
+               MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
+               if (container) {
+                       g_assert (!container->is_method);
                        /*
                         * FIXME: The following check is here solely
                         * for monodis, which uses the internal
@@ -2124,28 +2154,365 @@ retry:
                         * however, so a crash results without this
                         * check.
                         */
-                       if (!type->data.generic_param->owner->owner.klass)
-                               return FALSE;
-                       return type->data.generic_param->owner->owner.klass->image == image;
+                       if (!container->owner.klass)
+                               return container->image == image;
+                       return container->owner.klass->image == image;
                } else {
                        return type->data.generic_param->image == image;
                }
-       case MONO_TYPE_MVAR:
-               if (type->data.generic_param->owner) {
-                       g_assert (type->data.generic_param->owner->is_method);
-                       if (!type->data.generic_param->owner->owner.method)
+       }
+       case MONO_TYPE_MVAR: {
+               MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
+               if (type->data.generic_param->image == image)
+                       return TRUE;
+               if (container) {
+                       g_assert (container->is_method);
+                       if (!container->owner.method)
                                /* RefEmit created generic param whose method is not finished */
-                               return FALSE;
-                       return type->data.generic_param->owner->owner.method->klass->image == image;
+                               return container->image == image;
+                       return container->owner.method->klass->image == image;
                } else {
                        return type->data.generic_param->image == image;
                }
+       }
        default:
                /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type () */
                return image == mono_class_from_mono_type (type)->image;
        }
 }
 
+/*
+ * get_image_set:
+ *
+ *   Return a MonoImageSet representing the set of images in IMAGES.
+ * 
+ * LOCKING: Assumes the loader lock is held.
+ */
+static MonoImageSet*
+get_image_set (MonoImage **images, int nimages)
+{
+       int i, j, k;
+       MonoImageSet *set;
+       GSList *l;
+
+       if (!image_sets)
+               image_sets = g_ptr_array_new ();
+
+       /* Common case */
+       if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
+               return mscorlib_image_set;
+
+       /* Happens with empty generic instances */
+       if (nimages == 0)
+               return mscorlib_image_set;
+
+       if (images [0] == mono_defaults.corlib && nimages > 1)
+               l = images [1]->image_sets;
+       else
+               l = images [0]->image_sets;
+
+       set = NULL;
+       for (; l; l = l->next) {
+               set = l->data;
+
+               if (set->nimages == nimages) {
+                       for (j = 0; j < nimages; ++j) {
+                               for (k = 0; k < nimages; ++k)
+                                       if (set->images [k] == images [j])
+                                               break;
+                               if (k == nimages)
+                                       /* Not found */
+                                       break;
+                       }
+                       if (j == nimages)
+                               /* Found */
+                               break;
+               }
+       }
+
+       if (!l) {
+               /* Not found */
+               set = g_new0 (MonoImageSet, 1);
+               set->nimages = nimages;
+               set->images = g_new0 (MonoImage*, nimages);
+               InitializeCriticalSection (&set->lock);
+               for (i = 0; i < nimages; ++i)
+                       set->images [i] = images [i];
+               set->gclass_cache = g_hash_table_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
+               set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
+               set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
+               set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
+       
+               for (i = 0; i < nimages; ++i)
+                       set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
+
+               g_ptr_array_add (image_sets, set);
+       }
+
+       if (nimages == 1 && images [0] == mono_defaults.corlib)
+               mscorlib_image_set = set;
+
+       return set;
+}
+
+static void
+delete_image_set (MonoImageSet *set)
+{
+       int i;
+
+       g_hash_table_destroy (set->gclass_cache);
+       g_hash_table_destroy (set->ginst_cache);
+       g_hash_table_destroy (set->gmethod_cache);
+       g_hash_table_destroy (set->gsignature_cache);
+
+       for (i = 0; i < set->nimages; ++i)
+               set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set);
+
+       g_ptr_array_remove (image_sets, set);
+
+       if (set->mempool)
+               mono_mempool_destroy (set->mempool);
+       g_free (set->images);
+       DeleteCriticalSection (&set->lock);
+       g_free (set);
+}
+
+static void
+mono_image_set_lock (MonoImageSet *set)
+{
+       EnterCriticalSection (&set->lock);
+}
+
+static void
+mono_image_set_unlock (MonoImageSet *set)
+{
+       LeaveCriticalSection (&set->lock);
+}
+
+gpointer
+mono_image_set_alloc (MonoImageSet *set, guint size)
+{
+       gpointer res;
+
+       mono_image_set_lock (set);
+       if (!set->mempool)
+               set->mempool = mono_mempool_new_size (1024);
+       res = mono_mempool_alloc (set->mempool, size);
+       mono_image_set_unlock (set);
+
+       return res;
+}
+
+gpointer
+mono_image_set_alloc0 (MonoImageSet *set, guint size)
+{
+       gpointer res;
+
+       mono_image_set_lock (set);
+       if (!set->mempool)
+               set->mempool = mono_mempool_new_size (1024);
+       res = mono_mempool_alloc0 (set->mempool, size);
+       mono_image_set_unlock (set);
+
+       return res;
+}
+
+char*
+mono_image_set_strdup (MonoImageSet *set, const char *s)
+{
+       char *res;
+
+       mono_image_set_lock (set);
+       if (!set->mempool)
+               set->mempool = mono_mempool_new_size (1024);
+       res = mono_mempool_strdup (set->mempool, s);
+       mono_image_set_unlock (set);
+
+       return res;
+}
+
+/* 
+ * Structure used by the collect_..._images functions to store the image list.
+ */
+typedef struct {
+       MonoImage *image_buf [64];
+       MonoImage **images;
+       int nimages, images_len;
+} CollectData;
+
+static void
+collect_data_init (CollectData *data)
+{
+       data->images = data->image_buf;
+       data->images_len = 64;
+       data->nimages = 0;
+}
+
+static void
+collect_data_free (CollectData *data)
+{
+       if (data->images != data->image_buf)
+               g_free (data->images);
+}
+
+static void
+enlarge_data (CollectData *data)
+{
+       int new_len = data->images_len < 16 ? 16 : data->images_len * 2;
+       MonoImage **d = g_new (MonoImage *, new_len);
+
+       // FIXME: test this
+       g_assert_not_reached ();
+       memcpy (d, data->images, data->images_len);
+       if (data->images != data->image_buf)
+               g_free (data->images);
+       data->images = d;
+       data->images_len = new_len;
+}
+
+static inline void
+add_image (MonoImage *image, CollectData *data)
+{
+       int i;
+
+       /* The arrays are small, so use a linear search instead of a hash table */
+       for (i = 0; i < data->nimages; ++i)
+               if (data->images [i] == image)
+                       return;
+
+       if (data->nimages == data->images_len)
+               enlarge_data (data);
+
+       data->images [data->nimages ++] = image;
+}
+
+static void
+collect_type_images (MonoType *type, CollectData *data);
+
+static void
+collect_ginst_images (MonoGenericInst *ginst, CollectData *data)
+{
+       int i;
+
+       for (i = 0; i < ginst->type_argc; ++i) {
+               collect_type_images (ginst->type_argv [i], data);
+       }
+}
+
+static void
+collect_gclass_images (MonoGenericClass *gclass, CollectData *data)
+{
+       add_image (gclass->container_class->image, data);
+       if (gclass->context.class_inst)
+               collect_ginst_images (gclass->context.class_inst, data);
+}
+
+static void
+collect_signature_images (MonoMethodSignature *sig, CollectData *data)
+{
+       gpointer iter = NULL;
+       MonoType *p;
+
+       collect_type_images (mono_signature_get_return_type (sig), data);
+       while ((p = mono_signature_get_params (sig, &iter)) != NULL)
+               collect_type_images (p, data);
+}
+
+static void
+collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData *data)
+{
+       collect_signature_images (sig->sig, data);
+       if (sig->context.class_inst)
+               collect_ginst_images (sig->context.class_inst, data);
+       if (sig->context.method_inst)
+               collect_ginst_images (sig->context.method_inst, data);
+}
+
+static void
+collect_method_images (MonoMethodInflated *method, CollectData *data)
+{
+       add_image (method->declaring->klass->image, data);
+       if (method->context.class_inst)
+               collect_ginst_images (method->context.class_inst, data);
+       if (method->context.method_inst)
+               collect_ginst_images (method->context.method_inst, data);
+       /*
+       if (((MonoMethod*)method)->signature)
+               collect_signature_images (mono_method_signature ((MonoMethod*)method), data);
+       */
+}
+
+static void
+collect_type_images (MonoType *type, CollectData *data)
+{
+retry:
+       switch (type->type) {
+       case MONO_TYPE_GENERICINST:
+               collect_gclass_images (type->data.generic_class, data);
+               break;
+       case MONO_TYPE_PTR:
+               type = type->data.type;
+               goto retry;
+       case MONO_TYPE_SZARRAY:
+               type = &type->data.klass->byval_arg;
+               goto retry;
+       case MONO_TYPE_ARRAY:
+               type = &type->data.array->eklass->byval_arg;
+               goto retry;
+       case MONO_TYPE_FNPTR:
+               //return signature_in_image (type->data.method, image);
+               g_assert_not_reached ();
+       case MONO_TYPE_VAR: {
+               MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
+               if (container) {
+                       g_assert (!container->is_method);
+                       /*
+                        * FIXME: The following check is here solely
+                        * for monodis, which uses the internal
+                        * function
+                        * mono_metadata_load_generic_params().  The
+                        * caller of that function needs to fill in
+                        * owner->klass or owner->method of the
+                        * returned struct, but monodis doesn't do
+                        * that.  The image unloading depends on that,
+                        * however, so a crash results without this
+                        * check.
+                        */
+                       if (!container->owner.klass)
+                               add_image (container->image, data);
+                       else
+                               add_image (container->owner.klass->image, data);
+               } else {
+                       add_image (type->data.generic_param->image, data);
+               }
+       }
+               break;
+       case MONO_TYPE_MVAR: {
+               MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
+               if (type->data.generic_param->image)
+                       add_image (type->data.generic_param->image, data);
+               if (container) {
+                       if (!container->owner.method) {
+                               /* RefEmit created generic param whose method is not finished */
+                               add_image (container->image, data);
+                       } else {
+                               g_assert (container->is_method);
+                               add_image (container->owner.method->klass->image, data);
+                       }
+               } else {
+                       add_image (type->data.generic_param->image, data);
+               }
+       }
+               break;
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_VALUETYPE:
+               add_image (mono_class_from_mono_type (type)->image, data);
+               break;
+       default:
+               add_image (mono_defaults.corlib, data);
+       }
+}
+
 typedef struct {
        MonoImage *image;
        GSList *list;
@@ -2157,8 +2524,7 @@ steal_gclass_in_image (gpointer key, gpointer value, gpointer data)
        MonoGenericClass *gclass = key;
        CleanForImageUserData *user_data = data;
 
-       if (!gclass_in_image (gclass, user_data->image))
-               return FALSE;
+       g_assert (gclass_in_image (gclass, user_data->image));
 
        user_data->list = g_slist_prepend (user_data->list, gclass);
        return TRUE;
@@ -2170,8 +2536,8 @@ steal_ginst_in_image (gpointer key, gpointer value, gpointer data)
        MonoGenericInst *ginst = key;
        CleanForImageUserData *user_data = data;
 
-       if (!ginst_in_image (ginst, user_data->image))
-               return FALSE;
+       // This doesn't work during corlib compilation
+       //g_assert (ginst_in_image (ginst, user_data->image));
 
        user_data->list = g_slist_prepend (user_data->list, ginst);
        return TRUE;
@@ -2185,9 +2551,11 @@ inflated_method_in_image (gpointer key, gpointer value, gpointer data)
 
        // FIXME:
        // https://bugzilla.novell.com/show_bug.cgi?id=458168
-       return method->declaring->klass->image == image ||
+       g_assert (method->declaring->klass->image == image ||
                (method->context.class_inst && ginst_in_image (method->context.class_inst, image)) ||
-               (method->context.method_inst && ginst_in_image (method->context.method_inst, image)) || (((MonoMethod*)method)->signature && signature_in_image (mono_method_signature ((MonoMethod*)method), image));
+                         (method->context.method_inst && ginst_in_image (method->context.method_inst, image)) || (((MonoMethod*)method)->signature && signature_in_image (mono_method_signature ((MonoMethod*)method), image)));
+
+       return TRUE;
 }
 
 static gboolean
@@ -2201,24 +2569,70 @@ inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
                (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image));
 }      
 
-void
+static void
+check_gmethod (gpointer key, gpointer value, gpointer data)
+{
+       MonoMethodInflated *method = key;
+       MonoImage *image = data;
+
+       if (method->context.class_inst)
+               g_assert (!ginst_in_image (method->context.class_inst, image));
+       if (method->context.method_inst)
+               g_assert (!ginst_in_image (method->context.method_inst, image));
+       if (((MonoMethod*)method)->signature)
+               g_assert (!signature_in_image (mono_method_signature ((MonoMethod*)method), image));
+}
+
+/*
+ * check_image_sets:
+ *
+ *   Run a consistency check on the image set data structures.
+ */
+static G_GNUC_UNUSED void
+check_image_sets (MonoImage *image)
+{
+       int i;
+       GSList *l = image->image_sets;
+
+       if (!image_sets)
+               return;
+
+       for (i = 0; i < image_sets->len; ++i) {
+               MonoImageSet *set = g_ptr_array_index (image_sets, i);
+
+               if (!g_slist_find (l, set)) {
+                       g_hash_table_foreach (set->gmethod_cache, check_gmethod, image);
+               }
+       }
+}
+
+GSList*
 mono_metadata_clean_for_image (MonoImage *image)
 {
        CleanForImageUserData ginst_data, gclass_data;
-       GSList *l;
+       GSList *l, *set_list, *free_list = NULL;
+
+       //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);
@@ -2226,8 +2640,18 @@ mono_metadata_clean_for_image (MonoImage *image)
                free_generic_class (l->data);
        g_slist_free (ginst_data.list);
        g_slist_free (gclass_data.list);
-       mono_class_unregister_image_generic_subclasses (image);
+       /* delete_image_set () modifies the lists so make a copy */
+       set_list = g_slist_copy (image->image_sets);
+       for (l = set_list; l; l = l->next) {
+               MonoImageSet *set = l->data;
+
+               delete_image_set (set);
+       }
+       g_slist_free (set_list);
+
        mono_loader_unlock ();
+
+       return free_list;
 }
 
 static void
@@ -2236,12 +2660,13 @@ free_inflated_method (MonoMethodInflated *imethod)
        int i;
        MonoMethod *method = (MonoMethod*)imethod;
 
+       mono_marshal_free_inflated_wrappers (method);
+
        if (method->signature)
                mono_metadata_free_inflated_signature (method->signature);
 
        if (!((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))) {
-               MonoMethodNormal* mn = (MonoMethodNormal*) method;
-               MonoMethodHeader *header = mn->header;
+               MonoMethodHeader *header = imethod->header;
 
                if (header) {
                        /* Allocated in inflate_generic_header () */
@@ -2260,56 +2685,17 @@ free_generic_inst (MonoGenericInst *ginst)
 {
        int i;
 
+       /* The ginst itself is allocated from the image set mempool */
        for (i = 0; i < ginst->type_argc; ++i)
                mono_metadata_free_type (ginst->type_argv [i]);
-       g_free (ginst);
 }
 
-
 static void
 free_generic_class (MonoGenericClass *gclass)
 {
-       int i;
-
-       /* FIXME: The dynamic case */
-       if (gclass->cached_class && !gclass->cached_class->image->dynamic && !mono_generic_class_is_generic_type_definition (gclass)) {
-               MonoClass *class = gclass->cached_class;
-
-               /* Allocated in mono_class_init () */
-               g_free (class->methods);
-               if (class->ext)
-                       g_free (class->ext->properties);
-               /* Allocated in mono_generic_class_get_class () */
-               g_free (class->interfaces);
-               g_free (class);
-       } else if (gclass->is_dynamic) {
-               MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass *)gclass;
-
-               for (i = 0; i < dgclass->count_fields; ++i) {
-                       MonoClassField *field = dgclass->fields + i;
-                       mono_metadata_free_type (field->type);
-                       g_free ((char*)field->name);
-               }
-               for (i = 0; i < dgclass->count_properties; ++i) {
-                       MonoProperty *property = dgclass->properties + i;
-                       g_free ((char*)property->name);
-               }
-               for (i = 0; i < dgclass->count_events; ++i) {
-                       MonoEvent *event = dgclass->events + i;
-                       g_free ((char*)event->name);
-               }
-               
-               g_free (dgclass->methods);
-               g_free (dgclass->ctors);
-               g_free (dgclass->fields);
-               g_free (dgclass->properties);
-               g_free (dgclass->events);
-               g_free (dgclass->field_objects);
-               g_free (dgclass->field_generic_types);
-               if (!mono_generic_class_is_generic_type_definition (gclass))
-                       g_free (gclass->cached_class);
-       }
-       g_free (gclass);
+       /* The gclass itself is allocated from the image set mempool */
+       if (gclass->is_dynamic)
+               mono_reflection_free_dynamic_generic_class (gclass);
 }
 
 static void
@@ -2325,15 +2711,23 @@ free_inflated_signature (MonoInflatedMethodSignature *sig)
 MonoMethodInflated*
 mono_method_inflated_lookup (MonoMethodInflated* method, gboolean cache)
 {
+       CollectData data;
+       MonoImageSet *set;
+
+       collect_data_init (&data);
+
+       collect_method_images (method, &data);
+
+       set = get_image_set (data.images, data.nimages);
+
+       collect_data_free (&data);
+
        if (cache) {
-               if (!generic_method_cache)
-                       generic_method_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
-               g_hash_table_insert (generic_method_cache, method, method);
+               g_hash_table_insert (set->gmethod_cache, method, method);
+
                return method;
        } else {
-               if (generic_method_cache)
-                       return g_hash_table_lookup (generic_method_cache, method);
-               return NULL;
+               return g_hash_table_lookup (set->gmethod_cache, method);
        }
 }
 
@@ -2348,21 +2742,30 @@ mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericConte
 {
        MonoInflatedMethodSignature helper;
        MonoInflatedMethodSignature *res;
+       CollectData data;
+       MonoImageSet *set;
 
        mono_loader_lock ();
-       if (!generic_signature_cache)
-               generic_signature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
 
        helper.sig = sig;
        helper.context.class_inst = context->class_inst;
        helper.context.method_inst = context->method_inst;
-       res = g_hash_table_lookup (generic_signature_cache, &helper);
+
+       collect_data_init (&data);
+
+       collect_inflated_signature_images (&helper, &data);
+
+       set = get_image_set (data.images, data.nimages);
+
+       collect_data_free (&data);
+
+       res = g_hash_table_lookup (set->gsignature_cache, &helper);
        if (!res) {
                res = g_new0 (MonoInflatedMethodSignature, 1);
                res->sig = sig;
                res->context.class_inst = context->class_inst;
                res->context.method_inst = context->method_inst;
-               g_hash_table_insert (generic_signature_cache, res, res);
+               g_hash_table_insert (set->gsignature_cache, res, res);
        }
 
        mono_loader_unlock ();
@@ -2383,7 +2786,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]))
@@ -2391,24 +2796,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);
+               ginst = mono_image_set_alloc0 (set, size);
+#ifndef MONO_SMALL_CONFIG
                ginst->id = ++next_generic_inst_id;
+#endif
                ginst->is_open = is_open;
                ginst->type_argc = type_argc;
 
                for (i = 0; i < type_argc; ++i)
                        ginst->type_argv [i] = mono_metadata_type_dup (NULL, type_argv [i]);
 
-               g_hash_table_insert (generic_inst_cache, ginst, ginst);
+               g_hash_table_insert (set->ginst_cache, ginst, ginst);
        }
 
        mono_loader_unlock ();
@@ -2437,6 +2854,8 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
        MonoGenericClass *gclass;
        MonoGenericClass helper;
        gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic);
+       MonoImageSet *set;
+       CollectData data;
 
        helper.container_class = container_class;
        helper.context.class_inst = inst;
@@ -2447,7 +2866,15 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
 
        mono_loader_lock ();
 
-       gclass = g_hash_table_lookup (generic_class_cache, &helper);
+       collect_data_init (&data);
+
+       collect_gclass_images (&helper, &data);
+
+       set = get_image_set (data.images, data.nimages);
+
+       collect_data_free (&data);
+
+       gclass = g_hash_table_lookup (set->gclass_cache, &helper);
 
        /* A tripwire just to keep us honest */
        g_assert (!helper.cached_class);
@@ -2458,21 +2885,22 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
        }
 
        if (is_dynamic) {
-               MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
+               MonoDynamicGenericClass *dgclass = mono_image_set_new0 (set, MonoDynamicGenericClass, 1);
                gclass = &dgclass->generic_class;
                gclass->is_dynamic = 1;
        } else {
-               gclass = g_new0 (MonoGenericClass, 1);
+               gclass = mono_image_set_new0 (set, MonoGenericClass, 1);
        }
 
        gclass->is_tb_open = is_tb_open;
        gclass->container_class = container_class;
        gclass->context.class_inst = inst;
        gclass->context.method_inst = NULL;
+       gclass->owner = set;
        if (inst == container_class->generic_container->context.class_inst && !is_tb_open)
                gclass->cached_class = container_class;
 
-       g_hash_table_insert (generic_class_cache, gclass, gclass);
+       g_hash_table_insert (set->gclass_cache, gclass, gclass);
 
        mono_loader_unlock ();
 
@@ -2483,26 +2911,34 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
  * mono_metadata_inflate_generic_inst:
  *
  * Instantiate the generic instance @ginst with the context @context.
+ * Check @error for success.
  *
  */
 MonoGenericInst *
-mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context)
+mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context, MonoError *error)
 {
        MonoType **type_argv;
-       MonoGenericInst *nginst;
-       int i;
+       MonoGenericInst *nginst = NULL;
+       int i, count = 0;
+
+       mono_error_init (error);
 
        if (!ginst->is_open)
                return ginst;
 
        type_argv = g_new0 (MonoType*, ginst->type_argc);
 
-       for (i = 0; i < ginst->type_argc; i++)
-               type_argv [i] = mono_class_inflate_generic_type (ginst->type_argv [i], context);
+       for (i = 0; i < ginst->type_argc; i++) {
+               type_argv [i] = mono_class_inflate_generic_type_checked (ginst->type_argv [i], context, error);
+               if (!mono_error_ok (error))
+                       goto cleanup;
+               ++count;
+       }
 
        nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv);
 
-       for (i = 0; i < ginst->type_argc; i++)
+cleanup:
+       for (i = 0; i < count; i++)
                mono_metadata_free_type (type_argv [i]);
        g_free (type_argv);
 
@@ -2596,7 +3032,7 @@ select_container (MonoGenericContainer *gc, MonoTypeEnum type)
 
 /* 
  * mono_metadata_parse_generic_param:
- * @generic_container: Our MonoClass's or MonoMethodNormal's MonoGenericContainer;
+ * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
  *                     see mono_metadata_parse_type_full() for details.
  * Internal routine to parse a generic type parameter.
  * LOCKING: Acquires the loader lock
@@ -2615,15 +3051,15 @@ mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_c
                MonoGenericParam *param;
 
                param = mono_image_alloc0 (m, sizeof (MonoGenericParam));
-               param->name = mono_image_alloc0 (m, 8);
-               sprintf ((char*)param->name, "%d", index);
                param->num = index;
                param->image = m;
 
                return param;
        }
 
-       g_assert (index < generic_container->type_argc);
+       if (index >= generic_container->type_argc)
+               return NULL;
+
        return mono_generic_container_get_param (generic_container, index);
 }
 
@@ -2664,6 +3100,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
  * 
@@ -2681,7 +3118,7 @@ mono_metadata_get_shared_type (MonoType *type)
  */
 static gboolean
 do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container,
-                            const char *ptr, const char **rptr)
+                                                        gboolean transient, const char *ptr, const char **rptr)
 {
        gboolean ok = TRUE;
        type->type = mono_metadata_decode_value (ptr, &ptr);
@@ -2709,9 +3146,17 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer
        case MONO_TYPE_VALUETYPE:
        case MONO_TYPE_CLASS: {
                guint32 token;
+               MonoClass *class;
                token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
-               type->data.klass = mono_class_get (m, token);
-               if (!type->data.klass)
+               class = mono_class_get (m, token);
+               type->data.klass = class;
+               if (!class)
+                       return FALSE;
+               /* 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;
        }
@@ -2720,30 +3165,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)
@@ -2812,16 +3266,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 */
@@ -2848,11 +3302,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);
@@ -2885,8 +3339,79 @@ parse_section_data (MonoImage *m, MonoMethodHeader *mh, const unsigned char *ptr
                if (sect_data_flags & METHOD_HEADER_SECTION_MORE_SECTS)
                        ptr += sect_data_len - 4; /* LAMESPEC: it seems the size includes the header */
                else
-                       return;
+                       return clauses;
+       }
+}
+
+/*
+ * mono_method_get_header_summary:
+ * @method: The method to get the header.
+ * @summary: Where to store the header
+ *
+ *
+ * Returns: true if the header was properly decoded.
+ */
+gboolean
+mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *summary)
+{
+       int idx;
+       guint32 rva;
+       MonoImage* img;
+       const char *ptr;
+       unsigned char flags, format;
+       guint16 fat_flags;
+
+       /*Only the GMD has a pointer to the metadata.*/
+       while (method->is_inflated)
+               method = ((MonoMethodInflated*)method)->declaring;
+
+       summary->code_size = 0;
+       summary->has_clauses = FALSE;
+
+       /*FIXME extract this into a MACRO and share it with mono_method_get_header*/
+       if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
+               return FALSE;
+
+       if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
+               MonoMethodHeader *header =  ((MonoMethodWrapper *)method)->header;
+               if (!header)
+                       return FALSE;
+               summary->code_size = header->code_size;
+               summary->has_clauses = header->num_clauses > 0;
+               return TRUE;
+       }
+
+
+       idx = mono_metadata_token_index (method->token);
+       img = method->klass->image;
+       rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
+
+       /*We must run the verifier since we'll be decoding it.*/
+       if (!mono_verifier_verify_method_header (img, rva, NULL))
+               return FALSE;
+
+       ptr = mono_image_rva_map (img, rva);
+       g_assert (ptr);
+
+       flags = *(const unsigned char *)ptr;
+       format = flags & METHOD_HEADER_FORMAT_MASK;
+
+       switch (format) {
+       case METHOD_HEADER_TINY_FORMAT:
+               ptr++;
+               summary->code_size = flags >> 2;
+               break;
+       case METHOD_HEADER_FAT_FORMAT:
+               fat_flags = read16 (ptr);
+               ptr += 4;
+               summary->code_size = read32 (ptr);
+               if (fat_flags & METHOD_HEADER_MORE_SECTS)
+                       summary->has_clauses = TRUE;
+               break;
+       default:
+               return FALSE;
        }
+       return TRUE;
 }
 
 /*
@@ -2901,7 +3426,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)
@@ -2912,29 +3437,20 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons
        guint16 fat_flags;
        guint32 local_var_sig_tok, max_stack, code_size, init_locals;
        const unsigned char *code;
-       int hsize;
-       
+       MonoExceptionClause* clauses = NULL;
+       int hsize, num_clauses = 0;
+       MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG];
+       guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
+
        g_return_val_if_fail (ptr != NULL, NULL);
 
        switch (format) {
        case METHOD_HEADER_TINY_FORMAT:
-               mh = mono_image_alloc0 (m, sizeof (MonoMethodHeader));
-               ptr++;
-               mh->max_stack = 8;
-               local_var_sig_tok = 0;
-               mh->code_size = flags >> 2;
-               mh->code = (unsigned char*)ptr;
-               return mh;
-       case METHOD_HEADER_TINY_FORMAT1:
-               mh = mono_image_alloc0 (m, sizeof (MonoMethodHeader));
+               mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER);
                ptr++;
                mh->max_stack = 8;
+               mh->is_transient = TRUE;
                local_var_sig_tok = 0;
-
-               /*
-                * The spec claims 3 bits, but the Beta2 is
-                * incorrect
-                */
                mh->code_size = flags >> 2;
                mh->code = (unsigned char*)ptr;
                return mh;
@@ -2967,38 +3483,54 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons
        default:
                return NULL;
        }
-                      
+
+       if (local_var_sig_tok) {
+               int idx = (local_var_sig_tok & 0xffffff)-1;
+               if (idx >= t->rows || idx < 0)
+                       return NULL;
+               mono_metadata_decode_row (t, idx, cols, 1);
+
+               if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], NULL))
+                       return NULL;
+       }
+       if (fat_flags & METHOD_HEADER_MORE_SECTS)
+               clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr);
        if (local_var_sig_tok) {
-               MonoTableInfo *t = &m->tables [MONO_TABLE_STANDALONESIG];
                const char *locals_ptr;
-               guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
                int len=0, i, bsize;
 
-               mono_metadata_decode_row (t, (local_var_sig_tok & 0xffffff)-1, cols, 1);
                locals_ptr = mono_metadata_blob_heap (m, cols [MONO_STAND_ALONE_SIGNATURE]);
                bsize = mono_metadata_decode_blob_size (locals_ptr, &locals_ptr);
                if (*locals_ptr != 0x07)
                        g_warning ("wrong signature for locals blob");
                locals_ptr++;
                len = mono_metadata_decode_value (locals_ptr, &locals_ptr);
-               mh = mono_image_alloc0 (m, sizeof (MonoMethodHeader) + (len - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType*));
+               mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER + len * sizeof (MonoType*) + num_clauses * sizeof (MonoExceptionClause));
                mh->num_locals = len;
                for (i = 0; i < len; ++i) {
-                       mh->locals [i] = mono_metadata_parse_type_full (
-                               m, container, MONO_PARSE_LOCAL, 0, locals_ptr, &locals_ptr);
+                       mh->locals [i] = mono_metadata_parse_type_internal (m, container,
+                                                                                                                               MONO_PARSE_LOCAL, 0, TRUE, locals_ptr, &locals_ptr);
                        if (!mh->locals [i]) {
+                               g_free (clauses);
+                               g_free (mh);
                                return NULL;
                        }
                }
        } else {
-               mh = mono_image_alloc0 (m, sizeof (MonoMethodHeader));
+               mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause));
        }
        mh->code = code;
        mh->code_size = code_size;
        mh->max_stack = max_stack;
+       mh->is_transient = TRUE;
        mh->init_locals = init_locals;
-       if (fat_flags & METHOD_HEADER_MORE_SECTS)
-               parse_section_data (m, mh, (const unsigned char*)ptr);
+       if (clauses) {
+               MonoExceptionClause* clausesp = (MonoExceptionClause*)&mh->locals [mh->num_locals];
+               memcpy (clausesp, clauses, num_clauses * sizeof (MonoExceptionClause));
+               g_free (clauses);
+               mh->clauses = clausesp;
+               mh->num_clauses = num_clauses;
+       }
        return mh;
 }
 
@@ -3032,12 +3564,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);
+       }
 }
 
 /*
@@ -3362,7 +3903,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;
@@ -3393,7 +3934,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;
@@ -3403,16 +3944,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;
@@ -3451,7 +3996,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) {
@@ -3472,6 +4020,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)
 {
@@ -3479,7 +4041,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;
@@ -3956,11 +4518,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)
@@ -3971,9 +4556,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:
@@ -3989,7 +4585,7 @@ mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2, g
 {
        if (p1 == p2)
                return TRUE;
-       if (p1->num != p2->num)
+       if (mono_generic_param_num (p1) != mono_generic_param_num (p2))
                return FALSE;
 
        /*
@@ -4004,7 +4600,8 @@ mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2, g
         * The AOT runtime doesn't set the image when it's decoding
         * types, so we only compare it when the owner is NULL.
         */
-       if (p1->owner == p2->owner && (p1->owner || p1->image == p2->image))
+       if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2) &&
+           (mono_generic_param_owner (p1) || p1->image == p2->image))
                return TRUE;
 
        /*
@@ -4211,9 +4808,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);
 
@@ -4631,16 +5228,16 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
 
        mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
        ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
-       len = mono_metadata_decode_value (ptr, &ptr);
-
-       type = mono_image_alloc0 (image, sizeof (MonoType));
 
-       if (*ptr == MONO_TYPE_BYREF) {
-               type->byref = 1;
-               ptr++;
+       if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, NULL)) {
+               mono_loader_unlock ();
+               return NULL;
        }
 
-       if (!do_mono_metadata_parse_type (type, image, NULL, ptr, &ptr)) {
+       len = mono_metadata_decode_value (ptr, &ptr);
+
+       type = mono_metadata_parse_type_internal (image, NULL, MONO_PARSE_TYPE, 0, TRUE, ptr, &ptr);
+       if (!type) {
                mono_loader_unlock ();
                return NULL;
        }
@@ -4652,11 +5249,13 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
                return type2;
        }
 
-       g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type);
+       type2 = mono_metadata_type_dup (image, type);
+       g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
+       mono_metadata_free_type (type);
 
        mono_loader_unlock ();
 
-       return type;
+       return type2;
 }
 
 
@@ -4812,7 +5411,17 @@ handle_enum:
                }
                *conv = MONO_MARSHAL_CONV_BOOL_I4;
                return MONO_NATIVE_BOOLEAN;
-       case MONO_TYPE_CHAR: return MONO_NATIVE_U2;
+       case MONO_TYPE_CHAR:
+               if (mspec) {
+                       switch (mspec->native) {
+                       case MONO_NATIVE_U2:
+                       case MONO_NATIVE_U1:
+                               return mspec->native;
+                       default:
+                               g_error ("cant marshal char to native type %02x", mspec->native);
+                       }
+               }
+               return unicode ? MONO_NATIVE_U2 : MONO_NATIVE_U1;
        case MONO_TYPE_I1: return MONO_NATIVE_I1;
        case MONO_TYPE_U1: return MONO_NATIVE_U1;
        case MONO_TYPE_I2: return MONO_NATIVE_I2;
@@ -4974,7 +5583,7 @@ mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
        return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE));
 }
 
-static MonoMethod*
+MonoMethod*
 method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context)
 {
        guint32 idx = tok >> MONO_METHODDEFORREF_BITS;
@@ -5001,6 +5610,7 @@ gboolean
 mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides,
                               MonoGenericContext *generic_context)
 {
+       MonoError error;
        locator_t loc;
        MonoTableInfo *tdef  = &image->tables [MONO_TABLE_METHODIMPL];
        guint32 start, end;
@@ -5045,6 +5655,12 @@ mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod
        for (i = 0; i < num; ++i) {
                MonoMethod *method;
 
+               if (!mono_verifier_verify_methodimpl_row (image, start + i, &error)) {
+                       mono_error_cleanup (&error);
+                       ok = FALSE;
+                       break;
+               }
+
                mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE);
                method = method_from_method_def_or_ref (
                        image, cols [MONO_METHODIMPL_DECLARATION], generic_context);
@@ -5087,7 +5703,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;
@@ -5097,7 +5713,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 */
@@ -5107,11 +5727,11 @@ get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGene
        }
        if (!found)
                return TRUE;
-       res = g_new0 (MonoClass*, found + 1);
+       res = mono_image_alloc0 (image, sizeof (MonoClass*) * (found + 1));
        for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) {
                res [i] = tmp->data;
        }
-       g_list_free (cons);
+       g_slist_free (cons);
        *constraints = res;
        return TRUE;
 }
@@ -5167,22 +5787,42 @@ mono_metadata_has_generic_params (MonoImage *image, guint32 token)
        return mono_metadata_get_generic_param_row (image, token, &owner);
 }
 
+/*
+ * Memory is allocated from IMAGE's mempool.
+ */
+gboolean
+mono_metadata_load_generic_param_constraints_full (MonoImage *image, guint32 token,
+                                             MonoGenericContainer *container)
+{
+
+       guint32 start_row, i, owner;
+       if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner)))
+               return TRUE;
+       for (i = 0; i < container->type_argc; i++) {
+               if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
 /*
  * mono_metadata_load_generic_param_constraints:
  *
+ * @image: metadata context
+ * @token: metadata token to load the contraints, can be methodef or typedef.
+ * @container: generic container to load into.
+ *
  * Load the generic parameter constraints for the newly created generic type or method
  * represented by @token and @container.  The @container is the new container which has
  * been returned by a call to mono_metadata_load_generic_params() with this @token.
+ * Memory is allocated from IMAGE's mempool.
  */
 void
 mono_metadata_load_generic_param_constraints (MonoImage *image, guint32 token,
                                              MonoGenericContainer *container)
 {
-       guint32 start_row, i, owner;
-       if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner)))
-               return;
-       for (i = 0; i < container->type_argc; i++)
-               get_constraints (image, start_row + i, &(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 */
 }
 
 /*
@@ -5209,7 +5849,7 @@ mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericC
        guint32 cols [MONO_GENERICPARAM_SIZE];
        guint32 i, owner = 0, n;
        MonoGenericContainer *container;
-       MonoGenericParam *params;
+       MonoGenericParamFull *params;
        MonoGenericContext *context;
 
        if (!(i = mono_metadata_get_generic_param_row (image, token, &owner)))
@@ -5218,22 +5858,26 @@ mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericC
        params = NULL;
        n = 0;
        container = mono_image_alloc0 (image, sizeof (MonoGenericContainer));
+       container->image = image;
        do {
                n++;
-               params = g_realloc (params, sizeof (MonoGenericParam) * n);
-               memset (&params [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 (&params [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;
 
@@ -5281,43 +5925,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;
 }
 
@@ -5328,12 +6024,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)
 {
@@ -5359,30 +6135,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)
 {