2007-10-19 Marek Habersack <mhabersack@novell.com>
[mono.git] / mono / mini / generic-sharing.c
1 /*
2  * generic-sharing.c: Support functions for generic sharing.
3  *
4  * Author:
5  *   Mark Probst (mark.probst@gmail.com)
6  *
7  * (C) 2007 Novell, Inc.
8  */
9
10 #include <config.h>
11
12 #include <mono/metadata/class.h>
13
14 #include "mini.h"
15
16 static gboolean
17 generic_inst_uses_type (MonoGenericInst *inst, MonoType *type)
18 {
19         int i;
20
21         if (!inst)
22                 return FALSE;
23
24         for (i = 0; i < inst->type_argc; ++i)
25                 if (mono_metadata_type_equal (type, inst->type_argv [i]))
26                         return TRUE;
27         return FALSE;
28 }
29
30 static int context_check_context_used (MonoGenericContext *context, MonoGenericContext *shared_context);
31
32 static int
33 type_check_context_used (MonoType *type, MonoGenericContext *context, gboolean recursive)
34 {
35         int context_used = 0;
36
37         if (generic_inst_uses_type (context->class_inst, type))
38                 context_used |= MONO_GENERIC_CONTEXT_USED_CLASS;
39         if (generic_inst_uses_type (context->method_inst, type))
40                 context_used |= MONO_GENERIC_CONTEXT_USED_METHOD;
41
42         if (recursive) {
43                 int t = mono_type_get_type (type);
44
45                 if (t == MONO_TYPE_CLASS)
46                         context_used |= mono_class_check_context_used (mono_type_get_class (type), context);
47                 else if (t == MONO_TYPE_GENERICINST) {
48                         MonoGenericClass *gclass = type->data.generic_class;
49
50                         context_used |= context_check_context_used (&gclass->context, context);
51                         context_used |= mono_class_check_context_used (gclass->container_class, context);
52                 }
53         }
54
55         return context_used;
56 }
57
58 static int
59 inst_check_context_used (MonoGenericInst *inst, MonoGenericContext *context)
60 {
61         int context_used = 0;
62         int i;
63
64         if (!inst)
65                 return 0;
66
67         for (i = 0; i < inst->type_argc; ++i)
68                 context_used |= type_check_context_used (inst->type_argv [i], context, TRUE);
69
70         return context_used;
71 }
72
73 static int
74 context_check_context_used (MonoGenericContext *context, MonoGenericContext *shared_context)
75 {
76         int context_used = 0;
77
78         context_used |= inst_check_context_used (context->class_inst, shared_context);
79         context_used |= inst_check_context_used (context->method_inst, shared_context);
80
81         return context_used;
82 }
83
84 int
85 mono_method_check_context_used (MonoMethod *method, MonoGenericContext *context)
86 {
87         MonoGenericContext *method_context = mono_method_get_context (method);
88
89         if (!method_context)
90                 return 0;
91
92         return context_check_context_used (method_context, context);
93 }
94
95 int
96 mono_class_check_context_used (MonoClass *class, MonoGenericContext *context)
97 {
98         int context_used = 0;
99
100         context_used |= type_check_context_used (&class->this_arg, context, FALSE);
101         context_used |= type_check_context_used (&class->byval_arg, context, FALSE);
102
103         if (class->generic_class)
104                 context_used |= context_check_context_used (&class->generic_class->context, context);
105
106         return context_used;
107 }
108
109 static gboolean
110 generic_inst_is_sharable (MonoGenericInst *inst)
111 {
112         int i;
113
114         for (i = 0; i < inst->type_argc; ++i) {
115                 int type = mono_type_get_type (inst->type_argv [i]);
116
117                 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_STRING && type != MONO_TYPE_OBJECT &&
118                                 type != MONO_TYPE_SZARRAY && type != MONO_TYPE_ARRAY)
119                         return FALSE;
120         }
121
122         return TRUE;
123 }
124
125 static gboolean
126 generic_context_is_sharable (MonoGenericContext *context)
127 {
128         g_assert (context->class_inst || context->method_inst);
129
130         if (context->class_inst && !generic_inst_is_sharable (context->class_inst))
131                 return FALSE;
132
133         if (context->method_inst && !generic_inst_is_sharable (context->method_inst))
134                 return FALSE;
135
136         return TRUE;
137 }
138
139 gboolean
140 mono_method_is_generic_impl (MonoMethod *method)
141 {
142         return method->klass->generic_class != NULL && method->is_inflated;
143 }
144
145 gboolean
146 mono_method_is_generic_sharable_impl (MonoMethod *method)
147 {
148         if (!mono_method_is_generic_impl (method))
149                 return FALSE;
150
151         if (method->is_inflated) {
152                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
153                 MonoGenericContext *context = &inflated->context;
154
155                 if (!generic_context_is_sharable (context))
156                         return FALSE;
157
158                 g_assert (inflated->declaring);
159
160                 if (inflated->declaring->generic_container) {
161                         g_assert (inflated->declaring->generic_container->type_params);
162
163                         if (inflated->declaring->generic_container->type_params->constraints)
164                                 return FALSE;
165                 }
166         }
167
168         if (method->klass->generic_class) {
169                 if (!generic_context_is_sharable (&method->klass->generic_class->context))
170                         return FALSE;
171
172                 g_assert (method->klass->generic_class->container_class &&
173                                 method->klass->generic_class->container_class->generic_container &&
174                                 method->klass->generic_class->container_class->generic_container->type_params);
175
176                 if (method->klass->generic_class->container_class->generic_container->type_params->constraints)
177                         return FALSE;
178         }
179
180         return TRUE;
181 }
182
183 static MonoGenericInst*
184 share_generic_inst (MonoCompile *cfg, MonoGenericInst *inst)
185 {
186         MonoType **type_argv;
187         int i;
188
189         if (!inst)
190                 return NULL;
191
192         type_argv = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoType*) * inst->type_argc);
193
194         for (i = 0; i < inst->type_argc; ++i)
195                 type_argv [i] = &mono_defaults.object_class->byval_arg;
196
197         return mono_metadata_get_generic_inst (inst->type_argc, type_argv);
198 }
199
200 MonoGenericContext*
201 mono_make_shared_context (MonoCompile *cfg, MonoGenericContext *context)
202 {
203         MonoGenericContext *shared = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGenericContext));
204
205         shared->class_inst = share_generic_inst (cfg, context->class_inst);
206         shared->method_inst = share_generic_inst (cfg, context->method_inst);
207
208         return shared;
209 }
210
211 MonoType*
212 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
213 {
214         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
215                 /* FIXME: we support sharing only of reference types */
216                 g_assert (gsctx);
217                 return &mono_defaults.object_class->byval_arg;
218         }
219         return type;
220 }
221
222 int
223 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
224 {
225         return mono_type_stack_size_internal (t, align, gsctx != NULL);
226 }