Fix crash on 'make run-test' in mcs/errors
[mono.git] / mono / metadata / metadata.c
index c2a2563790e8a72f9d5a1ed910b2acb97b502aeb..7c67e451efa6c46ed9ed95b866175a866056ce5f 100644 (file)
@@ -30,6 +30,9 @@ static gboolean mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolea
 static gboolean mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only);
 static gboolean _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2,
                                                    gboolean signature_only);
+static void free_generic_inst (MonoGenericInst *ginst);
+static void free_generic_class (MonoGenericClass *ginst);
+static void free_inflated_method (MonoMethodInflated *method);
 
 /*
  * This enumeration is used to describe the data types in the metadata
@@ -432,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
@@ -921,13 +930,13 @@ mono_metadata_guid_heap (MonoImage *meta, guint32 index)
        return meta->heap_guid.data + index;
 }
 
-static const char *
-dword_align (const char *ptr)
+static const unsigned char *
+dword_align (const unsigned char *ptr)
 {
 #if SIZEOF_VOID_P == 8
-       return (const char *) (((guint64) (ptr + 3)) & ~3);
+       return (const unsigned char *) (((guint64) (ptr + 3)) & ~3);
 #else
-       return (const char *) (((guint32) (ptr + 3)) & ~3);
+       return (const unsigned char *) (((guint32) (ptr + 3)) & ~3);
 #endif
 }
 
@@ -1032,7 +1041,7 @@ mono_metadata_decode_blob_size (const char *xptr, const char **rptr)
                ptr += 4;
        }
        if (rptr)
-               *rptr = ptr;
+               *rptr = (char*)ptr;
        return size;
 }
 
@@ -1067,7 +1076,7 @@ mono_metadata_decode_value (const char *_ptr, const char **rptr)
                ptr += 4;
        }
        if (rptr)
-               *rptr = ptr;
+               *rptr = (char*)ptr;
        
        return len;
 }
@@ -1225,7 +1234,7 @@ mono_metadata_parse_custom_mod (MonoImage *m, MonoCustomMod *dest, const char *p
 }
 
 /*
- * mono_metadata_parse_array:
+ * mono_metadata_parse_array_full:
  * @m: a metadata context.
  * @ptr: a pointer to an encoded array description.
  * @rptr: pointer updated to match the end of the decoded stream
@@ -1233,14 +1242,16 @@ mono_metadata_parse_custom_mod (MonoImage *m, MonoCustomMod *dest, const char *p
  * Decodes the compressed array description found in the metadata @m at @ptr.
  *
  * Returns: a #MonoArrayType structure describing the array type
- * and dimensions.
+ * and dimensions. Memory is allocated from the image mempool.
+ *
+ * LOCKING: Assumes the loader lock is held.
  */
 MonoArrayType *
 mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container,
                                const char *ptr, const char **rptr)
 {
        int i;
-       MonoArrayType *array = g_new0 (MonoArrayType, 1);
+       MonoArrayType *array = mono_mempool_alloc0 (m->mempool, sizeof (MonoArrayType));
        MonoType *etype;
        
        etype = mono_metadata_parse_type_full (m, container, MONO_PARSE_TYPE, 0, ptr, &ptr);
@@ -1341,6 +1352,19 @@ static GHashTable *generic_inst_cache = NULL;
 static GHashTable *generic_class_cache = NULL;
 static int next_generic_inst_id = 0;
 
+/*
+ * Protected by the loader lock.
+ * It has a MonoMethodInflated* as key and value.
+ * The key lookup will just access the declaring and context fields
+ */
+static GHashTable *generic_method_cache = NULL;
+
+/*
+ * Protected by the loader lock.
+ * It has a MonoInflatedMethodSignature* as key and value.
+ */
+static GHashTable *generic_signature_cache = NULL;
+
 static guint mono_generic_class_hash (gconstpointer data);
 
 /*
@@ -1390,7 +1414,7 @@ mono_generic_inst_equal (gconstpointer ka, gconstpointer kb)
        const MonoGenericInst *b = (const MonoGenericInst *) kb;
        int i;
 
-       if ((a->is_open != b->is_open) || (a->type_argc != b->type_argc) || (a->is_reference != b->is_reference))
+       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))
@@ -1406,7 +1430,7 @@ mono_generic_class_hash (gconstpointer data)
        guint hash = mono_metadata_type_hash (&gclass->container_class->byval_arg);
 
        hash *= 13;
-       hash += mono_generic_inst_hash (gclass->inst);
+       hash += mono_metadata_generic_context_hash (&gclass->context);
 
        return hash;
 }
@@ -1432,8 +1456,8 @@ 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 (mono_generic_inst_hash, mono_generic_inst_equal);
-       generic_class_cache = g_hash_table_new (mono_generic_class_hash, mono_generic_class_equal);
+       generic_inst_cache = g_hash_table_new_full (mono_generic_inst_hash, mono_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]);
@@ -1451,6 +1475,15 @@ 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;
 }
 
 /**
@@ -1474,7 +1507,7 @@ mono_metadata_cleanup (void)
  * this MonoGenericContainer.
  * This is a Mono runtime internal function.
  *
- * LOCKING: Assumes the loader lock is held.
+ * LOCKING: Acquires the loader lock.
  *
  * Returns: a #MonoType structure representing the decoded type.
  */
@@ -1560,8 +1593,6 @@ mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, Mo
        type->pinned = pinned ? 1 : 0;
 
        if (!do_mono_metadata_parse_type (type, m, container, ptr, &ptr)) {
-               if (type != &stype)
-                       g_free (type);
                mono_loader_unlock ();
                return NULL;
        }
@@ -1569,7 +1600,7 @@ mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, Mo
        if (rptr)
                *rptr = ptr;
 
-               if (!type->num_mods) {
+       if (!type->num_mods) {
                /* 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;
@@ -1678,7 +1709,7 @@ mono_metadata_parse_signature_full (MonoImage *image, MonoGenericContainer *gene
        const char *ptr;
 
        if (image->dynamic)
-               return mono_lookup_dynamic_token (image, token);
+               return mono_lookup_dynamic_token (image, token, NULL);
 
        g_assert (mono_metadata_token_table(token) == MONO_TABLE_STANDALONESIG);
                
@@ -1874,71 +1905,448 @@ mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, co
  */
 void
 mono_metadata_free_method_signature (MonoMethodSignature *sig)
+{
+       /* Everything is allocated from mempools */
+       /*
+       int i;
+       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]);
+       }
+       */
+}
+
+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]);
        }
+       /* FIXME: The signature is allocated from a mempool */
+       //g_free (sig);
+}
+
+static gboolean
+inflated_method_equal (gconstpointer a, gconstpointer b)
+{
+       const MonoMethodInflated *ma = a;
+       const MonoMethodInflated *mb = b;
+       if (ma->declaring != mb->declaring)
+               return FALSE;
+       return mono_metadata_generic_context_equal (&ma->context, &mb->context);
+}
+
+static guint
+inflated_method_hash (gconstpointer a)
+{
+       const MonoMethodInflated *ma = 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)
+{
+       int i;
+       char *name;
+
+       g_print ("Ginst: <");
+       for (i = 0; i < ginst->type_argc; ++i) {
+               if (i != 0)
+                       g_print (", ");
+               name = mono_type_get_name (ginst->type_argv [i]);
+               g_print ("%s", name);
+               g_free (name);
+       }
+       g_print (">");
+}*/
+
+static gboolean gclass_in_image (gpointer key, gpointer value, gpointer data);
+
+typedef struct {
+       MonoImage *image;
+       GSList *ginst_list;
+       GSList *gclass_list;
+} CleanForImageUserData;
+
+static gboolean
+type_in_image (MonoType *type, CleanForImageUserData *user_data)
+{
+       MonoClass *klass;
+
+       /* Avoid allocations.  We just want _some_ MonoClass reachable from @type.  */
+retry:
+       switch (type->type) {
+       case MONO_TYPE_GENERICINST:
+               return gclass_in_image (type->data.generic_class, NULL, user_data);
+       case MONO_TYPE_PTR:
+               type = type->data.type;
+               goto retry;
+       case MONO_TYPE_SZARRAY:
+               klass = type->data.klass;
+               break;
+       case MONO_TYPE_ARRAY:
+               klass = type->data.array->eklass;
+               break;
+       case MONO_TYPE_FNPTR: {
+               gpointer iter = NULL;
+               MonoMethodSignature *sig = type->data.method;
+               MonoType *p;
+               if (type_in_image (mono_signature_get_return_type (sig), user_data))
+                       return TRUE;
+               while ((p = mono_signature_get_params (sig, &iter)) != NULL)
+                       if (type_in_image (p, user_data))
+                               return TRUE;
+               return FALSE;
+       }
+       default:
+               /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type () */
+               klass = mono_class_from_mono_type (type);
+               break;
+       }
+
+       return klass->image == user_data->image;
+}
+
+static gboolean
+ginst_in_image (gpointer key, gpointer value, gpointer data)
+{
+       CleanForImageUserData *user_data = data;
+       MonoGenericInst *ginst = key;
+       int i;
+
+       for (i = 0; i < ginst->type_argc; ++i) {
+               if (type_in_image (ginst->type_argv [i], user_data))
+                       break;
+       }
+
+       if (i == ginst->type_argc)
+               return FALSE;
+
+       if (!g_slist_find (user_data->ginst_list, ginst))
+               user_data->ginst_list = g_slist_append (user_data->ginst_list, ginst);
+
+       return TRUE;
+}
+
+static gboolean
+gclass_in_image (gpointer key, gpointer value, gpointer data)
+{
+       CleanForImageUserData *user_data = data;
+       MonoGenericClass *gclass = key;
+
+       if (gclass->container_class->image != user_data->image &&
+           !ginst_in_image (gclass->context.class_inst, NULL, data))
+               return FALSE;
+
+       if (!g_slist_find (user_data->gclass_list, gclass))
+               user_data->gclass_list = g_slist_append (user_data->gclass_list, gclass);
+
+       return TRUE;
+}
+
+static gboolean
+inflated_method_in_image (gpointer key, gpointer value, gpointer data)
+{
+       CleanForImageUserData *user_data = (CleanForImageUserData*)data;
+       MonoImage *image = user_data->image;
+       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;
+}
+
+static gboolean
+inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
+{
+       MonoInflatedMethodSignature *sig = key;
+
+       if (sig->context.class_inst && ginst_in_image (sig->context.class_inst, NULL, data))
+               return TRUE;
+       if (sig->context.method_inst && ginst_in_image (sig->context.method_inst, NULL, data))
+               return TRUE;
+       return FALSE;
+}      
+
+void
+mono_metadata_clean_for_image (MonoImage *image)
+{
+       CleanForImageUserData user_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;
+
+       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);
+       if (generic_method_cache)
+               g_hash_table_foreach_remove (generic_method_cache, inflated_method_in_image, &user_data);
+       if (generic_signature_cache)
+               g_hash_table_foreach_remove (generic_signature_cache, inflated_signature_in_image, &user_data);
+       /* Delete the removed items */
+       for (l = user_data.ginst_list; l; l = l->next)
+               free_generic_inst (l->data);
+       for (l = user_data.gclass_list; l; l = l->next)
+               free_generic_class (l->data);
+       g_slist_free (user_data.ginst_list);
+       g_slist_free (user_data.gclass_list);
+       mono_loader_unlock ();
+}
+
+static void
+free_inflated_method (MonoMethodInflated *imethod)
+{
+       int i;
+       MonoMethod *method = (MonoMethod*)imethod;
+
+       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;
+
+               if (header) {
+                       /* Allocated in inflate_generic_header () */
+                       for (i = 0; i < header->num_locals; ++i)
+                               mono_metadata_free_type (header->locals [i]);
+                       g_free (header->clauses);
+                       g_free (header);
+               }
+       }
+
+       g_free (method);
+}
+
+static void
+free_generic_inst (MonoGenericInst *ginst)
+{
+       int i;
+
+       for (i = 0; i < ginst->type_argc; ++i)
+               mono_metadata_free_type (ginst->type_argv [i]);
+       g_free (ginst->type_argv);
+       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) {
+               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 (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);
 }
 
 /*
- * mono_metadata_lookup_generic_inst:
+ * 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:
  *
- * Check whether the newly created generic instantiation @ginst already exists
- * in the cache and return the cached value in this case.  Otherwise insert
- * it into the cache.
+ *   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:
  *
- * Use this method each time you create a new `MonoGenericInst' to ensure
- * proper caching.  Only use the returned value as the argument passed to this
- * method may be freed.
+ * Given a list of types, return a MonoGenericInst that represents that list.
+ * The returned MonoGenericInst has its own copy of the list of types.  The list
+ * passed in the argument can be freed, modified or disposed of.
  *
  */
 MonoGenericInst *
-mono_metadata_lookup_generic_inst (MonoGenericInst *ginst)
+mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
 {
-       MonoGenericInst *cached;
+       MonoGenericInst *ginst;
+       MonoGenericInst helper;
        int i;
 
-       cached = g_hash_table_lookup (generic_inst_cache, ginst);
-       if (cached) {
-               for (i = 0; i < ginst->type_argc; i++)
-                       mono_metadata_free_type (ginst->type_argv [i]);
-               g_free (ginst->type_argv);
-               g_free (ginst);
-               return cached;
+       helper.type_argc = type_argc;
+       helper.type_argv = type_argv;
+       helper.id = 0;
+
+       for (i = 0; i < type_argc; ++i)
+               if (mono_class_is_open_constructed_type (type_argv [i]))
+                       break;
+       helper.is_open = (i < type_argc);
+
+       /*dump_ginst (&helper);*/
+       mono_loader_lock ();
+       ginst = g_hash_table_lookup (generic_inst_cache, &helper);
+       if (ginst) {
+               mono_loader_unlock ();
+               /*g_print (" found cached\n");*/
+               return ginst;
        }
 
+       ginst = g_new0 (MonoGenericInst, 1);
+       ginst->type_argc = type_argc;
+       ginst->type_argv = g_new (MonoType*, type_argc);
        ginst->id = ++next_generic_inst_id;
+       ginst->is_open = helper.is_open;
+
+       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);
 
+       mono_loader_unlock ();
+       /*g_print (" inserted\n");*/
        return ginst;
 }
 
 /*
  * mono_metadata_lookup_generic_class:
  *
- * Check whether the newly created generic class @gclass already exists
- * in the cache and return the cached value in this case.  Otherwise insert
- * it into the cache and return NULL.
- *
- * Returns: the previosly cached generic class or NULL if it has been newly
- *          inserted into the cache.
+ * Returns a MonoGenericClass with the given properties.
  *
  */
 MonoGenericClass *
-mono_metadata_lookup_generic_class (MonoGenericClass *gclass)
+mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
 {
-       MonoGenericClass *cached;
+       MonoGenericClass *gclass;
+
+       MonoGenericClass helper;
+       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.cached_class = NULL;
+
+       mono_loader_lock ();
 
-       cached = g_hash_table_lookup (generic_class_cache, gclass);
-       if (cached)
-               return cached;
+       gclass = g_hash_table_lookup (generic_class_cache, &helper);
+
+       /* A tripwire just to keep us honest */
+       g_assert (!helper.cached_class);
+
+       if (gclass) {
+               mono_loader_unlock ();
+               return gclass;
+       }
+
+       if (is_dynamic) {
+               MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
+               gclass = &dgclass->generic_class;
+               gclass->is_dynamic = 1;
+       } else {
+               gclass = g_new0 (MonoGenericClass, 1);
+       }
+
+       gclass->container_class = container_class;
+       gclass->context.class_inst = inst;
+       gclass->context.method_inst = NULL;
 
        g_hash_table_insert (generic_class_cache, gclass, gclass);
-       return NULL;
+
+       mono_loader_unlock ();
+
+       return gclass;
 }
 
 /*
@@ -1950,134 +2358,82 @@ mono_metadata_lookup_generic_class (MonoGenericClass *gclass)
 MonoGenericInst *
 mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context)
 {
+       MonoType **type_argv;
        MonoGenericInst *nginst;
        int i;
 
        if (!ginst->is_open)
                return ginst;
 
-       nginst = g_new0 (MonoGenericInst, 1);
-       nginst->type_argc = ginst->type_argc;
-       nginst->type_argv = g_new0 (MonoType*, nginst->type_argc);
-       nginst->is_reference = 1;
+       type_argv = g_new0 (MonoType*, ginst->type_argc);
 
-       for (i = 0; i < nginst->type_argc; i++) {
-               MonoType *t = 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 (ginst->type_argv [i], context);
 
-               if (!nginst->is_open)
-                       nginst->is_open = mono_class_is_open_constructed_type (t);
-               if (nginst->is_reference)
-                       nginst->is_reference = MONO_TYPE_IS_REFERENCE (t);
+       nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv);
 
-               nginst->type_argv [i] = t;
-       }
+       for (i = 0; i < ginst->type_argc; i++)
+               mono_metadata_free_type (type_argv [i]);
+       g_free (type_argv);
 
-       return mono_metadata_lookup_generic_inst (nginst);
+       return nginst;
 }
 
 MonoGenericInst *
 mono_metadata_parse_generic_inst (MonoImage *m, MonoGenericContainer *container,
                                  int count, const char *ptr, const char **rptr)
 {
+       MonoType **type_argv;
        MonoGenericInst *ginst;
        int i;
 
-       ginst = g_new0 (MonoGenericInst, 1);
-       ginst->type_argc = count;
-       ginst->type_argv = g_new0 (MonoType*, count);
-       ginst->is_reference = 1;
+       type_argv = g_new0 (MonoType*, count);
 
-       for (i = 0; i < ginst->type_argc; i++) {
+       for (i = 0; i < count; i++) {
                MonoType *t = mono_metadata_parse_type_full (m, container, MONO_PARSE_TYPE, 0, ptr, &ptr);
-
                if (!t) {
-                       g_free (ginst->type_argv);
-                       g_free (ginst);
+                       g_free (type_argv);
                        return NULL;
                }
-               ginst->type_argv [i] = t;
-               if (!ginst->is_open)
-                       ginst->is_open = mono_class_is_open_constructed_type (t);
-               if (ginst->is_reference)
-                       ginst->is_reference = MONO_TYPE_IS_REFERENCE (t);
+               type_argv [i] = t;
        }
 
        if (rptr)
                *rptr = ptr;
 
-       return mono_metadata_lookup_generic_inst (ginst);
+       ginst = mono_metadata_get_generic_inst (count, type_argv);
+
+       g_free (type_argv);
+
+       return ginst;
 }
 
 static gboolean
 do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericContainer *container,
                                      const char *ptr, const char **rptr)
 {
-       MonoInflatedGenericClass *igclass;
-       MonoGenericClass *gclass, *cached;
+       MonoGenericInst *inst;
        MonoClass *gklass;
        MonoType *gtype;
        int count;
 
-       igclass = g_new0 (MonoInflatedGenericClass, 1);
-       gclass = &igclass->generic_class;
-       gclass->is_inflated = TRUE;
-
-       type->data.generic_class = gclass;
-
-       /*
-        * Create the klass before parsing the type arguments.
-        * This is required to support "recursive" definitions.
-        * See mcs/tests/gen-23.cs for an example.
-        */
-       igclass->klass = g_new0 (MonoClass, 1);
-
        gtype = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
        if (gtype == NULL)
                return FALSE;
-       gclass->container_class = gklass = mono_class_from_mono_type (gtype);
 
-       g_assert (gklass->generic_container);
+       gklass = mono_class_from_mono_type (gtype);
+       if (!gklass->generic_container)
+               return FALSE;
 
        count = mono_metadata_decode_value (ptr, &ptr);
-
-       gclass->inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr);
+       inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr);
+       if (inst == NULL)
+               return FALSE;
 
        if (rptr)
                *rptr = ptr;
 
-       /* If we failed to parse, return, the error has been flagged. */
-       if (gclass->inst == NULL)
-               return FALSE;
-       
-       /*
-        * We may be called multiple times on different metadata to create the same
-        * instantiated type.  This happens for instance if we're part of a method or
-        * local variable signature.
-        *
-        * It's important to return the same MonoGenericClass * for each particualar
-        * instantiation of a generic type (ie "Stack<Int32>") to make static fields
-        * work.
-        *
-        * According to the spec ($26.1.5), a static variable in a generic class
-        * declaration is shared amongst all instances of the same closed constructed
-        * type.
-        */
-
-       cached = g_hash_table_lookup (generic_class_cache, gclass);
-       if (cached) {
-               g_free (igclass->klass);
-               g_free (gclass);
-
-               type->data.generic_class = cached;
-               return TRUE;
-       } else {
-               g_hash_table_insert (generic_class_cache, gclass, gclass);
-
-               mono_stats.generic_instance_count++;
-               mono_stats.generics_metadata_size += sizeof (MonoGenericClass) +
-                       sizeof (MonoGenericContext) +
-                       gclass->inst->type_argc * sizeof (MonoType);
-       }
+       type->data.generic_class = mono_metadata_lookup_generic_class (gklass, inst, FALSE);
        return TRUE;
 }
 
@@ -2113,6 +2469,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,
@@ -2125,8 +2482,9 @@ 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;
 
                return param;
@@ -2197,7 +2555,6 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer
                if (!etype)
                        return FALSE;
                type->data.klass = mono_class_from_mono_type (etype);
-               mono_metadata_free_type (etype);
                break;
        }
        case MONO_TYPE_PTR:
@@ -2231,8 +2588,7 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer
  * mono_metadata_free_type:
  * @type: type to free
  *
- * Free the memory allocated for type @type which is assumed to be created by
- * mono_metadata_parse_type ().
+ * Free the memory allocated for type @type which is allocated on the heap.
  */
 void
 mono_metadata_free_type (MonoType *type)
@@ -2262,7 +2618,7 @@ mono_metadata_free_type (MonoType *type)
                break;
        }
 
-       /* Allocated from a mempool, no need to free it */
+       g_free (type);
 }
 
 #if 0
@@ -2302,7 +2658,6 @@ parse_section_data (MonoImage *m, MonoMethodHeader *mh, const unsigned char *ptr
        
        while (1) {
                /* align on 32-bit boundary */
-               /* FIXME: not 64-bit clean code */
                sptr = ptr = dword_align (ptr); 
                sect_data_flags = *ptr;
                ptr++;
@@ -2402,7 +2757,7 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons
                mh->max_stack = 8;
                local_var_sig_tok = 0;
                mh->code_size = flags >> 2;
-               mh->code = ptr;
+               mh->code = (unsigned char*)ptr;
                mono_loader_unlock ();
                return mh;
        case METHOD_HEADER_TINY_FORMAT1:
@@ -2416,7 +2771,7 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons
                 * incorrect
                 */
                mh->code_size = flags >> 2;
-               mh->code = ptr;
+               mh->code = (unsigned char*)ptr;
                mono_loader_unlock ();
                return mh;
        case METHOD_HEADER_FAT_FORMAT:
@@ -2435,7 +2790,7 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons
                else
                        init_locals = 0;
 
-               code = ptr;
+               code = (unsigned char*)ptr;
 
                if (!(fat_flags & METHOD_HEADER_MORE_SECTS))
                        break;
@@ -2443,7 +2798,7 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons
                /*
                 * There are more sections
                 */
-               ptr = code + code_size;
+               ptr = (char*)code + code_size;
                break;
        default:
                mono_loader_unlock ();
@@ -3223,7 +3578,7 @@ mono_type_size (MonoType *t, int *align)
                if (t->data.klass->enumtype)
                        return mono_type_size (t->data.klass->enum_basetype, align);
                else
-                       return mono_class_value_size (t->data.klass, align);
+                       return mono_class_value_size (t->data.klass, (guint32*)align);
        }
        case MONO_TYPE_CLASS:
        case MONO_TYPE_SZARRAY:
@@ -3233,22 +3588,18 @@ mono_type_size (MonoType *t, int *align)
                *align = __alignof__(gpointer);
                return sizeof (gpointer);
        case MONO_TYPE_TYPEDBYREF:
-               return mono_class_value_size (mono_defaults.typed_reference_class, align);
+               return mono_class_value_size (mono_defaults.typed_reference_class, (guint32*)align);
        case MONO_TYPE_GENERICINST: {
-               MonoInflatedGenericClass *gclass;
-               MonoClass *container_class;
-
-               gclass = mono_get_inflated_generic_class (t->data.generic_class);
-               // g_assert (!gclass->generic_class.inst->is_open);
-               // g_assert (!gclass->klass->generic_container);
+               MonoGenericClass *gclass = t->data.generic_class;
+               MonoClass *container_class = gclass->container_class;
 
-               container_class = gclass->generic_class.container_class;
+               // g_assert (!gclass->inst->is_open);
 
                if (container_class->valuetype) {
                        if (container_class->enumtype)
                                return mono_type_size (container_class->enum_basetype, align);
                        else
-                               return mono_class_value_size (gclass->klass, align);
+                               return mono_class_value_size (mono_class_from_mono_type (t), (guint32*)align);
                } else {
                        *align = __alignof__(gpointer);
                        return sizeof (gpointer);
@@ -3275,7 +3626,7 @@ mono_type_size (MonoType *t, int *align)
 int
 mono_type_stack_size (MonoType *t, int *align)
 {
-       guint32 tmp;
+       int tmp;
 
        g_assert (t != NULL);
 
@@ -3326,7 +3677,7 @@ mono_type_stack_size (MonoType *t, int *align)
                if (t->data.klass->enumtype)
                        return mono_type_stack_size (t->data.klass->enum_basetype, align);
                else {
-                       size = mono_class_value_size (t->data.klass, align);
+                       size = mono_class_value_size (t->data.klass, (guint32*)align);
 
                        *align = *align + __alignof__(gpointer) - 1;
                        *align &= ~(__alignof__(gpointer) - 1);
@@ -3338,20 +3689,16 @@ mono_type_stack_size (MonoType *t, int *align)
                }
        }
        case MONO_TYPE_GENERICINST: {
-               MonoInflatedGenericClass *gclass;
-               MonoClass *container_class;
+               MonoGenericClass *gclass = t->data.generic_class;
+               MonoClass *container_class = gclass->container_class;
 
-               gclass = mono_get_inflated_generic_class (t->data.generic_class);
-               container_class = gclass->generic_class.container_class;
-
-               g_assert (!gclass->generic_class.inst->is_open);
-               g_assert (!gclass->klass->generic_container);
+               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);
                        else {
-                               guint32 size = mono_class_value_size (gclass->klass, align);
+                               guint32 size = mono_class_value_size (mono_class_from_mono_type (t), (guint32*)align);
 
                                *align = *align + __alignof__(gpointer) - 1;
                                *align &= ~(__alignof__(gpointer) - 1);
@@ -3389,33 +3736,38 @@ 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 ((g1->inst->type_argc != g2->inst->type_argc) || (g1->is_dynamic != g2->is_dynamic) ||
-           (g1->inst->is_reference != g2->inst->is_reference))
+       if (i1->type_argc != i2->type_argc || 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 < g1->inst->type_argc; ++i) {
-               if (!do_mono_metadata_type_equal (g1->inst->type_argv [i], g2->inst->type_argv [i], signature_only))
+       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;
 }
 
 guint
-mono_metadata_generic_method_hash (MonoGenericMethod *gmethod)
-{
-       return gmethod->inst->id;
+mono_metadata_generic_context_hash (const MonoGenericContext *context)
+{
+       /* FIXME: check if this seed is good enough */
+       guint hash = 0xc01dfee7;
+       if (context->class_inst)
+               hash = ((hash << 5) - hash) ^ context->class_inst->id;
+       if (context->method_inst)
+               hash = ((hash << 5) - hash) ^ context->method_inst->id;
+       return hash;
 }
 
 gboolean
-mono_metadata_generic_method_equal (MonoGenericMethod *g1, MonoGenericMethod *g2)
+mono_metadata_generic_context_equal (const MonoGenericContext *g1, const MonoGenericContext *g2)
 {
-       return (g1->container == g2->container) && (g1->class_inst == g2->class_inst) &&
-               (g1->inst == g2->inst);
+       return g1->class_inst == g2->class_inst && g1->method_inst == g2->method_inst;
 }
 
-
 /*
  * mono_metadata_type_hash:
  * @t1: a type
@@ -3599,6 +3951,9 @@ mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *s
        if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
                return FALSE;
 
+       if (sig1->generic_param_count != sig2->generic_param_count)
+               return FALSE;
+
        /*
         * We're just comparing the signatures of two methods here:
         *
@@ -3625,27 +3980,37 @@ mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *s
 }
 
 /**
- * mono_metadata_type_dup_mp:
- * @image: image type is defined in
+ * mono_metadata_type_dup:
+ * @mp: mempool to use
  * @original: type to duplicate
  *
- * Returns: copy of type allocated from mempool.
+ * Returns: copy of type allocated from mempool (or from the heap, if @mp is null).
  */
 MonoType *
-mono_metadata_type_dup_mp (MonoImage *image, const MonoType *original)
+mono_metadata_type_dup (MonoMemPool *mp, const MonoType *o)
 {
        MonoType *r = NULL;
+       int sizeof_o = sizeof (MonoType);
+       if (o->num_mods)
+               sizeof_o += (o->num_mods - MONO_ZERO_LEN_ARRAY) * sizeof (MonoCustomMod);
+
        mono_loader_lock ();
-       r = mono_mempool_alloc0 (image->mempool, sizeof(MonoType));
+       r = mp ? mono_mempool_alloc0 (mp, sizeof_o) : g_malloc (sizeof_o);
        mono_loader_unlock ();
-       *r = *original;
-       /* FIXME: we don't handle these yet because they need to duplicate memory
-        * but the current routines used are not using the mempools
-        */
-       if (original->type == MONO_TYPE_PTR || 
-               original->type == MONO_TYPE_ARRAY || 
-               original->type == MONO_TYPE_FNPTR)
-               g_assert_not_reached ();
+
+       memcpy (r, o, sizeof_o);
+
+       if (o->type == MONO_TYPE_PTR) {
+               r->data.type = mono_metadata_type_dup (mp, o->data.type);
+       } else if (o->type == MONO_TYPE_ARRAY) {
+               /* FIXME: should mono_dup_array_type() use mempools? */
+               g_assert (!mp);
+               r->data.array = mono_dup_array_type (o->data.array);
+       } else if (o->type == MONO_TYPE_FNPTR) {
+               /* FIXME: should mono_metadata_signature_deep_dup() use mempools? */
+               g_assert (!mp);
+               r->data.method = mono_metadata_signature_deep_dup (o->data.method);
+       }
        return r;
 }
 
@@ -4022,7 +4387,7 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
        guint32 cols [MONO_TYPESPEC_SIZE];
        const char *ptr;
        guint32 len;
-       MonoType *type;
+       MonoType *type, *type2;
 
        mono_loader_lock ();
 
@@ -4038,9 +4403,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);
-
-       g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type);
+       type = mono_mempool_alloc0 (image->mempool, sizeof (MonoType));
 
        if (*ptr == MONO_TYPE_BYREF) {
                type->byref = 1;
@@ -4048,12 +4411,20 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
        }
 
        if (!do_mono_metadata_parse_type (type, image, NULL, ptr, &ptr)) {
-               g_hash_table_remove (image->typespec_cache, GUINT_TO_POINTER (type_spec));
                g_free (type);
                mono_loader_unlock ();
                return NULL;
        }
 
+       type2 = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
+
+       if (type2) {
+               mono_loader_unlock ();
+               return type2;
+       }
+
+       g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type);
+
        mono_loader_unlock ();
 
        return type;
@@ -4232,14 +4603,24 @@ handle_enum:
                                g_error ("Can not marshal string to native type '%02x': Invalid managed/unmanaged type combination (String fields must be paired with LPStr, LPWStr, BStr or ByValTStr).", mspec->native);
                        }
                }       
-               *conv = MONO_MARSHAL_CONV_STR_LPTSTR;
-               return MONO_NATIVE_LPTSTR; 
+               if (unicode) {
+                       *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
+                       return MONO_NATIVE_LPWSTR; 
+               }
+               else {
+                       *conv = MONO_MARSHAL_CONV_STR_LPSTR;
+                       return MONO_NATIVE_LPSTR; 
+               }
        case MONO_TYPE_PTR: return MONO_NATIVE_UINT;
        case MONO_TYPE_VALUETYPE: /*FIXME*/
                if (type->data.klass->enumtype) {
                        t = type->data.klass->enum_basetype->type;
                        goto handle_enum;
                }
+               if (type->data.klass == mono_defaults.handleref_class){
+                       *conv = MONO_MARSHAL_CONV_HANDLEREF;
+                       return MONO_NATIVE_INT;
+               }
                return MONO_NATIVE_STRUCT;
        case MONO_TYPE_SZARRAY: 
        case MONO_TYPE_ARRAY: 
@@ -4273,6 +4654,8 @@ handle_enum:
                        switch (mspec->native) {
                        case MONO_NATIVE_STRUCT:
                                return MONO_NATIVE_STRUCT;
+                       case MONO_NATIVE_CUSTOM:
+                               return MONO_NATIVE_CUSTOM;
                        case MONO_NATIVE_INTERFACE:
                                *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
                                return MONO_NATIVE_INTERFACE;
@@ -4300,7 +4683,7 @@ handle_enum:
                        *conv = MONO_MARSHAL_CONV_DEL_FTN;
                        return MONO_NATIVE_FUNC;
                }
-               if (type->data.klass == mono_defaults.safehandle_class){
+               if (mono_defaults.safehandle_class && type->data.klass == mono_defaults.safehandle_class){
                        *conv = MONO_MARSHAL_CONV_SAFEHANDLE;
                        return MONO_NATIVE_INT;
                }
@@ -4456,9 +4839,6 @@ get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGene
        GList *cons = NULL, *tmp;
        MonoGenericContext *context = &container->context;
 
-       /* FIXME: !container->klass => this is probably monodis */
-       g_assert (!container->klass || context->class_inst || context->gmethod);
-
        *constraints = NULL;
        found = 0;
        for (i = 0; i < tdef->rows; ++i) {
@@ -4564,6 +4944,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)
@@ -4573,19 +4955,19 @@ mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericC
        guint32 i, owner = 0, n;
        MonoGenericContainer *container;
        MonoGenericParam *params;
+       MonoGenericContext *context;
 
        if (!(i = mono_metadata_get_generic_param_row (image, token, &owner)))
                return NULL;
        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);
                params [n - 1].owner = container;
                params [n - 1].pklass = NULL;
-               params [n - 1].method = NULL;
                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]);
@@ -4596,15 +4978,55 @@ 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)
                container->is_method = 1;
 
+       g_assert (container->parent == NULL || container->is_method);
+
+       context = &container->context;
+       if (container->is_method) {
+               context->class_inst = container->parent ? container->parent->context.class_inst : NULL;
+               context->method_inst = mono_get_shared_generic_inst (container);
+       } else {
+               context->class_inst = mono_get_shared_generic_inst (container);
+       }
+
        return container;
 }
 
+MonoGenericInst *
+mono_get_shared_generic_inst (MonoGenericContainer *container)
+{
+       MonoType **type_argv;
+       MonoType *helper;
+       MonoGenericInst *nginst;
+       int i;
+
+       type_argv = g_new0 (MonoType *, container->type_argc);
+       helper = g_new0 (MonoType, container->type_argc);
+
+       for (i = 0; i < container->type_argc; i++) {
+               MonoType *t = &helper [i];
+
+               t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
+               t->data.generic_param = &container->type_params [i];
+
+               type_argv [i] = t;
+       }
+
+       nginst = mono_metadata_get_generic_inst (container->type_argc, type_argv);
+
+       g_free (type_argv);
+       g_free (helper);
+
+       return nginst;
+}
+
 gboolean
 mono_type_is_byref (MonoType *type)
 {