2008-01-17 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata.c
index fbe9737341655296bda3071f406733bd2138e6fe..d2737b2709413b55bc44a91e78c8d5165a2f99d3 100644 (file)
@@ -954,7 +954,10 @@ mono_metadata_decode_row (const MonoTableInfo *t, int idx, guint32 *res, int res
 {
        guint32 bitfield = t->size_bitfield;
        int i, count = mono_metadata_table_count (bitfield);
-       const char *data = t->base + idx * t->row_size;
+       const char *data;
+
+       g_assert (idx < t->rows);
+       data = t->base + idx * t->row_size;
        
        g_assert (res_size == count);
        
@@ -989,10 +992,12 @@ mono_metadata_decode_row_col (const MonoTableInfo *t, int idx, guint col)
 {
        guint32 bitfield = t->size_bitfield;
        int i;
-       register const char *data = t->base + idx * t->row_size;
+       register const char *data
        register int n;
        
+       g_assert (idx < t->rows);
        g_assert (col < mono_metadata_table_count (bitfield));
+       data = t->base + idx * t->row_size;
 
        n = mono_metadata_table_size (bitfield, 0);
        for (i = 0; i < col; ++i) {
@@ -1408,21 +1413,35 @@ mono_generic_inst_hash (gconstpointer data)
 }
 
 static gboolean
-mono_generic_inst_equal (gconstpointer ka, gconstpointer kb)
+mono_generic_inst_equal_full (const MonoGenericInst *a, const MonoGenericInst *b, gboolean signature_only)
 {
-       const MonoGenericInst *a = (const MonoGenericInst *) ka;
-       const MonoGenericInst *b = (const MonoGenericInst *) kb;
        int i;
 
+       if (a->id && b->id) {
+               if (a->id == b->id)
+                       return TRUE;
+               if (!signature_only)
+                       return FALSE;
+       }
+
        if (a->is_open != b->is_open || a->type_argc != b->type_argc)
                return FALSE;
        for (i = 0; i < a->type_argc; ++i) {
-               if (!do_mono_metadata_type_equal (a->type_argv [i], b->type_argv [i], FALSE))
+               if (!do_mono_metadata_type_equal (a->type_argv [i], b->type_argv [i], signature_only))
                        return FALSE;
        }
        return TRUE;
 }
 
+static gboolean
+mono_generic_inst_equal (gconstpointer ka, gconstpointer kb)
+{
+       const MonoGenericInst *a = (const MonoGenericInst *) ka;
+       const MonoGenericInst *b = (const MonoGenericInst *) kb;
+
+       return mono_generic_inst_equal_full (a, b, FALSE);
+}
+
 static guint
 mono_generic_class_hash (gconstpointer data)
 {
@@ -1430,6 +1449,7 @@ mono_generic_class_hash (gconstpointer data)
        guint hash = mono_metadata_type_hash (&gclass->container_class->byval_arg);
 
        hash *= 13;
+       hash += gclass->is_tb_open;
        hash += mono_metadata_generic_context_hash (&gclass->context);
 
        return hash;
@@ -1930,8 +1950,7 @@ mono_metadata_free_inflated_signature (MonoMethodSignature *sig)
                if (sig->params [i])
                        mono_metadata_free_type (sig->params [i]);
        }
-       /* FIXME: The signature is allocated from a mempool */
-       //g_free (sig);
+       g_free (sig);
 }
 
 static gboolean
@@ -2043,6 +2062,23 @@ retry:
                goto retry;
        case MONO_TYPE_FNPTR:
                return signature_in_image (type->data.method, image);
+       case MONO_TYPE_VAR:
+               if (type->data.generic_param->owner) {
+                       g_assert (!type->data.generic_param->owner->is_method);
+                       return type->data.generic_param->owner->owner.klass->image == image;
+               } else {
+                       return type->data.generic_param->image == image;
+               }
+       case MONO_TYPE_MVAR:
+               if (type->data.generic_param->owner) {
+                       g_assert (type->data.generic_param->owner->is_method);
+                       if (!type->data.generic_param->owner->owner.method)
+                               /* RefEmit created generic param whose method is not finished */
+                               return FALSE;
+                       return type->data.generic_param->owner->owner.method->klass->image == image;
+               } else {
+                       return type->data.generic_param->image == image;
+               }
        default:
                /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type () */
                return image == mono_class_from_mono_type (type)->image;
@@ -2173,7 +2209,7 @@ free_generic_class (MonoGenericClass *gclass)
        int i;
 
        /* FIXME: The dynamic case */
-       if (gclass->cached_class && !gclass->cached_class->image->dynamic) {
+       if (gclass->cached_class && !gclass->cached_class->image->dynamic && !mono_generic_class_is_generic_type_definition (gclass)) {
                MonoClass *class = gclass->cached_class;
 
                /* Allocated in mono_class_init () */
@@ -2299,6 +2335,16 @@ mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
        return ginst;
 }
 
+static gboolean
+mono_metadata_is_type_builder_generic_type_definition (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
+{
+       MonoGenericContainer *container = container_class->generic_container; 
+
+       if (!is_dynamic || container_class->wastypebuilder || container->type_argc != inst->type_argc)
+               return FALSE;
+       return inst == container->context.class_inst;
+}
+
 /*
  * mono_metadata_lookup_generic_class:
  *
@@ -2309,12 +2355,14 @@ MonoGenericClass *
 mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
 {
        MonoGenericClass *gclass;
-
        MonoGenericClass helper;
+       gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic);
+
        helper.container_class = container_class;
        helper.context.class_inst = inst;
        helper.context.method_inst = NULL;
        helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
+       helper.is_tb_open = is_tb_open;
        helper.cached_class = NULL;
 
        mono_loader_lock ();
@@ -2337,9 +2385,12 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
                gclass = g_new0 (MonoGenericClass, 1);
        }
 
+       gclass->is_tb_open = is_tb_open;
        gclass->container_class = container_class;
        gclass->context.class_inst = inst;
        gclass->context.method_inst = NULL;
+       if (inst == container_class->generic_container->context.class_inst && !is_tb_open)
+               gclass->cached_class = container_class;
 
        g_hash_table_insert (generic_class_cache, gclass, gclass);
 
@@ -2485,6 +2536,7 @@ mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_c
                param->name = mono_mempool_alloc0 (m->mempool, 8);
                sprintf ((char*)param->name, "%d", index);
                param->num = index;
+               param->image = m;
 
                return param;
        }
@@ -3624,6 +3676,12 @@ mono_type_size (MonoType *t, int *align)
  */
 int
 mono_type_stack_size (MonoType *t, int *align)
+{
+       return mono_type_stack_size_internal (t, align, FALSE);
+}
+
+int
+mono_type_stack_size_internal (MonoType *t, int *align, gboolean allow_open)
 {
        int tmp;
 
@@ -3674,7 +3732,7 @@ mono_type_stack_size (MonoType *t, int *align)
                guint32 size;
 
                if (t->data.klass->enumtype)
-                       return mono_type_stack_size (t->data.klass->enum_basetype, align);
+                       return mono_type_stack_size_internal (t->data.klass->enum_basetype, align, allow_open);
                else {
                        size = mono_class_value_size (t->data.klass, (guint32*)align);
 
@@ -3691,11 +3749,12 @@ mono_type_stack_size (MonoType *t, int *align)
                MonoGenericClass *gclass = t->data.generic_class;
                MonoClass *container_class = gclass->container_class;
 
-               g_assert (!gclass->context.class_inst->is_open);
+               if (!allow_open)
+                       g_assert (!gclass->context.class_inst->is_open);
 
                if (container_class->valuetype) {
                        if (container_class->enumtype)
-                               return mono_type_stack_size (container_class->enum_basetype, align);
+                               return mono_type_stack_size_internal (container_class->enum_basetype, align, allow_open);
                        else {
                                guint32 size = mono_class_value_size (mono_class_from_mono_type (t), (guint32*)align);
 
@@ -3734,19 +3793,29 @@ mono_metadata_generic_class_is_valuetype (MonoGenericClass *gclass)
 static gboolean
 _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
 {
-       int i;
        MonoGenericInst *i1 = g1->context.class_inst;
        MonoGenericInst *i2 = g2->context.class_inst;
 
-       if (i1->type_argc != i2->type_argc || g1->is_dynamic != g2->is_dynamic)
+       if (g1->is_dynamic != g2->is_dynamic)
                return FALSE;
        if (!mono_metadata_class_equal (g1->container_class, g2->container_class, signature_only))
                return FALSE;
-       for (i = 0; i < i1->type_argc; ++i) {
-               if (!do_mono_metadata_type_equal (i1->type_argv [i], i2->type_argv [i], signature_only))
-                       return FALSE;
-       }
-       return TRUE;
+       if (!mono_generic_inst_equal_full (i1, i2, signature_only))
+               return FALSE;
+       return g1->is_tb_open == g2->is_tb_open;
+}
+
+static gboolean
+_mono_metadata_generic_class_container_equal (const MonoGenericClass *g1, MonoClass *c2, gboolean signature_only)
+{
+       MonoGenericInst *i1 = g1->context.class_inst;
+       MonoGenericInst *i2 = c2->generic_container->context.class_inst;
+
+       if (!mono_metadata_class_equal (g1->container_class, c2, signature_only))
+               return FALSE;
+       if (!mono_generic_inst_equal_full (i1, i2, signature_only))
+               return FALSE;
+       return !g1->is_tb_open;
 }
 
 guint
@@ -3821,6 +3890,10 @@ mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only
                return TRUE;
        if (c1->generic_class && c2->generic_class)
                return _mono_metadata_generic_class_equal (c1->generic_class, c2->generic_class, signature_only);
+       if (c1->generic_class && c2->generic_container)
+               return _mono_metadata_generic_class_container_equal (c1->generic_class, c2, signature_only);
+       if (c1->generic_container && c2->generic_class)
+               return _mono_metadata_generic_class_container_equal (c2->generic_class, c1, signature_only);
        if ((c1->byval_arg.type == MONO_TYPE_VAR) && (c2->byval_arg.type == MONO_TYPE_VAR))
                return mono_metadata_generic_param_equal (
                        c1->byval_arg.data.generic_param, c2->byval_arg.data.generic_param, signature_only);
@@ -3933,6 +4006,23 @@ mono_metadata_type_equal (MonoType *t1, MonoType *t2)
        return do_mono_metadata_type_equal (t1, t2, FALSE);
 }
 
+/**
+ * mono_metadata_type_equal_full:
+ * @t1: a type
+ * @t2: another type
+ * @signature_only: if signature only comparison should be made
+ *
+ * Determine if @t1 and @t2 are signature compatible if @signature_only is #TRUE, otherwise
+ * behaves the same way as mono_metadata_type_equal.
+ * The function mono_metadata_type_equal(a, b) is just a shortcut for mono_metadata_type_equal_full(a, b, FALSE).
+ * Returns: #TRUE if @t1 and @t2 are equal taking @signature_only into account.
+ */
+gboolean
+mono_metadata_type_equal_full (MonoType *t1, MonoType *t2, gboolean signature_only)
+{
+       return do_mono_metadata_type_equal (t1, t2, signature_only);
+}
+
 /**
  * mono_metadata_signature_equal:
  * @sig1: a signature