2008-01-17 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata.c
index ce6fafbf46e611e77c9c0d7d15dfcada667031b8..d2737b2709413b55bc44a91e78c8d5165a2f99d3 100644 (file)
@@ -435,6 +435,12 @@ 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
@@ -948,7 +954,10 @@ mono_metadata_decode_row (const MonoTableInfo *t, int idx, guint32 *res, int res
 {
        guint32 bitfield = t->size_bitfield;
        int i, count = mono_metadata_table_count (bitfield);
-       const char *data = t->base + idx * t->row_size;
+       const char *data;
+
+       g_assert (idx < t->rows);
+       data = t->base + idx * t->row_size;
        
        g_assert (res_size == count);
        
@@ -983,10 +992,12 @@ mono_metadata_decode_row_col (const MonoTableInfo *t, int idx, guint col)
 {
        guint32 bitfield = t->size_bitfield;
        int i;
-       register const char *data = t->base + idx * t->row_size;
+       register const char *data
        register int n;
        
+       g_assert (idx < t->rows);
        g_assert (col < mono_metadata_table_count (bitfield));
+       data = t->base + idx * t->row_size;
 
        n = mono_metadata_table_size (bitfield, 0);
        for (i = 0; i < col; ++i) {
@@ -1353,6 +1364,12 @@ static int next_generic_inst_id = 0;
  */
 static GHashTable *generic_method_cache = NULL;
 
+/*
+ * Protected by the loader lock.
+ * It has a MonoInflatedMethodSignature* as key and value.
+ */
+static GHashTable *generic_signature_cache = NULL;
+
 static guint mono_generic_class_hash (gconstpointer data);
 
 /*
@@ -1396,21 +1413,35 @@ mono_generic_inst_hash (gconstpointer data)
 }
 
 static gboolean
-mono_generic_inst_equal (gconstpointer ka, gconstpointer kb)
+mono_generic_inst_equal_full (const MonoGenericInst *a, const MonoGenericInst *b, gboolean signature_only)
 {
-       const MonoGenericInst *a = (const MonoGenericInst *) ka;
-       const MonoGenericInst *b = (const MonoGenericInst *) kb;
        int i;
 
+       if (a->id && b->id) {
+               if (a->id == b->id)
+                       return TRUE;
+               if (!signature_only)
+                       return FALSE;
+       }
+
        if (a->is_open != b->is_open || a->type_argc != b->type_argc)
                return FALSE;
        for (i = 0; i < a->type_argc; ++i) {
-               if (!do_mono_metadata_type_equal (a->type_argv [i], b->type_argv [i], FALSE))
+               if (!do_mono_metadata_type_equal (a->type_argv [i], b->type_argv [i], signature_only))
                        return FALSE;
        }
        return TRUE;
 }
 
+static gboolean
+mono_generic_inst_equal (gconstpointer ka, gconstpointer kb)
+{
+       const MonoGenericInst *a = (const MonoGenericInst *) ka;
+       const MonoGenericInst *b = (const MonoGenericInst *) kb;
+
+       return mono_generic_inst_equal_full (a, b, FALSE);
+}
+
 static guint
 mono_generic_class_hash (gconstpointer data)
 {
@@ -1418,6 +1449,7 @@ mono_generic_class_hash (gconstpointer data)
        guint hash = mono_metadata_type_hash (&gclass->container_class->byval_arg);
 
        hash *= 13;
+       hash += gclass->is_tb_open;
        hash += mono_metadata_generic_context_hash (&gclass->context);
 
        return hash;
@@ -1465,10 +1497,13 @@ mono_metadata_cleanup (void)
        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;
 }
 
 /**
@@ -1903,6 +1938,21 @@ mono_metadata_free_method_signature (MonoMethodSignature *sig)
        */
 }
 
+void
+mono_metadata_free_inflated_signature (MonoMethodSignature *sig)
+{
+       int i;
+
+       /* Allocated in inflate_generic_signature () */
+       if (sig->ret)
+               mono_metadata_free_type (sig->ret);
+       for (i = 0; i < sig->param_count; ++i) {
+               if (sig->params [i])
+                       mono_metadata_free_type (sig->params [i]);
+       }
+       g_free (sig);
+}
+
 static gboolean
 inflated_method_equal (gconstpointer a, gconstpointer b)
 {
@@ -1920,6 +1970,28 @@ inflated_method_hash (gconstpointer a)
        return mono_metadata_generic_context_hash (&ma->context) ^ mono_aligned_addr_hash (ma->declaring);
 }
 
+static gboolean
+inflated_signature_equal (gconstpointer a, gconstpointer b)
+{
+       const MonoInflatedMethodSignature *sig1 = a;
+       const MonoInflatedMethodSignature *sig2 = b;
+
+       /* sig->sig is assumed to be canonized */
+       if (sig1->sig != sig2->sig)
+               return FALSE;
+       /* The generic instances are canonized */
+       return mono_metadata_generic_context_equal (&sig1->context, &sig2->context);
+}
+
+static guint
+inflated_signature_hash (gconstpointer a)
+{
+       const MonoInflatedMethodSignature *sig = a;
+
+       /* sig->sig is assumed to be canonized */
+       return mono_metadata_generic_context_hash (&sig->context) ^ mono_aligned_addr_hash (sig->sig);
+}
+
 /*static void
 dump_ginst (MonoGenericInst *ginst)
 {
@@ -1937,127 +2009,160 @@ dump_ginst (MonoGenericInst *ginst)
        g_print (">");
 }*/
 
-static gboolean gclass_in_image (gpointer key, gpointer value, gpointer data);
+static gboolean type_in_image (MonoType *type, MonoImage *image);
 
-typedef struct {
-       MonoImage *image;
-       GSList *ginst_list;
-       GSList *gclass_list;
-} CleanForImageUserData;
+static gboolean
+signature_in_image (MonoMethodSignature *sig, MonoImage *image)
+{
+       gpointer iter = NULL;
+       MonoType *p;
+
+       while ((p = mono_signature_get_params (sig, &iter)) != NULL)
+               if (type_in_image (p, image))
+                       return TRUE;
+
+       return type_in_image (mono_signature_get_return_type (sig), image);
+}
 
 static gboolean
-ginst_in_image (gpointer key, gpointer value, gpointer data)
+ginst_in_image (MonoGenericInst *ginst, MonoImage *image)
 {
-       CleanForImageUserData *user_data = (CleanForImageUserData*)data;
-       MonoImage *image = user_data->image;
-       MonoGenericInst *ginst = key;
-       MonoClass *klass;
        int i;
-       for (i = 0; i < ginst->type_argc; ++i) {
-               MonoType *type = ginst->type_argv [i];
-
-               /* FIXME: Avoid a possible mono_class_inst inside mono_class_from_mono_type */
-               if (type->type == MONO_TYPE_GENERICINST) {
-                       if (gclass_in_image (type->data.generic_class, NULL, data)) {
-                               if (!g_slist_find (user_data->ginst_list, ginst))
-                                       user_data->ginst_list = g_slist_append (user_data->ginst_list, ginst);
-                               return TRUE;
-                       }
-                       continue;
-               }
 
-               klass = mono_class_from_mono_type (ginst->type_argv [i]);
-               if (klass->image == image) {
-                       /*dump_ginst (ginst);
-                         g_print (" removed\n");*/
-                       if (!g_slist_find (user_data->ginst_list, ginst))
-                               user_data->ginst_list = g_slist_append (user_data->ginst_list, ginst);
+       for (i = 0; i < ginst->type_argc; ++i) {
+               if (type_in_image (ginst->type_argv [i], image))
                        return TRUE;
-               }
        }
+
        return FALSE;
 }
 
 static gboolean
-gclass_in_image (gpointer key, gpointer value, gpointer data)
+gclass_in_image (MonoGenericClass *gclass, MonoImage *image)
+{
+       return gclass->container_class->image == image ||
+               ginst_in_image (gclass->context.class_inst, image);
+}
+
+static gboolean
+type_in_image (MonoType *type, MonoImage *image)
+{
+retry:
+       switch (type->type) {
+       case MONO_TYPE_GENERICINST:
+               return gclass_in_image (type->data.generic_class, image);
+       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);
+       case MONO_TYPE_VAR:
+               if (type->data.generic_param->owner) {
+                       g_assert (!type->data.generic_param->owner->is_method);
+                       return type->data.generic_param->owner->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)
+                               /* RefEmit created generic param whose method is not finished */
+                               return FALSE;
+                       return type->data.generic_param->owner->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;
+       }
+}
+
+typedef struct {
+       MonoImage *image;
+       GSList *list;
+} CleanForImageUserData;
+
+static gboolean
+steal_gclass_in_image (gpointer key, gpointer value, gpointer data)
 {
-       CleanForImageUserData *user_data = (CleanForImageUserData*)data;
-       MonoImage *image = user_data->image;
        MonoGenericClass *gclass = key;
-       gboolean match = FALSE;
+       CleanForImageUserData *user_data = data;
 
-       if (ginst_in_image (gclass->context.class_inst, NULL, data))
-               match = TRUE;
-       if (gclass->container_class->image == image)
-               match = TRUE;
+       if (!gclass_in_image (gclass, user_data->image))
+               return FALSE;
 
-       if (match) {
-               if (!g_slist_find (user_data->gclass_list, gclass))
-                       user_data->gclass_list = g_slist_append (user_data->gclass_list, gclass);
-               return TRUE;
-       } else {
+       user_data->list = g_slist_prepend (user_data->list, gclass);
+       return TRUE;
+}
+
+static gboolean
+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;
-       }
+
+       user_data->list = g_slist_prepend (user_data->list, ginst);
+       return TRUE;
 }
 
 static gboolean
 inflated_method_in_image (gpointer key, gpointer value, gpointer data)
 {
-       CleanForImageUserData *user_data = (CleanForImageUserData*)data;
-       MonoImage *image = user_data->image;
+       MonoImage *image = data;
        MonoMethodInflated *method = key;
 
-       if (method->declaring->klass->image == image)
-               return TRUE;
-       if (method->context.class_inst && ginst_in_image (method->context.class_inst, NULL, data))
-               return TRUE;
-       if (method->context.method_inst && ginst_in_image (method->context.method_inst, NULL, data))
-               return TRUE;
-       return FALSE;
+       return 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));
 }
 
-/*
- * LOCKING: assumes the loader lock is held.
- */
-MonoMethodInflated*
-mono_method_inflated_lookup (MonoMethodInflated* method, gboolean cache)
+static gboolean
+inflated_signature_in_image (gpointer key, gpointer value, gpointer 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);
-               return method;
-       } else {
-               if (generic_method_cache)
-                       return g_hash_table_lookup (generic_method_cache, method);
-               return NULL;
-       }
-}
+       MonoImage *image = data;
+       MonoInflatedMethodSignature *sig = key;
+
+       return /* signature_in_image (sig->sig, image) || */
+               (sig->context.class_inst && ginst_in_image (sig->context.class_inst, image)) ||
+               (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image));
+}      
 
 void
 mono_metadata_clean_for_image (MonoImage *image)
 {
-       CleanForImageUserData user_data;
+       CleanForImageUserData ginst_data, gclass_data;
        GSList *l;
 
        /* The data structures could reference each other so we delete them in two phases */
-       user_data.image = image;
-       user_data.ginst_list = NULL;
-       user_data.gclass_list = NULL;
+       ginst_data.image = gclass_data.image = image;
+       ginst_data.list = gclass_data.list = NULL;
 
        mono_loader_lock ();    
        /* Collect the items to delete and remove them from the hash table */
-       g_hash_table_foreach_steal (generic_inst_cache, ginst_in_image, &user_data);
-       g_hash_table_foreach_steal (generic_class_cache, gclass_in_image, &user_data);
+       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, &user_data);
+               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 = user_data.ginst_list; l; l = l->next)
+       for (l = ginst_data.list; l; l = l->next)
                free_generic_inst (l->data);
-       for (l = user_data.gclass_list; l; l = l->next)
+       for (l = gclass_data.list; l; l = l->next)
                free_generic_class (l->data);
-       g_slist_free (user_data.ginst_list);
-       g_slist_free (user_data.gclass_list);
+       g_slist_free (ginst_data.list);
+       g_slist_free (gclass_data.list);
        mono_loader_unlock ();
 }
 
@@ -2067,17 +2172,8 @@ free_inflated_method (MonoMethodInflated *imethod)
        int i;
        MonoMethod *method = (MonoMethod*)imethod;
 
-       if (method->signature) {
-               MonoMethodSignature *sig = method->signature;
-
-               /* Allocated in inflate_generic_signature () */
-               mono_metadata_free_type (sig->ret);
-               for (i = 0; i < sig->param_count; ++i)
-                       mono_metadata_free_type (sig->params [i]);
-
-               /* FIXME: The signature is allocated from a mempool */
-               //g_free (method->signature);
-       }
+       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;
@@ -2110,14 +2206,86 @@ free_generic_inst (MonoGenericInst *ginst)
 static void
 free_generic_class (MonoGenericClass *gclass)
 {
-       if (gclass->cached_class) {
+       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);
+               g_free (class->properties);
+               /* Allocated in mono_class_setup_fields () */
+               if (class->fields) {
+                       for (i = 0; i < class->field.count; ++i) {
+                               g_free (class->fields [i].generic_info);
+                               mono_metadata_free_type (class->fields [i].type);
+                       }
+               }
                /* Allocated in mono_generic_class_get_class () */
-               g_free (gclass->cached_class->interfaces);
-               g_free (gclass->cached_class);
+               g_free (class->interfaces);
+               g_free (class);
        }               
        g_free (gclass);
 }
 
+static void
+free_inflated_signature (MonoInflatedMethodSignature *sig)
+{
+       mono_metadata_free_inflated_signature (sig->sig);
+       g_free (sig);
+}
+
+/*
+ * LOCKING: assumes the loader lock is held.
+ */
+MonoMethodInflated*
+mono_method_inflated_lookup (MonoMethodInflated* method, gboolean cache)
+{
+       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);
+               return method;
+       } else {
+               if (generic_method_cache)
+                       return g_hash_table_lookup (generic_method_cache, method);
+               return NULL;
+       }
+}
+
+/*
+ * mono_metadata_get_inflated_signature:
+ *
+ *   Given an inflated signature and a generic context, return a canonical copy of the 
+ * signature. The returned signature might be equal to SIG or it might be a cached copy.
+ */
+MonoMethodSignature *
+mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericContext *context)
+{
+       MonoInflatedMethodSignature helper;
+       MonoInflatedMethodSignature *res;
+
+       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);
+       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);
+       }
+
+       mono_loader_unlock ();
+       return res->sig;
+}
+
 /*
  * mono_metadata_get_generic_inst:
  *
@@ -2167,6 +2335,16 @@ mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
        return ginst;
 }
 
+static gboolean
+mono_metadata_is_type_builder_generic_type_definition (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
+{
+       MonoGenericContainer *container = container_class->generic_container; 
+
+       if (!is_dynamic || container_class->wastypebuilder || container->type_argc != inst->type_argc)
+               return FALSE;
+       return inst == container->context.class_inst;
+}
+
 /*
  * mono_metadata_lookup_generic_class:
  *
@@ -2177,12 +2355,14 @@ MonoGenericClass *
 mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
 {
        MonoGenericClass *gclass;
-
        MonoGenericClass helper;
+       gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic);
+
        helper.container_class = container_class;
        helper.context.class_inst = inst;
        helper.context.method_inst = NULL;
        helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
+       helper.is_tb_open = is_tb_open;
        helper.cached_class = NULL;
 
        mono_loader_lock ();
@@ -2205,9 +2385,12 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
                gclass = g_new0 (MonoGenericClass, 1);
        }
 
+       gclass->is_tb_open = is_tb_open;
        gclass->container_class = container_class;
        gclass->context.class_inst = inst;
        gclass->context.method_inst = NULL;
+       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);
 
@@ -2336,6 +2519,7 @@ select_container (MonoGenericContainer *gc, MonoTypeEnum type)
  * @generic_container: Our MonoClass's or MonoMethodNormal's MonoGenericContainer;
  *                     see mono_metadata_parse_type_full() for details.
  * Internal routine to parse a generic type parameter.
+ * LOCKING: Assumes the loader lock is held.
  */
 static MonoGenericParam *
 mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_container,
@@ -2348,9 +2532,11 @@ mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_c
        generic_container = select_container (generic_container, type);
        if (!generic_container) {
                /* Create dummy MonoGenericParam */
-               MonoGenericParam *param = g_new0 (MonoGenericParam, 1);
-               param->name = g_strdup_printf ("%d", index);
+               MonoGenericParam *param = mono_mempool_alloc0 (m->mempool, sizeof (MonoGenericParam));
+               param->name = mono_mempool_alloc0 (m->mempool, 8);
+               sprintf ((char*)param->name, "%d", index);
                param->num = index;
+               param->image = m;
 
                return param;
        }
@@ -3490,6 +3676,12 @@ mono_type_size (MonoType *t, int *align)
  */
 int
 mono_type_stack_size (MonoType *t, int *align)
+{
+       return mono_type_stack_size_internal (t, align, FALSE);
+}
+
+int
+mono_type_stack_size_internal (MonoType *t, int *align, gboolean allow_open)
 {
        int tmp;
 
@@ -3540,7 +3732,7 @@ mono_type_stack_size (MonoType *t, int *align)
                guint32 size;
 
                if (t->data.klass->enumtype)
-                       return mono_type_stack_size (t->data.klass->enum_basetype, align);
+                       return mono_type_stack_size_internal (t->data.klass->enum_basetype, align, allow_open);
                else {
                        size = mono_class_value_size (t->data.klass, (guint32*)align);
 
@@ -3557,11 +3749,12 @@ mono_type_stack_size (MonoType *t, int *align)
                MonoGenericClass *gclass = t->data.generic_class;
                MonoClass *container_class = gclass->container_class;
 
-               g_assert (!gclass->context.class_inst->is_open);
+               if (!allow_open)
+                       g_assert (!gclass->context.class_inst->is_open);
 
                if (container_class->valuetype) {
                        if (container_class->enumtype)
-                               return mono_type_stack_size (container_class->enum_basetype, align);
+                               return mono_type_stack_size_internal (container_class->enum_basetype, align, allow_open);
                        else {
                                guint32 size = mono_class_value_size (mono_class_from_mono_type (t), (guint32*)align);
 
@@ -3600,19 +3793,29 @@ mono_metadata_generic_class_is_valuetype (MonoGenericClass *gclass)
 static gboolean
 _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
 {
-       int i;
        MonoGenericInst *i1 = g1->context.class_inst;
        MonoGenericInst *i2 = g2->context.class_inst;
 
-       if (i1->type_argc != i2->type_argc || g1->is_dynamic != g2->is_dynamic)
+       if (g1->is_dynamic != g2->is_dynamic)
                return FALSE;
        if (!mono_metadata_class_equal (g1->container_class, g2->container_class, signature_only))
                return FALSE;
-       for (i = 0; i < i1->type_argc; ++i) {
-               if (!do_mono_metadata_type_equal (i1->type_argv [i], i2->type_argv [i], signature_only))
-                       return FALSE;
-       }
-       return TRUE;
+       if (!mono_generic_inst_equal_full (i1, i2, signature_only))
+               return FALSE;
+       return g1->is_tb_open == g2->is_tb_open;
+}
+
+static gboolean
+_mono_metadata_generic_class_container_equal (const MonoGenericClass *g1, MonoClass *c2, gboolean signature_only)
+{
+       MonoGenericInst *i1 = g1->context.class_inst;
+       MonoGenericInst *i2 = c2->generic_container->context.class_inst;
+
+       if (!mono_metadata_class_equal (g1->container_class, c2, signature_only))
+               return FALSE;
+       if (!mono_generic_inst_equal_full (i1, i2, signature_only))
+               return FALSE;
+       return !g1->is_tb_open;
 }
 
 guint
@@ -3687,6 +3890,10 @@ mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only
                return TRUE;
        if (c1->generic_class && c2->generic_class)
                return _mono_metadata_generic_class_equal (c1->generic_class, c2->generic_class, signature_only);
+       if (c1->generic_class && c2->generic_container)
+               return _mono_metadata_generic_class_container_equal (c1->generic_class, c2, signature_only);
+       if (c1->generic_container && c2->generic_class)
+               return _mono_metadata_generic_class_container_equal (c2->generic_class, c1, signature_only);
        if ((c1->byval_arg.type == MONO_TYPE_VAR) && (c2->byval_arg.type == MONO_TYPE_VAR))
                return mono_metadata_generic_param_equal (
                        c1->byval_arg.data.generic_param, c2->byval_arg.data.generic_param, signature_only);
@@ -3799,6 +4006,23 @@ mono_metadata_type_equal (MonoType *t1, MonoType *t2)
        return do_mono_metadata_type_equal (t1, t2, FALSE);
 }
 
+/**
+ * mono_metadata_type_equal_full:
+ * @t1: a type
+ * @t2: another type
+ * @signature_only: if signature only comparison should be made
+ *
+ * Determine if @t1 and @t2 are signature compatible if @signature_only is #TRUE, otherwise
+ * behaves the same way as mono_metadata_type_equal.
+ * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
+ * Returns: #TRUE if @t1 and @t2 are equal taking @signature_only into account.
+ */
+gboolean
+mono_metadata_type_equal_full (MonoType *t1, MonoType *t2, gboolean signature_only)
+{
+       return do_mono_metadata_type_equal (t1, t2, signature_only);
+}
+
 /**
  * mono_metadata_signature_equal:
  * @sig1: a signature
@@ -4268,7 +4492,7 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
        ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
        len = mono_metadata_decode_value (ptr, &ptr);
 
-       type = g_new0 (MonoType, 1);
+       type = mono_mempool_alloc0 (image->mempool, sizeof (MonoType));
 
        if (*ptr == MONO_TYPE_BYREF) {
                type->byref = 1;
@@ -4276,7 +4500,6 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
        }
 
        if (!do_mono_metadata_parse_type (type, image, NULL, ptr, &ptr)) {
-               g_free (type);
                mono_loader_unlock ();
                return NULL;
        }
@@ -4284,7 +4507,6 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
        type2 = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
 
        if (type2) {
-               g_free (type);
                mono_loader_unlock ();
                return type2;
        }
@@ -4810,6 +5032,8 @@ mono_metadata_load_generic_param_constraints (MonoImage *image, guint32 token,
  *
  * Returns: NULL if @token is not a generic type or method definition or the new generic container.
  *
+ * LOCKING: Assumes the loader lock is held.
+ *
  */
 MonoGenericContainer *
 mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container)
@@ -4826,7 +5050,7 @@ mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericC
        mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
        params = NULL;
        n = 0;
-       container = g_new0 (MonoGenericContainer, 1);
+       container = mono_mempool_alloc0 (image->mempool, sizeof (MonoGenericContainer));
        do {
                n++;
                params = g_realloc (params, sizeof (MonoGenericParam) * n);
@@ -4842,7 +5066,9 @@ mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericC
        } while (cols [MONO_GENERICPARAM_OWNER] == owner);
 
        container->type_argc = n;
-       container->type_params = params;
+       container->type_params = mono_mempool_alloc0 (image->mempool, sizeof (MonoGenericParam) * n);
+       memcpy (container->type_params, params, sizeof (MonoGenericParam) * n);
+       g_free (params);
        container->parent = parent_container;
 
        if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)