Sat Jan 8 19:03:26 CET 2005 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / class.c
index 58b79b0e94b9bed64eba64eb8385c2c8fe5995b9..361f4745a5a202d35722855b3f0868c33d5e4077 100644 (file)
@@ -222,7 +222,7 @@ mono_type_get_underlying_type (MonoType *type)
                        return type->data.klass->enum_basetype;
                break;
        case MONO_TYPE_GENERICINST:
-               return mono_type_get_underlying_type (type->data.generic_class->generic_type);
+               return mono_type_get_underlying_type (&type->data.generic_class->container_class->byval_arg);
        default:
                break;
        }
@@ -247,7 +247,7 @@ mono_class_is_open_constructed_type (MonoType *t)
                MonoGenericClass *gclass = t->data.generic_class;
                int i;
 
-               if (mono_class_is_open_constructed_type (gclass->generic_type))
+               if (mono_class_is_open_constructed_type (&gclass->container_class->byval_arg))
                        return TRUE;
                for (i = 0; i < gclass->inst->type_argc; i++)
                        if (mono_class_is_open_constructed_type (gclass->inst->type_argv [i]))
@@ -259,6 +259,44 @@ mono_class_is_open_constructed_type (MonoType *t)
        }
 }
 
+static MonoGenericClass *
+inflate_generic_class (MonoGenericClass *ogclass, MonoGenericContext *context)
+{
+       MonoGenericClass *ngclass, *cached;
+
+       if (ogclass->is_dynamic) {
+               MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
+               ngclass = &dgclass->generic_class;
+               ngclass->is_dynamic = 1;
+       } else
+               ngclass = g_new0 (MonoGenericClass, 1);
+
+       *ngclass = *ogclass;
+
+       ngclass->inst = mono_metadata_inflate_generic_inst (ogclass->inst, context);
+
+       ngclass->klass = NULL;
+
+       ngclass->context = g_new0 (MonoGenericContext, 1);
+       ngclass->context->container = context->container;
+       ngclass->context->gclass = ngclass;
+
+       ngclass->initialized = FALSE;
+
+       mono_loader_lock ();
+       cached = mono_metadata_lookup_generic_class (ngclass);
+       mono_loader_unlock ();
+       if (cached) {
+               g_free (ngclass);
+               return cached;
+       }
+
+       mono_class_create_generic (ngclass);
+       mono_class_create_generic_2 (ngclass);
+
+       return ngclass;
+}
+
 static MonoType*
 inflate_generic_type (MonoType *type, MonoGenericContext *context)
 {
@@ -287,47 +325,25 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context)
                return nt;
        }
        case MONO_TYPE_GENERICINST: {
-               MonoGenericClass *ogclass = type->data.generic_class;
-               MonoGenericClass *ngclass, *cached;
+               MonoGenericClass *ngclass = inflate_generic_class (type->data.generic_class, context);
+               MonoType *nt = dup_type (type, type);
+               nt->data.generic_class = ngclass;
+               return nt;
+       }
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_VALUETYPE: {
+               MonoClass *klass = type->data.klass;
+               MonoGenericClass *gclass;
                MonoType *nt;
-               int i;
-
-               ngclass = g_new0 (MonoGenericClass, 1);
-               *ngclass = *ogclass;
 
-               ngclass->inst = mono_metadata_inflate_generic_inst (ogclass->inst, context);
-
-               ngclass->klass = NULL;
-
-               ngclass->context = g_new0 (MonoGenericContext, 1);
-               ngclass->context->container = ngclass->container;
-               ngclass->context->gclass = ngclass;
-
-               ngclass->dynamic_info = NULL;
-               ngclass->initialized = FALSE;
-
-               mono_loader_lock ();
-               cached = mono_metadata_lookup_generic_class (ngclass);
-               if (cached) {
-                       g_free (ngclass);
-                       mono_loader_unlock ();
-
-                       nt = dup_type (type, type);
-                       nt->data.generic_class = cached;
-                       return nt;
-               }
-
-               mono_class_create_generic (ngclass);
-               mono_class_create_generic_2 (ngclass);
+               if (!klass->generic_container)
+                       return NULL;
 
-               mono_stats.generic_instance_count++;
-               mono_stats.generics_metadata_size += sizeof (MonoGenericClass) +
-                       sizeof (MonoGenericContext) +
-                       ngclass->inst->type_argc * sizeof (MonoType);
+               gclass = inflate_generic_class (klass->generic_container->context.gclass, context);
 
                nt = dup_type (type, type);
-               nt->data.generic_class = ngclass;
-               mono_loader_unlock ();
+               nt->type = MONO_TYPE_GENERICINST;
+               nt->data.generic_class = gclass;
                return nt;
        }
        default:
@@ -348,14 +364,16 @@ mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
        return inflated;
 }
 
-static MonoMethodSignature*
-inflate_generic_signature (MonoImage *image, MonoMethodSignature *sig,
-                          MonoGenericContext *context)
+MonoMethodSignature*
+mono_class_inflate_generic_signature (MonoImage *image, MonoMethodSignature *sig, MonoGenericContext *context)
 {
        MonoMethodSignature *res;
        gboolean is_open;
        int i;
 
+       if (!context)
+               return sig;
+
        res = mono_metadata_signature_alloc (image, sig->param_count);
        res->ret = mono_class_inflate_generic_type (sig->ret, context);
        is_open = mono_class_is_open_constructed_type (res->ret);
@@ -368,6 +386,7 @@ inflate_generic_signature (MonoImage *image, MonoMethodSignature *sig,
        res->explicit_this = sig->explicit_this;
        res->call_convention = sig->call_convention;
        res->generic_param_count = sig->generic_param_count;
+       res->sentinelpos = sig->sentinelpos;
        res->has_type_parameters = is_open;
        res->is_inflated = 1;
        return res;
@@ -391,6 +410,27 @@ inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context)
        return res;
 }
 
+static MonoGenericContext *
+inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with)
+{
+       MonoGenericContext *res = g_new0 (MonoGenericContext, 1);
+
+       res->container = context->container;
+
+       if (context->gclass)
+               res->gclass = inflate_generic_class (context->gclass, inflate_with);
+
+       if (context->gmethod) {
+               res->gmethod = g_new0 (MonoGenericMethod, 1);
+
+               res->gmethod->container = context->gmethod->container;
+               res->gmethod->inst = mono_metadata_inflate_generic_inst (context->gmethod->inst, inflate_with);
+       } else
+               res->gmethod = inflate_with->gmethod;
+
+       return res;
+}
+
 MonoMethod*
 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context,
                                   MonoClass *klass)
@@ -402,43 +442,61 @@ mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *conte
            (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
                return method;
 
+       if (method->is_inflated || method->signature->is_inflated) {
+               MonoMethodInflated *imethod = (MonoMethodInflated *) method;
+
+               context = inflate_generic_context (imethod->context, context);
+               method = imethod->declaring;
+       }
+
        mono_stats.inflated_method_count++;
-       mono_stats.generics_metadata_size +=
-               sizeof (MonoMethodInflated) - sizeof (MonoMethodNormal);
 
        result = g_new0 (MonoMethodInflated, 1);
        result->nmethod = *(MonoMethodNormal*)method;
+       result->nmethod.method.is_inflated = 1;
+       result->context = context;
+       result->declaring = method;
 
-       if (mono_method_get_header (method))
-               result->nmethod.header = inflate_generic_header (
-                       mono_method_get_header (method), context);
+       if (result->nmethod.method.klass->generic_class)
+               result->nmethod.method.klass = result->nmethod.method.klass->generic_class->container_class;
 
-       if (klass)
-               rklass = result->nmethod.method.klass = klass;
-       else {
-               MonoType *declaring = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
-               rklass = result->nmethod.method.klass = mono_class_from_mono_type (declaring);
-       }
+       return (MonoMethod *) result;
+}
 
-       result->nmethod.method.signature = inflate_generic_signature (
-               method->klass->image, method->signature, context);
+MonoMethod *
+mono_get_inflated_method (MonoMethod *method)
+{
+       MonoMethodInflated *imethod, *res;
+       MonoMethodHeader *mh;
+       MonoType *dtype;
+       MonoClass *rklass;
 
-       if (context->gmethod) {
-               result->context = g_new0 (MonoGenericContext, 1);
-               result->context->container = context->gmethod->container;
-               result->context->gmethod = context->gmethod;
-               result->context->gclass = rklass->generic_class;
+       if (!method->is_inflated)
+               return method;
 
-               mono_stats.generics_metadata_size += sizeof (MonoGenericContext);
-       } else if (rklass->generic_class)
-               result->context = rklass->generic_class->context;
+       imethod = (MonoMethodInflated *) method;
+       if (imethod->inflated)
+               return (MonoMethod *) imethod->inflated;
 
-       if (method->signature->is_inflated)
-               result->declaring = ((MonoMethodInflated *) method)->declaring;
-       else
-               result->declaring = method;
+       mono_stats.inflated_method_count_2++;
+       mono_stats.generics_metadata_size +=
+               sizeof (MonoMethodInflated) - sizeof (MonoMethodNormal);
 
-       return (MonoMethod *) result;
+       res = g_new0 (MonoMethodInflated, 1);
+       *res = *imethod;
+       res->inflated = imethod->inflated = res;
+
+       mh = mono_method_get_header (method);
+       if (mh)
+               res->nmethod.header = inflate_generic_header (mh, imethod->context);
+
+       dtype = mono_class_inflate_generic_type (&method->klass->byval_arg, imethod->context);
+       rklass = res->nmethod.method.klass = mono_class_from_mono_type (dtype);
+
+       res->nmethod.method.signature = mono_class_inflate_generic_signature (
+               method->klass->image, method->signature, imethod->context);
+
+       return (MonoMethod *) res;
 }
 
 /** 
@@ -521,8 +579,8 @@ class_compute_field_layout (MonoClass *class)
                if (class->generic_container)
                        container = class->generic_container;
                else if (class->generic_class) {
-                       g_assert (class->generic_class->container);
-                       container = class->generic_class->container;
+                       container = class->generic_class->container_class->generic_container;
+                       g_assert (container);
                }
                field->type = mono_metadata_parse_type_full (
                        m, (MonoGenericContext *) container, MONO_PARSE_FIELD,
@@ -965,7 +1023,7 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum)
        MonoMethod **vtable;
        int i, max_vtsize = 0, max_iid, cur_slot = 0;
        GPtrArray *ifaces;
-       MonoGHashTable *override_map = NULL;
+       GHashTable *override_map = NULL;
 
        /* setup_vtable() must be called only once on the type */
        if (class->interface_offsets) {
@@ -1010,9 +1068,9 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum)
                        vtable [dslot] = overrides [i*2 + 1];
                        vtable [dslot]->slot = dslot;
                        if (!override_map)
-                               override_map = mono_g_hash_table_new (NULL, NULL);
+                               override_map = g_hash_table_new (NULL, NULL);
 
-                       mono_g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
+                       g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
                }
        }
 
@@ -1096,7 +1154,7 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum)
                                        continue;
 
                                if (ic->generic_class) {
-                                       MonoClass *the_ic = mono_class_from_mono_type (ic->generic_class->generic_type);
+                                       MonoClass *the_ic = ic->generic_class->container_class;
                                        the_cname = _mono_type_get_name (&the_ic->byval_arg, TRUE, FALSE, TRUE);
                                        cname = the_cname;
                                } else {
@@ -1219,8 +1277,8 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum)
                                                slot = k->methods [j]->slot;
                                                g_assert (cm->slot < max_vtsize);
                                                if (!override_map)
-                                                       override_map = mono_g_hash_table_new (NULL, NULL);
-                                               mono_g_hash_table_insert (override_map, m1, cm);
+                                                       override_map = g_hash_table_new (NULL, NULL);
+                                               g_hash_table_insert (override_map, m1, cm);
                                                break;
                                        }
                                }
@@ -1246,8 +1304,8 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum)
                        vtable [decl->slot] = overrides [i*2 + 1];
                        overrides [i * 2 + 1]->slot = decl->slot;
                        if (!override_map)
-                               override_map = mono_g_hash_table_new (NULL, NULL);
-                       mono_g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
+                               override_map = g_hash_table_new (NULL, NULL);
+                       g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
                }
        }
 
@@ -1258,16 +1316,16 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum)
        if (override_map) {
                for (i = 0; i < max_vtsize; ++i)
                        if (vtable [i]) {
-                               MonoMethod *cm = mono_g_hash_table_lookup (override_map, vtable [i]);
+                               MonoMethod *cm = g_hash_table_lookup (override_map, vtable [i]);
                                if (cm)
                                        vtable [i] = cm;
                        }
 
-               mono_g_hash_table_destroy (override_map);
+               g_hash_table_destroy (override_map);
        }
 
        if (class->generic_class) {
-               MonoClass *gklass = mono_class_from_mono_type (class->generic_class->generic_type);
+               MonoClass *gklass = class->generic_class->container_class;
 
                mono_class_init (gklass);
                class->vtable_size = gklass->vtable_size;
@@ -1372,9 +1430,10 @@ mono_class_init (MonoClass *class)
 
        if (class->generic_class && !class->generic_class->is_dynamic) {
                MonoGenericClass *gclass = class->generic_class;
-               MonoClass *gklass;
+               MonoClass *gklass = gclass->container_class;
+
+               mono_stats.generic_class_count++;
 
-               gklass = mono_class_from_mono_type (gclass->generic_type);
                mono_class_init (gklass);
 
                if (MONO_CLASS_IS_INTERFACE (class))
@@ -1383,10 +1442,13 @@ mono_class_init (MonoClass *class)
                g_assert (class->method.count == gklass->method.count);
                class->methods = g_new0 (MonoMethod *, class->method.count);
 
-               for (i = 0; i < class->method.count; i++)
-                       class->methods [i] = mono_class_inflate_generic_method (
+               for (i = 0; i < class->method.count; i++) {
+                       MonoMethod *inflated = mono_class_inflate_generic_method (
                                gklass->methods [i], gclass->context, gclass->klass);
 
+                       class->methods [i] = mono_get_inflated_method (inflated);
+               }
+
                g_assert (class->field.count == gklass->field.count);
                class->fields = g_new0 (MonoClassField, class->field.count);
 
@@ -1806,6 +1868,59 @@ set_generic_param_owner (MonoGenericContainer *container, MonoClass *klass, int
        return pos + gc->type_argc;
 }
 
+static MonoGenericInst *
+get_shared_inst (MonoGenericContainer *container)
+{
+       MonoGenericInst *nginst;
+       int i;
+
+       nginst = g_new0 (MonoGenericInst, 1);
+       nginst->type_argc = container->type_argc;
+       nginst->type_argv = g_new0 (MonoType *, nginst->type_argc);
+       nginst->is_open = 1;
+
+       for (i = 0; i < nginst->type_argc; i++) {
+               MonoType *t = g_new0 (MonoType, 1);
+
+               t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
+               t->data.generic_param = &container->type_params [i];
+
+               nginst->type_argv [i] = t;
+       }
+
+       return mono_metadata_lookup_generic_inst (nginst);
+}
+
+MonoGenericClass *
+mono_get_shared_generic_class (MonoGenericContainer *container, gboolean is_dynamic)
+{
+       MonoGenericClass *gclass;
+       MonoGenericClass *cached;
+
+       if (is_dynamic) {
+               MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
+               gclass = &dgclass->generic_class;
+               gclass->is_dynamic = 1;
+       } else
+               gclass = g_new0 (MonoGenericClass, 1);
+
+       gclass->context = &container->context;
+       gclass->container_class = container->klass;
+       gclass->inst = get_shared_inst (container);
+
+#if 0
+       cached = mono_metadata_lookup_generic_class (gclass);
+       if (cached) {
+               g_free (gclass);
+               return cached;
+       }
+#endif
+
+       gclass->klass = container->klass;
+
+       return gclass;
+}
+
 /**
  * @image: context where the image is created
  * @type_token:  typedef token
@@ -1848,11 +1963,12 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
 
        g_hash_table_insert (image->class_cache, GUINT_TO_POINTER (type_token), class);
 
-       class->generic_container = mono_metadata_load_generic_params (image, class->type_token);
+       class->generic_container = mono_metadata_load_generic_params (image, class->type_token, NULL);
        if (class->generic_container) {
                class->generic_container->klass = class;
-               context = g_new0 (MonoGenericContext, 1);
-               context->container = class->generic_container;
+               context = &class->generic_container->context;
+
+               context->gclass = mono_get_shared_generic_class (context->container, FALSE);
        }
 
        if (cols [MONO_TYPEDEF_EXTENDS])
@@ -1934,7 +2050,7 @@ mono_class_create_generic (MonoGenericClass *gclass)
                gclass->klass = g_malloc0 (sizeof (MonoClass));
        klass = gclass->klass;
 
-       gklass = mono_class_from_mono_type (gclass->generic_type);
+       gklass = gclass->container_class;
 
        klass->nested_in = gklass->nested_in;
 
@@ -1958,6 +2074,8 @@ mono_class_create_generic (MonoGenericClass *gclass)
                klass->inited = 1;
 
                klass->valuetype = gklass->valuetype;
+
+               mono_class_setup_supertypes (klass);
        }
 }
 
@@ -1972,7 +2090,7 @@ mono_class_create_generic_2 (MonoGenericClass *gclass)
                return;
 
        klass = gclass->klass;
-       gklass = mono_class_from_mono_type (gclass->generic_type);
+       gklass = gclass->container_class;
 
        klass->method = gklass->method;
        klass->field = gklass->field;
@@ -2261,7 +2379,7 @@ mono_class_create_from_typespec (MonoImage *image, guint32 type_spec,
                break;
        }
 
-       if (!class || !context)
+       if (!class || !context || (!context->gclass && !context->gmethod))
                return class;
 
        inflated = mono_class_inflate_generic_type (&class->byval_arg, context);
@@ -2809,6 +2927,7 @@ mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
                           gboolean check_interfaces)
 {
  again:
+       g_assert (klassc->idepth > 0);
        if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
                if ((klassc->interface_id <= klass->max_interface_id) &&
                        (klass->interface_offsets [klassc->interface_id] >= 0))
@@ -2969,7 +3088,7 @@ handle_enum:
                }
                return mono_class_instance_size (klass) - sizeof (MonoObject);
        case MONO_TYPE_GENERICINST:
-               type = type->data.generic_class->generic_type;
+               type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
        default:
                g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);