2004-12-29 Martin Baulig <martin@ximian.com>
[mono.git] / mono / metadata / metadata.c
index 65e56c1b3c0ec41a096f8cd8f9f3789852b697b3..523bec047179b46f0e840cb2847a3fc09e0a45e5 100644 (file)
 #include <config.h>
 #include <stdio.h> 
 #include <stdlib.h>
+#include <string.h>
 #include <glib.h>
 #include "metadata.h"
 #include "tabledefs.h"
 #include "mono-endian.h"
 #include "cil-coff.h"
 #include "tokentype.h"
+#include "metadata-internals.h"
+#include "class-internals.h"
 #include "private.h"
 #include "class.h"
 
-static void do_mono_metadata_parse_type (MonoType *type, MonoImage *m, const char *ptr, const char **rptr);
+static void do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContext *generic_context,
+                                        const char *ptr, const char **rptr);
+
+static gboolean do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only);
+static gboolean mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only);
+static gboolean _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2,
+                                                   gboolean signature_only);
 
 /*
  * Encoding of the "description" argument:
@@ -296,7 +305,6 @@ const static MonoMetaTable GenericParamSchema [] = {
 
        /* soon to be removed */
        { MONO_MT_TABLE_IDX,  "Kind" }, 
-       { MONO_MT_TABLE_IDX,  "DeprecatedConstraint" },
        
        { MONO_MT_END, NULL }
 };
@@ -368,7 +376,7 @@ const static struct {
  * mono_meta_table_name:
  * @table: table index
  *
- * Returns the name for the @table index
+ * Returns: the name for the @table index
  */
 const char *
 mono_meta_table_name (int table)
@@ -409,7 +417,7 @@ int
 mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bitfield)
 {
        guint32 bitfield = 0;
-       int size = 0, field_size;
+       int size = 0, field_size = 0;
        int i, n, code;
        int shift = 0;
        const MonoMetaTable *table = tables [tableindex].table;
@@ -742,7 +750,7 @@ mono_metadata_compute_table_bases (MonoImage *meta)
  * @table: table code.
  * @idx: index of element to retrieve from @table.
  *
- * Returns a pointer to the @idx element in the metadata table
+ * Returns: a pointer to the @idx element in the metadata table
  * whose code is @table.
  */
 const char *
@@ -759,7 +767,7 @@ mono_metadata_locate (MonoImage *meta, int table, int idx)
  * @meta: metadata context
  * @token: metadata token
  *
- * Returns a pointer to the data in the metadata represented by the
+ * Returns: a pointer to the data in the metadata represented by the
  * token #token.
  */
 const char *
@@ -772,7 +780,7 @@ mono_metadata_locate_token (MonoImage *meta, guint32 token)
  * mono_metadata_get_table:
  * @table: table to retrieve
  *
- * Returns the MonoMetaTable structure for table @table
+ * Returns: the MonoMetaTable structure for table @table
  */
 const MonoMetaTable *
 mono_metadata_get_table (MonoMetaTableEnum table)
@@ -862,7 +870,7 @@ dword_align (const char *ptr)
  * into the guint32 @res array that has res_size elements
  */
 void
-mono_metadata_decode_row (MonoTableInfo *t, int idx, guint32 *res, int res_size)
+mono_metadata_decode_row (const MonoTableInfo *t, int idx, guint32 *res, int res_size)
 {
        guint32 bitfield = t->size_bitfield;
        int i, count = mono_metadata_table_count (bitfield);
@@ -899,7 +907,7 @@ mono_metadata_decode_row (MonoTableInfo *t, int idx, guint32 *res, int res_size)
  * row in the table @t.
  */
 guint32
-mono_metadata_decode_row_col (MonoTableInfo *t, int idx, guint col)
+mono_metadata_decode_row_col (const MonoTableInfo *t, int idx, guint col)
 {
        guint32 bitfield = t->size_bitfield;
        int i;
@@ -1052,13 +1060,14 @@ mono_metadata_parse_custom_mod (MonoImage *m, MonoCustomMod *dest, const char *p
  * and dimensions.
  */
 MonoArrayType *
-mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
+mono_metadata_parse_array_full (MonoImage *m, MonoGenericContext *generic_context,
+                               const char *ptr, const char **rptr)
 {
        int i;
        MonoArrayType *array = g_new0 (MonoArrayType, 1);
        MonoType *etype;
        
-       etype = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
+       etype = mono_metadata_parse_type_full (m, generic_context, MONO_PARSE_TYPE, 0, ptr, &ptr);
        array->eklass = mono_class_from_mono_type (etype);
        array->rank = mono_metadata_decode_value (ptr, &ptr);
 
@@ -1079,6 +1088,12 @@ mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
        return array;
 }
 
+MonoArrayType *
+mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
+{
+       return mono_metadata_parse_array_full (m, NULL, ptr, rptr);
+}
+
 /*
  * mono_metadata_free_array:
  * @array: array description
@@ -1102,7 +1117,7 @@ mono_metadata_free_array (MonoArrayType *array)
  * private static
  * private static literal
  */
-static MonoType
+static const MonoType
 builtin_types[] = {
        /* data, attrs, type,              nmods, byref, pinned */
        {{NULL}, 0,     MONO_TYPE_VOID,    0,     0,     0},
@@ -1132,6 +1147,8 @@ builtin_types[] = {
        {{NULL}, 0,     MONO_TYPE_R8,      0,     1,     0},
        {{NULL}, 0,     MONO_TYPE_STRING,  0,     0,     0},
        {{NULL}, 0,     MONO_TYPE_STRING,  0,     1,     0},
+       {{NULL}, 0,     MONO_TYPE_OBJECT,  0,     0,     0},
+       {{NULL}, 0,     MONO_TYPE_OBJECT,  0,     1,     0},
        {{NULL}, 0,     MONO_TYPE_TYPEDBYREF,  0,     0,     0},
        {{NULL}, 0,     MONO_TYPE_I,       0,     0,     0},
        {{NULL}, 0,     MONO_TYPE_I,       0,     1,     0},
@@ -1142,6 +1159,9 @@ 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;
 
 /*
  * MonoTypes with modifies are never cached, so we never check or use that field.
@@ -1165,6 +1185,45 @@ mono_type_equal (gconstpointer ka, gconstpointer kb)
        return 1;
 }
 
+static guint
+mono_generic_inst_hash (gconstpointer data)
+{
+       const MonoGenericInst *ginst = (const MonoGenericInst *) data;
+       return ginst->type_argc | (ginst->is_open << 8);
+}
+
+static gboolean
+mono_generic_inst_equal (gconstpointer ka, gconstpointer kb)
+{
+       const MonoGenericInst *a = (const MonoGenericInst *) ka;
+       const MonoGenericInst *b = (const MonoGenericInst *) kb;
+       int i;
+
+       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))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+static guint
+mono_generic_class_hash (gconstpointer data)
+{
+       const MonoGenericClass *gclass = (const MonoGenericClass *) data;
+       return mono_metadata_type_hash (&gclass->container_class->byval_arg);
+}
+
+static gboolean
+mono_generic_class_equal (gconstpointer ka, gconstpointer kb)
+{
+       const MonoGenericClass *a = (const MonoGenericClass *) ka;
+       const MonoGenericClass *b = (const MonoGenericClass *) kb;
+
+       return _mono_metadata_generic_class_equal (a, b, FALSE);
+}
+
 /**
  * mono_metadata_init:
  *
@@ -1176,12 +1235,14 @@ 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);
 
        for (i = 0; i < NBUILTIN_TYPES (); ++i)
-               g_hash_table_insert (type_cache, &builtin_types [i], &builtin_types [i]);
+               g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
 }
 
-/*
+/**
  * mono_metadata_parse_type:
  * @m: metadata context
  * @mode: king of type that may be found at @ptr
@@ -1195,13 +1256,25 @@ mono_metadata_init (void)
  * This function can be used to decode type descriptions in method signatures,
  * field signatures, locals signatures etc.
  *
+ * 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.
+ * When we encounter any MONO_TYPE_VAR or MONO_TYPE_MVAR's, they're looked up in
+ * this MonoGenericContainer.
+ *
  * Returns: a #MonoType structure representing the decoded type.
  */
 MonoType*
-mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs, const char *ptr, const char **rptr)
+mono_metadata_parse_type_full (MonoImage *m, MonoGenericContext *generic_context, MonoParseTypeMode mode,
+                              short opt_attrs, const char *ptr, const char **rptr)
 {
        MonoType *type, *cached;
+       MonoType stype;
        gboolean byref = FALSE;
+       gboolean pinned = FALSE;
+       const char *tmp_ptr;
+       int count = 0;
+       gboolean found;
 
        /*
         * According to the spec, custom modifiers should come before the byref
@@ -1211,80 +1284,101 @@ mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
         * Also, this type seems to be different from 'object & modopt(...)'. Maybe
         * it would be better to treat byref as real type constructor instead of
         * a modifier...
+        * Also, pinned should come before anything else, but some MSV++ produced
+        * assemblies violate this (#bug 61990).
         */
-       if (*ptr == MONO_TYPE_BYREF) {
-               byref = TRUE;
-               ++ptr;
-       }
 
-       switch (mode) {
-       case MONO_PARSE_MOD_TYPE:
-       case MONO_PARSE_PARAM:
-       case MONO_PARSE_RET:
-       case MONO_PARSE_LOCAL: /* should not have modifiers according to the spec, but ms tools disagree */
-       case MONO_PARSE_FIELD: {
-               /* count the modifiers */
-               const char *tmp_ptr = ptr;
-               int count = 0;
-               while (mono_metadata_parse_custom_mod (m, NULL, tmp_ptr, &tmp_ptr))
-                       count++;
-               if (count) {
-                       type = g_malloc0 (sizeof (MonoType) + ((gint32)count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoCustomMod));
-                       type->num_mods = count;
-                       if (count > 64)
-                               g_warning ("got more than 64 modifiers in type");
-                       /* save them this time */
-                       count = 0;
-                       while (mono_metadata_parse_custom_mod (m, &(type->modifiers [count]), ptr, &ptr))
-                               count++;
+       /* Count the modifiers first */
+       tmp_ptr = ptr;
+       found = TRUE;
+       while (found) {
+               switch (*tmp_ptr) {
+               case MONO_TYPE_PINNED:
+               case MONO_TYPE_BYREF:
+                       ++tmp_ptr;
+                       break;
+               case MONO_TYPE_CMOD_REQD:
+               case MONO_TYPE_CMOD_OPT:
+                       count ++;
+                       mono_metadata_parse_custom_mod (m, NULL, tmp_ptr, &tmp_ptr);
                        break;
-               } /* fall through */
+               default:
+                       found = FALSE;
+               }
        }
-       case MONO_PARSE_TYPE:
-               /*
-                * Later we can avoid doing this allocation.
-                */
-               type = g_new0 (MonoType, 1);
-               break;
-       default:
-               g_assert_not_reached ();
+
+       if (count) {
+               type = g_malloc0 (sizeof (MonoType) + ((gint32)count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoCustomMod));
+               type->num_mods = count;
+               if (count > 64)
+                       g_warning ("got more than 64 modifiers in type");
        }
-       
-       type->attrs = opt_attrs;
-       type->byref = byref;
-       if (mode == MONO_PARSE_LOCAL) {
-               /*
-                * check for pinned flag
-                */
-               if (*ptr == MONO_TYPE_PINNED) {
-                       type->pinned = 1;
+       else {
+               type = &stype;
+               memset (type, 0, sizeof (MonoType));
+       }
+
+       /* Parse pinned, byref and custom modifiers */
+       found = TRUE;
+       count = 0;
+       while (found) {
+               switch (*ptr) {
+               case MONO_TYPE_PINNED:
+                       pinned = TRUE;
+                       ++ptr;
+                       break;
+               case MONO_TYPE_BYREF:
+                       byref = TRUE;
                        ++ptr;
+                       break;
+               case MONO_TYPE_CMOD_REQD:
+               case MONO_TYPE_CMOD_OPT:
+                       mono_metadata_parse_custom_mod (m, &(type->modifiers [count]), ptr, &ptr);
+                       count ++;
+                       break;
+               default:
+                       found = FALSE;
                }
        }
+       
+       type->attrs = opt_attrs;
+       type->byref = byref;
+       type->pinned = pinned ? 1 : 0;
+
+       do_mono_metadata_parse_type (type, m, generic_context, ptr, &ptr);
 
-       switch (*ptr) {
-       case MONO_TYPE_BYREF: 
-               if (mode == MONO_PARSE_FIELD)
-                       g_warning ("A field type cannot be byref");
-               type->byref = 1; 
-               ptr++;
-               /* follow through */
-       default:
-               /*if (*ptr == MONO_TYPE_VOID && mode != MONO_PARSE_RET)
-                       g_error ("void not allowed in param");*/
-               do_mono_metadata_parse_type (type, m, ptr, &ptr);
-               break;
-       }
        if (rptr)
                *rptr = ptr;
 
-       /* No need to use locking since nobody is modifying the hash table */
-       if (mode != MONO_PARSE_PARAM && !type->num_mods && (cached = g_hash_table_lookup (type_cache, type))) {
-               mono_metadata_free_type (type);
-               return cached;
-       } else {
-               return type;
+       
+       /* FIXME: remove the != MONO_PARSE_PARAM condition, this accounts for
+        * almost 10k (about 2/3rds) of all MonoType's we create.
+        */
+       if (mode != MONO_PARSE_PARAM && !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) {
+                       if (type->byref)
+                               return &type->data.klass->this_arg;
+                       else
+                               return &type->data.klass->byval_arg;
+               }
+               /* No need to use locking since nobody is modifying the hash table */
+               if ((cached = g_hash_table_lookup (type_cache, type)))
+                       return cached;
        }
+       
+       /*printf ("%x%c %s\n", type->attrs, type->pinned ? 'p' : ' ', mono_type_full_name (type));*/
+       
+       if (type == &stype)
+               type = g_memdup (&stype, sizeof (MonoType));
+       return type;
+}
+
+MonoType*
+mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
+                         const char *ptr, const char **rptr)
+{
+       return mono_metadata_parse_type_full (m, NULL, mode, opt_attrs, ptr, rptr);
 }
 
 /*
@@ -1297,14 +1391,14 @@ mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
  * Returns: a MonoMethodSignature describing the signature.
  */
 MonoMethodSignature *
-mono_metadata_parse_signature (MonoImage *image, guint32 token)
+mono_metadata_parse_signature_full (MonoImage *image, MonoGenericContext *generic_context, guint32 token)
 {
        MonoTableInfo *tables = image->tables;
        guint32 idx = mono_metadata_token_index (token);
        guint32 sig;
        const char *ptr;
 
-       if (image->assembly->dynamic)
+       if (image->dynamic)
                return mono_lookup_dynamic_token (image, token);
 
        g_assert (mono_metadata_token_table(token) == MONO_TABLE_STANDALONESIG);
@@ -1314,7 +1408,13 @@ mono_metadata_parse_signature (MonoImage *image, guint32 token)
        ptr = mono_metadata_blob_heap (image, sig);
        mono_metadata_decode_blob_size (ptr, &ptr);
 
-       return mono_metadata_parse_method_signature (image, FALSE, ptr, NULL); 
+       return mono_metadata_parse_method_signature_full (image, generic_context, FALSE, ptr, NULL); 
+}
+
+MonoMethodSignature *
+mono_metadata_parse_signature (MonoImage *image, guint32 token)
+{
+       return mono_metadata_parse_signature_full (image, NULL, token);
 }
 
 MonoMethodSignature*
@@ -1325,10 +1425,20 @@ mono_metadata_signature_alloc (MonoImage *m, guint32 nparams)
        /* later we want to allocate signatures with mempools */
        sig = g_malloc0 (sizeof (MonoMethodSignature) + ((gint32)nparams - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType*));
        sig->param_count = nparams;
+       sig->sentinelpos = -1;
 
        return sig;
 }
 
+MonoMethodSignature*
+mono_metadata_signature_dup (MonoMethodSignature *sig)
+{
+       int sigsize;
+
+       sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
+       return g_memdup (sig, sigsize);
+}
+
 /*
  * mono_metadata_parse_method_signature:
  * @m: metadata context
@@ -1341,12 +1451,15 @@ mono_metadata_signature_alloc (MonoImage *m, guint32 nparams)
  * Returns: a MonoMethodSignature describing the signature.
  */
 MonoMethodSignature *
-mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, const char **rptr)
+mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContext *generic_context,
+                                          int def, const char *ptr, const char **rptr)
 {
        MonoMethodSignature *method;
        int i, ret_attrs = 0, *pattrs = NULL;
        guint32 hasthis = 0, explicit_this = 0, call_convention, param_count;
        guint32 gen_param_count = 0;
+       gboolean is_open = FALSE;
+       MonoGenericContext *context = NULL;
 
        if (*ptr & 0x10)
                gen_param_count = 1;
@@ -1384,8 +1497,34 @@ mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, co
        method->explicit_this = explicit_this;
        method->call_convention = call_convention;
        method->generic_param_count = gen_param_count;
-       if (call_convention != 0xa)
-               method->ret = mono_metadata_parse_type (m, MONO_PARSE_RET, ret_attrs, ptr, &ptr);
+
+       if (gen_param_count)
+               method->has_type_parameters = 1;
+
+       if (gen_param_count && (!generic_context || !generic_context->container->is_method)) {
+               MonoGenericContainer *container = g_new0 (MonoGenericContainer, 1);
+
+               if (generic_context)
+                       container->parent = generic_context->container;
+               container->is_signature = 1;
+
+               context = &container->context;
+               container->context.container = container;
+
+               container->type_argc = gen_param_count;
+               container->type_params = g_new0 (MonoGenericParam, gen_param_count);
+
+               for (i = 0; i < gen_param_count; i++) {
+                       container->type_params [i].owner = container;
+                       container->type_params [i].num = i;
+               }
+       } else
+               context = generic_context;
+
+       if (call_convention != 0xa) {
+               method->ret = mono_metadata_parse_type_full (m, context, MONO_PARSE_RET, ret_attrs, ptr, &ptr);
+               is_open = mono_class_is_open_constructed_type (method->ret);
+       }
 
        if (method->param_count) {
                method->sentinelpos = -1;
@@ -1397,9 +1536,18 @@ mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, co
                                method->sentinelpos = i;
                                ptr++;
                        }
-                       method->params [i] = mono_metadata_parse_type (m, MONO_PARSE_PARAM, pattrs [i], ptr, &ptr);
+                       method->params [i] = mono_metadata_parse_type_full (
+                               m, context, MONO_PARSE_PARAM, pattrs [i], ptr, &ptr);
+                       if (!is_open)
+                               is_open = mono_class_is_open_constructed_type (method->params [i]);
                }
        }
+
+       method->has_type_parameters = is_open;
+
+       if (def && (method->call_convention == MONO_CALL_VARARG))
+               method->sentinelpos = method->param_count;
+
        g_free (pattrs);
 
        if (rptr)
@@ -1410,6 +1558,12 @@ mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, co
        return method;
 }
 
+MonoMethodSignature *
+mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, const char **rptr)
+{
+       return mono_metadata_parse_method_signature_full (m, NULL, def, ptr, rptr);
+}
+
 /*
  * mono_metadata_free_method_signature:
  * @sig: signature to destroy
@@ -1427,20 +1581,112 @@ mono_metadata_free_method_signature (MonoMethodSignature *sig)
        g_free (sig);
 }
 
-static void
-do_mono_metadata_parse_generic_inst (MonoType *type, MonoImage *m, const char *ptr, const char **rptr)
+MonoGenericInst *
+mono_metadata_lookup_generic_inst (MonoGenericInst *ginst)
+{
+       MonoGenericInst *cached;
+       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;
+       }
+
+       ginst->id = ++next_generic_inst_id;
+       g_hash_table_insert (generic_inst_cache, ginst, ginst);
+
+       return ginst;
+}
+
+MonoGenericClass *
+mono_metadata_lookup_generic_class (MonoGenericClass *gclass)
+{
+       MonoGenericClass *cached;
+       int i;
+
+       cached = g_hash_table_lookup (generic_class_cache, gclass);
+       if (cached)
+               return cached;
+
+       g_hash_table_insert (generic_class_cache, gclass, gclass);
+       return NULL;
+}
+
+MonoGenericInst *
+mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context)
+{
+       MonoGenericInst *nginst, *cached;
+       int i;
+
+       nginst = g_new0 (MonoGenericInst, 1);
+       nginst->type_argc = ginst->type_argc;
+       nginst->type_argv = g_new0 (MonoType*, nginst->type_argc);
+
+       for (i = 0; i < nginst->type_argc; i++) {
+               MonoType *t = ginst->type_argv [i];
+
+               nginst->type_argv [i] = mono_class_inflate_generic_type (t, context);
+
+               if (!nginst->is_open)
+                       nginst->is_open = mono_class_is_open_constructed_type (nginst->type_argv [i]);
+       }
+
+       return mono_metadata_lookup_generic_inst (nginst);
+}
+
+MonoGenericInst *
+mono_metadata_parse_generic_inst (MonoImage *m, MonoGenericContext *generic_context,
+                                 int count, const char *ptr, const char **rptr)
 {
-       MonoGenericInst *generic_inst = g_new0 (MonoGenericInst, 1);
-       MonoClass *klass, *gklass;
+       MonoGenericInst *ginst;
+       int i;
+
+       ginst = g_new0 (MonoGenericInst, 1);
+       ginst->type_argc = count;
+       ginst->type_argv = g_new0 (MonoType*, count);
+
+       for (i = 0; i < ginst->type_argc; i++) {
+               MonoType *t = mono_metadata_parse_type_full (m, generic_context, MONO_PARSE_TYPE, 0, ptr, &ptr);
+
+               ginst->type_argv [i] = t;
+               if (!ginst->is_open)
+                       ginst->is_open = mono_class_is_open_constructed_type (t);
+       }
+
+       if (rptr)
+               *rptr = ptr;
+
+       return mono_metadata_lookup_generic_inst (ginst);
+}
+
+static void
+do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericContext *generic_context,
+                                     const char *ptr, const char **rptr)
+{
+       MonoGenericClass *gclass = g_new0 (MonoGenericClass, 1);
+       MonoGenericContainer *container;
+       MonoGenericClass *cached;
+       MonoGenericInst *ginst;
+       MonoClass *gklass;
+       MonoType *gtype;
        int i, count;
 
-       type->data.generic_inst = generic_inst;
+       type->data.generic_class = gclass;
 
-       generic_inst->klass = klass = g_new0 (MonoClass, 1);
-       
-       generic_inst->generic_type = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
-       generic_inst->type_argc = count = mono_metadata_decode_value (ptr, &ptr);
-       generic_inst->type_argv = g_new0 (MonoType*, count);
+       gclass->context = g_new0 (MonoGenericContext, 1);
+       gclass->context->gclass = gclass;
+
+       gclass->klass = g_new0 (MonoClass, 1);
+
+       gtype = mono_metadata_parse_type_full (m, generic_context, MONO_PARSE_TYPE, 0, ptr, &ptr);
+       gclass->container_class = gklass = mono_class_from_mono_type (gtype);
+
+       g_assert ((gclass->context->container = gklass->generic_container) != NULL);
+       count = mono_metadata_decode_value (ptr, &ptr);
 
        /*
         * Create the klass before parsing the type arguments.
@@ -1448,37 +1694,94 @@ do_mono_metadata_parse_generic_inst (MonoType *type, MonoImage *m, const char *p
         * See mcs/tests/gen-23.cs for an example.
         */
 
-       gklass = mono_class_from_mono_type (generic_inst->generic_type);
-       mono_class_init (gklass);
+       gclass->init_pending = TRUE;
 
-       klass->name_space = gklass->name_space;
-       klass->image = m;
-       klass->flags = gklass->flags;
+       mono_class_create_generic (gclass);
 
-       klass->generic_inst = type;
+       gclass->inst = mono_metadata_parse_generic_inst (m, generic_context, count, ptr, &ptr);
 
-       klass->cast_class = klass->element_class = klass;
+       mono_class_create_generic_2 (gclass);
 
-       for (i = 0; i < generic_inst->type_argc; i++)
-               generic_inst->type_argv [i] = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
-       
-       mono_class_initialize_generic (generic_inst->klass, TRUE);
-       
        if (rptr)
                *rptr = ptr;
+
+       /*
+        * 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 (gclass->klass);
+               g_free (gclass);
+
+               type->data.generic_class = cached;
+               return;
+       } 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);
+       }
+
+       gclass->init_pending = FALSE;
 }
 
+/* 
+ * do_mono_metadata_parse_generic_param:
+ * @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.
+ */
 static MonoGenericParam *
-mono_metadata_parse_generic_param (MonoImage *m, const char *ptr, const char **rptr)
+mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContext *generic_context,
+                                  gboolean is_mvar, const char *ptr, const char **rptr)
 {
-       MonoGenericParam *generic_param = g_new0 (MonoGenericParam, 1);
-       
-       generic_param->num = mono_metadata_decode_value (ptr, &ptr);
+       MonoGenericContainer *generic_container;
+       int index;
 
+       index = mono_metadata_decode_value (ptr, &ptr);
        if (rptr)
                *rptr = ptr;
 
-       return generic_param;
+       g_assert (generic_context);
+       if (generic_context->gmethod)
+               generic_container = generic_context->gmethod->container;
+       else if (generic_context->gclass)
+               generic_container = generic_context->gclass->container_class->generic_container;
+       else
+               generic_container = generic_context->container;
+
+       if (!is_mvar) {
+               g_assert (generic_container);
+               if (generic_container->parent) {
+                       /*
+                        * The current MonoGenericContainer is a generic method -> its `parent'
+                        * points to the containing class'es container.
+                        */
+                       generic_container = generic_container->parent;
+               }
+               g_assert (generic_container && !generic_container->is_method);
+               g_assert (index < generic_container->type_argc);
+
+               return &generic_container->type_params [index];
+       } else {
+               g_assert (generic_container && (generic_container->is_method || generic_container->is_signature));
+               g_assert (index < generic_container->type_argc);
+
+               return &generic_container->type_params [index];
+       }
 }
 
 /* 
@@ -1496,7 +1799,8 @@ mono_metadata_parse_generic_param (MonoImage *m, const char *ptr, const char **r
  * This extracts a Type as specified in Partition II (22.2.12) 
  */
 static void
-do_mono_metadata_parse_type (MonoType *type, MonoImage *m, const char *ptr, const char **rptr)
+do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContext *generic_context,
+                            const char *ptr, const char **rptr)
 {
        type->type = mono_metadata_decode_value (ptr, &ptr);
        
@@ -1528,27 +1832,31 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, const char *ptr, cons
                break;
        }
        case MONO_TYPE_SZARRAY: {
-               MonoType *etype = mono_metadata_parse_type (m, MONO_PARSE_MOD_TYPE, 0, ptr, &ptr);
+               MonoType *etype = mono_metadata_parse_type_full (m, generic_context, MONO_PARSE_MOD_TYPE, 0, ptr, &ptr);
                type->data.klass = mono_class_from_mono_type (etype);
+               mono_metadata_free_type (etype);
                break;
        }
        case MONO_TYPE_PTR:
-               type->data.type = mono_metadata_parse_type (m, MONO_PARSE_MOD_TYPE, 0, ptr, &ptr);
+               type->data.type = mono_metadata_parse_type_full (m, generic_context, MONO_PARSE_MOD_TYPE, 0, ptr, &ptr);
                break;
        case MONO_TYPE_FNPTR:
-               type->data.method = mono_metadata_parse_method_signature (m, 0, ptr, &ptr);
+               type->data.method = mono_metadata_parse_method_signature_full (m, generic_context, 0, ptr, &ptr);
                break;
        case MONO_TYPE_ARRAY:
-               type->data.array = mono_metadata_parse_array (m, ptr, &ptr);
+               type->data.array = mono_metadata_parse_array_full (m, generic_context, ptr, &ptr);
                break;
 
        case MONO_TYPE_MVAR:
+               type->data.generic_param = mono_metadata_parse_generic_param (m, generic_context, TRUE, ptr, &ptr);
+               break;
+
        case MONO_TYPE_VAR:
-               type->data.generic_param = mono_metadata_parse_generic_param (m, ptr, &ptr);
+               type->data.generic_param = mono_metadata_parse_generic_param (m, generic_context, FALSE, ptr, &ptr);
                break;
 
        case MONO_TYPE_GENERICINST:
-               do_mono_metadata_parse_generic_inst (type, m, ptr, &ptr);
+               do_mono_metadata_parse_generic_class (type, m, generic_context, ptr, &ptr);
                break;
                
        default:
@@ -1570,7 +1878,18 @@ mono_metadata_free_type (MonoType *type)
 {
        if (type >= builtin_types && type < builtin_types + NBUILTIN_TYPES ())
                return;
+       
        switch (type->type){
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_STRING:
+               if (!type->data.klass)
+                       break;
+               /* fall through */
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_VALUETYPE:
+               if (type == &type->data.klass->byval_arg || type == &type->data.klass->this_arg)
+                       return;
+               break;
        case MONO_TYPE_PTR:
                mono_metadata_free_type (type->data.type);
                break;
@@ -1612,7 +1931,7 @@ hex_dump (const char *buffer, int base, int count)
  * @ptr: Points to the beginning of the Section Data (25.3)
  */
 static void
-parse_section_data (MonoMethodHeader *mh, const unsigned char *ptr)
+parse_section_data (MonoImage *m, MonoMethodHeader *mh, const unsigned char *ptr)
 {
        unsigned char sect_data_flags;
        const unsigned char *sptr;
@@ -1650,9 +1969,8 @@ parse_section_data (MonoMethodHeader *mh, const unsigned char *ptr)
                        mh->clauses = g_new0 (MonoExceptionClause, mh->num_clauses);
                        for (i = 0; i < mh->num_clauses; ++i) {
                                MonoExceptionClause *ec = &mh->clauses [i];
-
+                               guint32 tof_value;
                                if (is_fat) {
-                                       /* we could memcpy and byteswap */
                                        ec->flags = read32 (p);
                                        p += 4;
                                        ec->try_offset = read32 (p);
@@ -1663,7 +1981,7 @@ parse_section_data (MonoMethodHeader *mh, const unsigned char *ptr)
                                        p += 4;
                                        ec->handler_len = read32 (p);
                                        p += 4;
-                                       ec->token_or_filter = read32 (p);
+                                       tof_value = read32 (p);
                                        p += 4;
                                } else {
                                        ec->flags = read16 (p);
@@ -1676,9 +1994,16 @@ parse_section_data (MonoMethodHeader *mh, const unsigned char *ptr)
                                        p += 2;
                                        ec->handler_len = *p;
                                        ++p;
-                                       ec->token_or_filter = read32 (p);
+                                       tof_value = read32 (p);
                                        p += 4;
                                }
+                               if (ec->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+                                       ec->data.filter_offset = tof_value;
+                               } else if (ec->flags == MONO_EXCEPTION_CLAUSE_NONE) {
+                                       ec->data.catch_class = tof_value? mono_class_get (m, tof_value): 0;
+                               } else {
+                                       ec->data.catch_class = NULL;
+                               }
                                /* g_print ("try %d: %x %04x-%04x %04x\n", i, ec->flags, ec->try_offset, ec->try_offset+ec->try_len, ec->try_len); */
                        }
 
@@ -1701,7 +2026,7 @@ parse_section_data (MonoMethodHeader *mh, const unsigned char *ptr)
  * Returns: a MonoMethodHeader.
  */
 MonoMethodHeader *
-mono_metadata_parse_mh (MonoImage *m, const char *ptr)
+mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContext *generic_context, const char *ptr)
 {
        MonoMethodHeader *mh;
        unsigned char flags = *(const unsigned char *) ptr;
@@ -1783,7 +2108,8 @@ mono_metadata_parse_mh (MonoImage *m, const char *ptr)
                mh = g_malloc0 (sizeof (MonoMethodHeader) + (len - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType*));
                mh->num_locals = len;
                for (i = 0; i < len; ++i)
-                       mh->locals [i] = mono_metadata_parse_type (m, MONO_PARSE_LOCAL, 0, locals_ptr, &locals_ptr);
+                       mh->locals [i] = mono_metadata_parse_type_full (
+                               m, generic_context, MONO_PARSE_LOCAL, 0, locals_ptr, &locals_ptr);
        } else {
                mh = g_new0 (MonoMethodHeader, 1);
        }
@@ -1792,10 +2118,16 @@ mono_metadata_parse_mh (MonoImage *m, const char *ptr)
        mh->max_stack = max_stack;
        mh->init_locals = init_locals;
        if (fat_flags & METHOD_HEADER_MORE_SECTS)
-               parse_section_data (mh, (const unsigned char*)ptr);
+               parse_section_data (m, mh, (const unsigned char*)ptr);
        return mh;
 }
 
+MonoMethodHeader *
+mono_metadata_parse_mh (MonoImage *m, const char *ptr)
+{
+       return mono_metadata_parse_mh_full (m, NULL, ptr);
+}
+
 /*
  * mono_metadata_free_mh:
  * @mh: a method header
@@ -1889,8 +2221,6 @@ typedef struct {
        guint32 result;
 } locator_t;
 
-#define CSIZE(x) (sizeof (x) / 4)
-
 /*
  * How the row locator works.
  *
@@ -1973,14 +2303,33 @@ table_locator (const void *a, const void *b)
                return 1;
 }
 
-/*
+static int
+declsec_locator (const void *a, const void *b)
+{
+       locator_t *loc = (locator_t *) a;
+       const char *bb = (const char *) b;
+       guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
+       guint32 col;
+
+       col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
+
+       if (loc->idx == col) {
+               loc->result = table_index;
+               return 0;
+       }
+       if (loc->idx < col)
+               return -1;
+       else
+               return 1;
+}
+
+/**
  * mono_metadata_typedef_from_field:
  * @meta: metadata context
  * @index: FieldDef token
  *
- * Returns the 1-based index into the TypeDef table of the type that
- * declared the field described by @index.
- * Returns 0 if not found.
+ * Returns: the 1-based index into the TypeDef table of the type that
+ * declared the field described by @index, or 0 if not found.
  */
 guint32
 mono_metadata_typedef_from_field (MonoImage *meta, guint32 index)
@@ -2007,9 +2356,8 @@ mono_metadata_typedef_from_field (MonoImage *meta, guint32 index)
  * @meta: metadata context
  * @index: MethodDef token
  *
- * Returns the 1-based index into the TypeDef table of the type that
- * declared the method described by @index.
- * Returns 0 if not found.
+ * Returns: the 1-based index into the TypeDef table of the type that
+ * declared the method described by @index.  0 if not found.
  */
 guint32
 mono_metadata_typedef_from_method (MonoImage *meta, guint32 index)
@@ -2036,11 +2384,11 @@ mono_metadata_typedef_from_method (MonoImage *meta, guint32 index)
  * @meta: metadata context
  * @index: typedef token
  * 
- * Returns and array of interfaces that the @index typedef token implements.
+ * Returns: and array of interfaces that the @index typedef token implements.
  * The number of elemnts in the array is returned in @count.
  */
 MonoClass**
-mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *count)
+mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, guint *count, MonoGenericContext *context)
 {
        MonoTableInfo *tdef = &meta->tables [MONO_TABLE_INTERFACEIMPL];
        locator_t loc;
@@ -2077,13 +2425,20 @@ mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *co
                if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
                        break;
                result = g_renew (MonoClass*, result, i + 1);
-               result [i] = mono_class_get (meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]));
+               result [i] = mono_class_get_full (
+                       meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context);
                *count = ++i;
                ++start;
        }
        return result;
 }
 
+MonoClass**
+mono_metadata_interfaces_from_typedef (MonoImage *meta, guint32 index, guint *count)
+{
+       return mono_metadata_interfaces_from_typedef_full (meta, index, count, NULL);
+}
+
 /*
  * mono_metadata_nested_in_typedef:
  * @meta: metadata context
@@ -2120,8 +2475,7 @@ mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index)
  * 
  * Returns: the 1-based index into the TypeDef table of the first type
  * that is nested inside the type described by @index. The search starts at
- * @start_index.
- * Returns 0 if no such type is found.
+ * @start_index.  returns 0 if no such type is found.
  */
 guint32
 mono_metadata_nesting_typedef (MonoImage *meta, guint32 index, guint32 start_index)
@@ -2153,7 +2507,7 @@ mono_metadata_nesting_typedef (MonoImage *meta, guint32 index, guint32 start_ind
  * @meta: metadata context
  * @index: token representing a type
  * 
- * Returns the info stored in the ClassLAyout table for the given typedef token
+ * Returns: the info stored in the ClassLAyout table for the given typedef token
  * into the @packing and @size pointers.
  * Returns 0 if the info is not found.
  */
@@ -2217,6 +2571,38 @@ mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index)
        return loc.result + 1;
 }
 
+/*
+ * mono_metadata_declsec_from_index:
+ * @meta: metadata context
+ * @index: token representing the parent
+ * 
+ * Returns: the 0-based index into the DeclarativeSecurity table of the first 
+ * attribute which belongs to the metadata object described by @index.
+ * Returns -1 if no such attribute is found.
+ */
+guint32
+mono_metadata_declsec_from_index (MonoImage *meta, guint32 index)
+{
+       MonoTableInfo *tdef = &meta->tables [MONO_TABLE_DECLSECURITY];
+       locator_t loc;
+
+       if (!tdef->base)
+               return -1;
+
+       loc.idx = index;
+       loc.col_idx = MONO_DECL_SECURITY_PARENT;
+       loc.t = tdef;
+
+       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, declsec_locator))
+               return -1;
+
+       /* Find the first entry by searching backwards */
+       while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_DECL_SECURITY_PARENT) == index))
+               loc.result --;
+
+       return loc.result;
+}
+
 #ifdef DEBUG
 static void
 mono_backtrace (int limit)
@@ -2313,8 +2699,19 @@ mono_type_size (MonoType *t, gint *align)
        case MONO_TYPE_TYPEDBYREF:
                return mono_class_value_size (mono_defaults.typed_reference_class, align);
        case MONO_TYPE_GENERICINST: {
-               MonoClass *iclass = mono_class_from_mono_type (t);
-               return mono_type_size (&iclass->byval_arg, align);
+               MonoGenericClass *gclass = t->data.generic_class;
+
+               g_assert (!gclass->inst->is_open && !gclass->klass->generic_container);
+
+               if (gclass->container_class->valuetype) {
+                       if (gclass->container_class->enumtype)
+                               return mono_type_size (gclass->container_class->enum_basetype, align);
+                       else
+                               return mono_class_value_size (gclass->klass, align);
+               } else {
+                       *align = __alignof__(gpointer);
+                       return sizeof (gpointer);
+               }
        }
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
@@ -2370,7 +2767,7 @@ mono_type_stack_size (MonoType *t, gint *align)
                return sizeof (gpointer);
        case MONO_TYPE_TYPEDBYREF:
                *align = __alignof__(gpointer);
-               return sizeof (gpointer) * 2;
+               return sizeof (gpointer) * 3;
        case MONO_TYPE_R4:
                *align = __alignof__(float);
                return sizeof (float);          
@@ -2399,8 +2796,28 @@ mono_type_stack_size (MonoType *t, gint *align)
                }
        }
        case MONO_TYPE_GENERICINST: {
-               MonoClass *iclass = mono_class_from_mono_type (t);
-               return mono_type_stack_size (&iclass->byval_arg, align);
+               MonoGenericClass *gclass = t->data.generic_class;
+
+               g_assert (!gclass->inst->is_open && !gclass->klass->generic_container);
+
+               if (gclass->container_class->valuetype) {
+                       if (gclass->container_class->enumtype)
+                               return mono_type_stack_size (gclass->container_class->enum_basetype, align);
+                       else {
+                               guint32 size = mono_class_value_size (gclass->klass, align);
+
+                               *align = *align + __alignof__(gpointer) - 1;
+                               *align &= ~(__alignof__(gpointer) - 1);
+
+                               size += sizeof (gpointer) - 1;
+                               size &= ~(sizeof (gpointer) - 1);
+
+                               return size;
+                       }
+               } else {
+                       *align = __alignof__(gpointer);
+                       return sizeof (gpointer);
+               }
        }
        default:
                g_error ("type 0x%02x unknown", t->type);
@@ -2408,6 +2825,41 @@ mono_type_stack_size (MonoType *t, gint *align)
        return 0;
 }
 
+gboolean
+mono_metadata_generic_class_is_valuetype (MonoGenericClass *gclass)
+{
+       return gclass->container_class->valuetype;
+}
+
+static gboolean
+_mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
+{
+       int i;
+
+       if ((g1->inst->type_argc != g2->inst->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))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+guint
+mono_metadata_generic_method_hash (MonoGenericMethod *gmethod)
+{
+       return gmethod->inst->id;
+}
+
+gboolean
+mono_metadata_generic_method_equal (MonoGenericMethod *g1, MonoGenericMethod *g2)
+{
+       return (g1->container == g2->container) && (g1->inst == g2->inst);
+}
+
+
 /*
  * mono_metadata_type_hash:
  * @t1: a type
@@ -2431,11 +2883,47 @@ mono_metadata_type_hash (MonoType *t1)
        case MONO_TYPE_ARRAY:
                return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
        case MONO_TYPE_GENERICINST:
-               return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.generic_inst->generic_type);
+               return ((hash << 5) - hash) ^ mono_generic_class_hash (t1->data.generic_class);
        }
        return hash;
 }
 
+static gboolean
+mono_metadata_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2, gboolean signature_only)
+{
+       if (p1 == p2)
+               return TRUE;
+       if (p1->num != p2->num)
+               return FALSE;
+
+       g_assert (p1->owner && p2->owner);
+       if (p1->owner == p2->owner)
+               return TRUE;
+
+       /*
+        * If `signature_only' is true, we're comparing two (method) signatures.
+        * In this case, the owner of two type parameters doesn't need to match.
+        */
+
+       return signature_only;
+}
+
+static gboolean
+mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only)
+{
+       if (c1 == c2)
+               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->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, FALSE);
+       if ((c1->byval_arg.type == MONO_TYPE_MVAR) && (c2->byval_arg.type == MONO_TYPE_MVAR))
+               return mono_metadata_generic_param_equal (
+                       c1->byval_arg.data.generic_param, c2->byval_arg.data.generic_param, signature_only);
+       return FALSE;
+}
+
 /*
  * mono_metadata_type_equal:
  * @t1: a type
@@ -2444,8 +2932,8 @@ mono_metadata_type_hash (MonoType *t1)
  * Determine if @t1 and @t2 represent the same type.
  * Returns: #TRUE if @t1 and @t2 are equal.
  */
-gboolean
-mono_metadata_type_equal (MonoType *t1, MonoType *t2)
+static gboolean
+do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only)
 {
        if (t1->type != t2->type ||
            t1->byref != t2->byref)
@@ -2474,28 +2962,22 @@ mono_metadata_type_equal (MonoType *t1, MonoType *t2)
        case MONO_TYPE_VALUETYPE:
        case MONO_TYPE_CLASS:
        case MONO_TYPE_SZARRAY:
-               return t1->data.klass == t2->data.klass;
+               return mono_metadata_class_equal (t1->data.klass, t2->data.klass, signature_only);
        case MONO_TYPE_PTR:
-               return mono_metadata_type_equal (t1->data.type, t2->data.type);
+               return do_mono_metadata_type_equal (t1->data.type, t2->data.type, signature_only);
        case MONO_TYPE_ARRAY:
                if (t1->data.array->rank != t2->data.array->rank)
                        return FALSE;
-               return t1->data.array->eklass == t2->data.array->eklass;
-       case MONO_TYPE_GENERICINST: {
-               int i;
-               if (t1->data.generic_inst->type_argc != t2->data.generic_inst->type_argc)
-                       return FALSE;
-               if (!mono_metadata_type_equal (t1->data.generic_inst->generic_type, t2->data.generic_inst->generic_type))
-                       return FALSE;
-               for (i = 0; i < t1->data.generic_inst->type_argc; ++i) {
-                       if (!mono_metadata_type_equal (t1->data.generic_inst->type_argv [i], t2->data.generic_inst->type_argv [i]))
-                               return FALSE;
-               }
-               return TRUE;
-       }
+               return mono_metadata_class_equal (t1->data.array->eklass, t2->data.array->eklass, signature_only);
+       case MONO_TYPE_GENERICINST:
+               return _mono_metadata_generic_class_equal (
+                       t1->data.generic_class, t2->data.generic_class, signature_only);
        case MONO_TYPE_VAR:
+               return mono_metadata_generic_param_equal (
+                       t1->data.generic_param, t2->data.generic_param, FALSE);
        case MONO_TYPE_MVAR:
-               return t1->data.generic_param->num == t2->data.generic_param->num;
+               return mono_metadata_generic_param_equal (
+                       t1->data.generic_param, t2->data.generic_param, signature_only);
        default:
                g_error ("implement type compare for %0x!", t1->type);
                return FALSE;
@@ -2504,7 +2986,13 @@ mono_metadata_type_equal (MonoType *t1, MonoType *t2)
        return FALSE;
 }
 
-/*
+gboolean
+mono_metadata_type_equal (MonoType *t1, MonoType *t2)
+{
+       return do_mono_metadata_type_equal (t1, t2, FALSE);
+}
+
+/**
  * mono_metadata_signature_equal:
  * @sig1: a signature
  * @sig2: another signature
@@ -2522,18 +3010,27 @@ mono_metadata_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *s
            sig1->param_count != sig2->param_count)
                return FALSE;
 
+       /*
+        * We're just comparing the signatures of two methods here:
+        *
+        * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
+        * U and V are equal here.
+        *
+        * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
+        */
+
        for (i = 0; i < sig1->param_count; i++) { 
                MonoType *p1 = sig1->params[i];
                MonoType *p2 = sig2->params[i];
                
-               //if (p1->attrs != p2->attrs)
-               //      return FALSE;
-               
-               if (!mono_metadata_type_equal (p1, p2))
+               /if (p1->attrs != p2->attrs)
+                       return FALSE;
+               */
+               if (!do_mono_metadata_type_equal (p1, p2, TRUE))
                        return FALSE;
        }
 
-       if (!mono_metadata_type_equal (sig1->ret, sig2->ret))
+       if (!do_mono_metadata_type_equal (sig1->ret, sig2->ret, TRUE))
                return FALSE;
        return TRUE;
 }
@@ -2564,9 +3061,9 @@ mono_metadata_encode_value (guint32 value, char *buf, char **endbuf)
 {
        char *p = buf;
        
-       if (value <= 127)
+       if (value < 0x80)
                *p++ = value;
-       else if (value <= 16384) {
+       else if (value < 0x4000) {
                p [0] = 0x80 | (value >> 8);
                p [1] = value & 0xff;
                p += 2;
@@ -2660,16 +3157,16 @@ mono_metadata_get_constant_index (MonoImage *meta, guint32 token, guint32 hint)
        guint32 index = mono_metadata_token_index (token);
 
        tdef = &meta->tables [MONO_TABLE_CONSTANT];
-       index <<= HASCONSTANT_BITS;
+       index <<= MONO_HASCONSTANT_BITS;
        switch (mono_metadata_token_table (token)) {
        case MONO_TABLE_FIELD:
-               index |= HASCONSTANT_FIEDDEF;
+               index |= MONO_HASCONSTANT_FIEDDEF;
                break;
        case MONO_TABLE_PARAM:
-               index |= HASCONSTANT_PARAM;
+               index |= MONO_HASCONSTANT_PARAM;
                break;
        case MONO_TABLE_PROPERTY:
-               index |= HASCONSTANT_PROPERTY;
+               index |= MONO_HASCONSTANT_PROPERTY;
                break;
        default:
                g_warning ("Not a valid token for the constant table: 0x%08x", token);
@@ -2750,7 +3247,7 @@ mono_metadata_methods_from_event   (MonoImage *meta, guint32 index, guint *end_i
 
        loc.t = msemt;
        loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
-       loc.idx = ((index + 1) << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT; /* Method association coded index */
+       loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT; /* Method association coded index */
 
        if (!bsearch (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
                return 0;
@@ -2838,7 +3335,7 @@ mono_metadata_methods_from_property   (MonoImage *meta, guint32 index, guint *en
 
        loc.t = msemt;
        loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
-       loc.idx = ((index + 1) << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_PROPERTY; /* Method association coded index */
+       loc.idx = ((index + 1) << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY; /* Method association coded index */
 
        if (!bsearch (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
                return 0;
@@ -2875,7 +3372,7 @@ mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
 
        loc.t = tdef;
        loc.col_idx = MONO_IMPLMAP_MEMBER;
-       loc.idx = ((method_idx + 1) << MEMBERFORWD_BITS) | MEMBERFORWD_METHODDEF;
+       loc.idx = ((method_idx + 1) << MONO_MEMBERFORWD_BITS) | MONO_MEMBERFORWD_METHODDEF;
 
        if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return 0;
@@ -2891,7 +3388,7 @@ mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
  * token.
  */
 MonoType *
-mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
+mono_type_create_from_typespec_full (MonoImage *image, MonoGenericContext *generic_context, guint32 type_spec)
 {
        guint32 idx = mono_metadata_token_index (type_spec);
        MonoTableInfo *t;
@@ -2922,13 +3419,19 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
                ptr++;
        }
 
-       do_mono_metadata_parse_type (type, image, ptr, &ptr);
+       do_mono_metadata_parse_type (type, image, generic_context, ptr, &ptr);
 
        mono_loader_unlock ();
 
        return type;
 }
 
+MonoType *
+mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
+{
+       return mono_type_create_from_typespec_full (image, NULL, type_spec);
+}
+
 MonoMarshalSpec *
 mono_metadata_parse_marshal_spec (MonoImage *image, const char *ptr)
 {
@@ -2981,6 +3484,16 @@ mono_metadata_parse_marshal_spec (MonoImage *image, const char *ptr)
        return res;
 }
 
+void 
+mono_metadata_free_marshal_spec (MonoMarshalSpec *spec)
+{
+       if (spec->native == MONO_NATIVE_CUSTOM) {
+               g_free (spec->data.custom_data.custom_name);
+               g_free (spec->data.custom_data.cookie);
+       }
+       g_free (spec);
+}
+       
 guint32
 mono_type_to_unmanaged (MonoType *type, MonoMarshalSpec *mspec, gboolean as_field,
                        gboolean unicode, MonoMarshalConv *conv) 
@@ -3105,6 +3618,16 @@ handle_enum:
                        case MONO_NATIVE_IUNKNOWN:
                                *conv = MONO_MARSHAL_CONV_OBJECT_IUNKNOWN;
                                return MONO_NATIVE_IUNKNOWN;
+                       case MONO_NATIVE_FUNC:
+                               if (t == MONO_TYPE_CLASS && (type->data.klass == mono_defaults.multicastdelegate_class ||
+                                                                                        type->data.klass == mono_defaults.delegate_class || 
+                                                                                        type->data.klass->parent == mono_defaults.multicastdelegate_class)) {
+                                       *conv = MONO_MARSHAL_CONV_DEL_FTN;
+                                       return MONO_NATIVE_FUNC;
+                               }
+                               else
+                                       /* Fall through */
+                                       ;
                        default:
                                g_error ("cant marshal object as native type %02x", mspec->native);
                        }
@@ -3137,7 +3660,7 @@ mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
 
        loc.t = tdef;
        loc.col_idx = MONO_FIELD_MARSHAL_PARENT;
-       loc.idx = ((idx + 1) << HAS_FIELD_MARSHAL_BITS) | (is_field? HAS_FIELD_MARSHAL_FIELDSREF: HAS_FIELD_MARSHAL_PARAMDEF);
+       loc.idx = ((idx + 1) << MONO_HAS_FIELD_MARSHAL_BITS) | (is_field? MONO_HAS_FIELD_MARSHAL_FIELDSREF: MONO_HAS_FIELD_MARSHAL_PARAMDEF);
 
        if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
                return NULL;
@@ -3148,11 +3671,11 @@ mono_metadata_get_marshal_info (MonoImage *meta, guint32 idx, gboolean is_field)
 static MonoMethod*
 method_from_method_def_or_ref (MonoImage *m, guint32 tok)
 {
-       guint32 idx = tok >> METHODDEFORREF_BITS;
-       switch (tok & METHODDEFORREF_MASK) {
-       case METHODDEFORREF_METHODDEF:
+       guint32 idx = tok >> MONO_METHODDEFORREF_BITS;
+       switch (tok & MONO_METHODDEFORREF_MASK) {
+       case MONO_METHODDEFORREF_METHODDEF:
                return mono_get_method (m, MONO_TOKEN_METHOD_DEF | idx, NULL);
-       case METHODDEFORREF_METHODREF:
+       case MONO_METHODDEFORREF_METHODREF:
                return mono_get_method (m, MONO_TOKEN_MEMBER_REF | idx, NULL);
        }
        g_assert_not_reached ();
@@ -3229,7 +3752,7 @@ mono_guid_to_string (const guint8 *guid)
 }
 
 static MonoClass**
-get_constraints (MonoImage *image, int owner)
+get_constraints (MonoImage *image, int owner, MonoGenericContext *context)
 {
        MonoTableInfo *tdef  = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
        guint32 cols [MONO_GENPARCONSTRAINT_SIZE];
@@ -3243,7 +3766,7 @@ get_constraints (MonoImage *image, int owner)
                mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE);
                if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) {
                        token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]);
-                       klass = mono_class_get (image, token);
+                       klass = mono_class_get_full (image, token, context);
                        cons = g_list_append (cons, klass);
                        ++found;
                } else {
@@ -3262,12 +3785,14 @@ get_constraints (MonoImage *image, int owner)
        return res;
 }
 
-MonoGenericParam *
-mono_metadata_load_generic_params (MonoImage *image, guint32 token, guint32 *num)
+MonoGenericContainer *
+mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container)
 {
        MonoTableInfo *tdef  = &image->tables [MONO_TABLE_GENERICPARAM];
        guint32 cols [MONO_GENERICPARAM_SIZE];
-       guint32 i, owner, last_num, n;
+       guint32 i, owner = 0, last_num, n;
+       MonoGenericContainer *container;
+       MonoGenericClass *gclass;
        MonoGenericParam *params;
 
        if (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
@@ -3276,10 +3801,9 @@ mono_metadata_load_generic_params (MonoImage *image, guint32 token, guint32 *num
                owner = MONO_TYPEORMETHOD_METHOD;
        else {
                g_error ("wrong token %x to load_generics_params", token);
+               return NULL;
        }
        owner |= mono_metadata_token_index (token) << MONO_TYPEORMETHOD_BITS;
-       if (num)
-               *num = 0;
        if (!tdef->base)
                return NULL;
 
@@ -3288,27 +3812,139 @@ mono_metadata_load_generic_params (MonoImage *image, guint32 token, guint32 *num
                if (cols [MONO_GENERICPARAM_OWNER] == owner)
                        break;
        }
-       last_num = 0;
+       last_num = i;
        if (i >= tdef->rows)
                return NULL;
        params = NULL;
        n = 0;
+       container = g_new0 (MonoGenericContainer, 1);
        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]);
-               params [n - 1].constraints = get_constraints (image, i + 1);
                if (++i >= tdef->rows)
                        break;
                mono_metadata_decode_row (tdef, i, cols, MONO_GENERICPARAM_SIZE);
        } while (cols [MONO_GENERICPARAM_OWNER] == owner);
-       
-       if (num)
-               *num = n;
-       return params;
+
+       container->type_argc = n;
+       container->type_params = params;
+       container->parent = parent_container;
+
+       if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
+               container->is_method = 1;
+
+       container->context.container = container;
+
+       for (i = 0; i < n; i++)
+               params [i].constraints = get_constraints (image, last_num + i + 1, &container->context);
+
+       return container;
+}
+
+gboolean
+mono_type_is_byref (MonoType *type)
+{
+       return type->byref;
+}
+
+int
+mono_type_get_type (MonoType *type)
+{
+       return type->type;
+}
+
+/* For MONO_TYPE_FNPTR */
+MonoMethodSignature*
+mono_type_get_signature (MonoType *type)
+{
+       return type->data.method;
+}
+
+/* For MONO_TYPE_CLASS, VALUETYPE */
+MonoClass*
+mono_type_get_class (MonoType *type)
+{
+       return type->data.klass;
+}
+
+/* For MONO_TYPE_ARRAY */
+MonoArrayType*
+mono_type_get_array_type (MonoType *type)
+{
+       return type->data.array;
+}
+
+MonoClass*
+mono_type_get_modifiers (MonoType *type, gboolean *is_required, gpointer *iter)
+{
+       /* FIXME: implement */
+       return NULL;
+}
+
+MonoType*
+mono_signature_get_return_type (MonoMethodSignature *sig)
+{
+       return sig->ret;
+}
+
+MonoType*
+mono_signature_get_params (MonoMethodSignature *sig, gpointer *iter)
+{
+       MonoType** type;
+       if (!iter)
+               return NULL;
+       if (!*iter) {
+               /* start from the first */
+               if (sig->param_count) {
+                       *iter = &sig->params [0];
+                       return sig->params [0];
+               } else {
+                       /* no method */
+                       return NULL;
+               }
+       }
+       type = *iter;
+       type++;
+       if (type < &sig->params [sig->param_count]) {
+               *iter = type;
+               return *type;
+       }
+       return NULL;
+}
+
+guint32
+mono_signature_get_param_count (MonoMethodSignature *sig)
+{
+       return sig->param_count;
+}
+
+guint32
+mono_signature_get_call_conv (MonoMethodSignature *sig)
+{
+       return sig->call_convention;
+}
+
+int
+mono_signature_vararg_start (MonoMethodSignature *sig)
+{
+       return sig->sentinelpos;
+}
+
+gboolean
+mono_signature_is_instance (MonoMethodSignature *sig)
+{
+       return sig->hasthis;
+}
+
+gboolean
+mono_signature_explicit_this (MonoMethodSignature *sig)
+{
+       return sig->explicit_this;
 }