Merge pull request #2237 from xmcclure/container-owner
[mono.git] / mono / mini / mini-generic-sharing.c
index 420b9aac36eb669795755da219ed5c6445576e44..a90afecd82dd6e8a2ca9cbcb925f6d6383e84220 100644 (file)
 static void
 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
 
-static gboolean partial_supported = FALSE;
+/* Counters */
+static int num_templates_allocted;
+static int num_templates_bytes;
+static int num_oti_allocted;
+static int num_oti_bytes;
+
+static gboolean partial_supported = TRUE;
 
 static inline gboolean
 partial_sharing_supported (void)
@@ -340,41 +346,22 @@ mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_
 static MonoRuntimeGenericContextTemplate*
 alloc_template (MonoClass *klass)
 {
-       static gboolean inited = FALSE;
-       static int num_allocted = 0;
-       static int num_bytes = 0;
-
        int size = sizeof (MonoRuntimeGenericContextTemplate);
 
-       if (!inited) {
-               mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
-               mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
-               inited = TRUE;
-       }
-
-       num_allocted++;
-       num_bytes += size;
+       num_templates_allocted++;
+       num_templates_bytes += size;
 
        return mono_image_alloc0 (klass->image, size);
 }
 
+/* LOCKING: Takes the loader lock */
 static MonoRuntimeGenericContextInfoTemplate*
 alloc_oti (MonoImage *image)
 {
-       static gboolean inited = FALSE;
-       static int num_allocted = 0;
-       static int num_bytes = 0;
-
        int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
 
-       if (!inited) {
-               mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
-               mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
-               inited = TRUE;
-       }
-
-       num_allocted++;
-       num_bytes += size;
+       num_oti_allocted++;
+       num_oti_bytes += size;
 
        return mono_image_alloc0 (image, size);
 }
@@ -882,11 +869,11 @@ class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_ty
                        return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
                if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
-                       return GUINT_TO_POINTER (1);
+                       return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
                else if (mono_class_is_nullable (klass))
-                       return GUINT_TO_POINTER (2);
+                       return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
                else
-                       return GUINT_TO_POINTER (0);
+                       return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO: {
                static MonoMethod *memcpy_method [17];
@@ -1187,6 +1174,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
                MonoJumpInfoVirtMethod *info = data;
                MonoClass *iface_class = info->method->klass;
                MonoMethod *method;
+               MonoError error;
                int ioffset, slot;
                gpointer addr;
 
@@ -1203,6 +1191,8 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
                g_assert (info->klass->vtable);
                method = info->klass->vtable [ioffset + slot];
 
+               method = mono_class_inflate_generic_method_checked (method, context, &error);
+
                addr = mono_compile_method (method);
                return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
        }
@@ -1228,11 +1218,11 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
 
                impl_class = method->klass;
                if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
-                       return GUINT_TO_POINTER (1);
+                       return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
                else if (mono_class_is_nullable (impl_class))
-                       return GUINT_TO_POINTER (2);
+                       return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
                else
-                       return GUINT_TO_POINTER (0);
+                       return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
        }
 #ifndef DISABLE_REMOTING
        case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
@@ -1245,10 +1235,11 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
        case MONO_RGCTX_INFO_FIELD_OFFSET: {
                MonoClassField *field = data;
 
+               /* The value is offset by 1 */
                if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
-                       return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
+                       return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
                else
-                       return GUINT_TO_POINTER (field->offset);
+                       return GUINT_TO_POINTER (field->offset + 1);
        }
        case MONO_RGCTX_INFO_METHOD_RGCTX: {
                MonoMethodInflated *method = data;
@@ -1843,6 +1834,7 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
                                                                                method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
        /* This might take the loader lock */
        info = instantiate_info (domain, &oti, &context, klass);
+       g_assert (info);
 
        /*
        if (method_inst)
@@ -2619,6 +2611,11 @@ mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
 void
 mono_generic_sharing_init (void)
 {
+       mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
+       mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
+       mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
+       mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
+
        mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
 }
 
@@ -2728,19 +2725,14 @@ get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
        }
 }
 
-typedef struct {
-       MonoGenericParam *par;
-       MonoType *constraint;
-} SharedGParam;
-
 static guint
 shared_gparam_hash (gconstpointer data)
 {
-       SharedGParam *p = (SharedGParam*)data;
+       MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
        guint hash;
 
-       hash = mono_metadata_generic_param_hash (p->par);
-       hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->constraint);
+       hash = mono_metadata_generic_param_hash (p->parent);
+       hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
 
        return hash;
 }
@@ -2748,81 +2740,71 @@ shared_gparam_hash (gconstpointer data)
 static gboolean
 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
 {
-       SharedGParam *p1 = (SharedGParam*)ka;
-       SharedGParam *p2 = (SharedGParam*)kb;
+       MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
+       MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
 
        if (p1 == p2)
                return TRUE;
-       if (p1->par != p2->par)
+       if (p1->parent != p2->parent)
                return FALSE;
-       if (!mono_metadata_type_equal (p1->constraint, p2->constraint))
+       if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
                return FALSE;
        return TRUE;
 }
 
 /*
- * get_shared_gparam:
+ * mini_get_shared_gparam:
  *
- *   Create an anonymous gparam with a type variable with a constraint which encodes which types can match it.
+ *   Create an anonymous gparam from T with a constraint which encodes which types can match it.
  */
-static MonoType*
-get_shared_gparam (MonoType *t, MonoType *constraint)
+MonoType*
+mini_get_shared_gparam (MonoType *t, MonoType *constraint)
 {
        MonoGenericParam *par = t->data.generic_param;
-       MonoGenericParam *copy;
-       SharedGParam key;
+       MonoGSharedGenericParam *copy, key;
        MonoType *res;
        MonoImage *image = NULL;
        char *name;
 
        memset (&key, 0, sizeof (key));
-       key.par = par;
-       key.constraint = constraint;
+       key.parent = par;
+       key.param.param.gshared_constraint = constraint;
 
        g_assert (mono_generic_param_info (par));
-       /* image might not be set for sre */
-       if (par->owner && par->owner->image) {
-               image = par->owner->image;
+       image = get_image_for_generic_param(par);
 
-               mono_image_lock (image);
-               if (!image->gshared_types) {
-                       image->gshared_types_len = MONO_TYPE_INTERNAL;
-                       image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
-               }
-               if (!image->gshared_types [constraint->type])
-                       image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
-               res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
-               mono_image_unlock (image);
-               if (res)
-                       return res;
-               copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
-               memcpy (copy, par, sizeof (MonoGenericParamFull));
-               name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
-               ((MonoGenericParamFull*)copy)->info.name = mono_image_strdup (image, name);
-               g_free (name);
-       } else {
-               /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
-               copy = (MonoGenericParam*)g_new0 (MonoGenericParamFull, 1);
-               memcpy (copy, par, sizeof (MonoGenericParam));
-       }
-       copy->owner = NULL;
-       // FIXME:
-       copy->image = image ? image : mono_defaults.corlib;
+       /*
+        * Need a cache to ensure the newly created gparam
+        * is unique wrt T/CONSTRAINT.
+        */
+       mono_image_lock (image);
+       if (!image->gshared_types) {
+               image->gshared_types_len = MONO_TYPE_INTERNAL;
+               image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
+       }
+       if (!image->gshared_types [constraint->type])
+               image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
+       res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
+       mono_image_unlock (image);
+       if (res)
+               return res;
+       copy = mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
+       memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
+       name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
+       copy->param.info.name = mono_image_strdup (image, name);
+       g_free (name);
+
+       copy->param.param.owner = par->owner;
 
-       copy->gshared_constraint = constraint;
+       copy->param.param.gshared_constraint = constraint;
+       copy->parent = par;
        res = mono_metadata_type_dup (NULL, t);
-       res->data.generic_param = copy;
+       res->data.generic_param = (MonoGenericParam*)copy;
 
        if (image) {
-               SharedGParam *dkey;
-
-               dkey = mono_image_alloc0 (image, sizeof (SharedGParam));
-               dkey->par = par;
-               dkey->constraint = constraint;
-
                mono_image_lock (image);
                /* Duplicates are ok */
-               g_hash_table_insert (image->gshared_types [constraint->type], dkey, res);
+               g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
                mono_image_unlock (image);
        }
 
@@ -2850,7 +2832,7 @@ get_shared_type (MonoType *t, MonoType *type)
 
                k = mono_class_inflate_generic_class (gclass->container_class, &context);
 
-               return get_shared_gparam (t, &k->byval_arg);
+               return mini_get_shared_gparam (t, &k->byval_arg);
        } else if (MONO_TYPE_ISSTRUCT (type)) {
                return type;
        }
@@ -2863,7 +2845,7 @@ get_shared_type (MonoType *t, MonoType *type)
                ttype = MONO_TYPE_OBJECT;
        } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
                if (type->data.generic_param->gshared_constraint)
-                       return get_shared_gparam (t, type->data.generic_param->gshared_constraint);
+                       return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
                ttype = MONO_TYPE_OBJECT;
        }
 
@@ -2875,7 +2857,7 @@ get_shared_type (MonoType *t, MonoType *type)
                t2.type = ttype;
                klass = mono_class_from_mono_type (&t2);
 
-               return get_shared_gparam (t, &klass->byval_arg);
+               return mini_get_shared_gparam (t, &klass->byval_arg);
        }
 }
 
@@ -2883,7 +2865,7 @@ static MonoType*
 get_gsharedvt_type (MonoType *t)
 {
        /* Use TypeHandle as the constraint type since its a valuetype */
-       return get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
+       return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
 }
 
 static MonoGenericInst*