2008-07-02 Zoltan Varga <vargaz@gmail.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 #include <mono/utils/mono-counters.h>
14
15 #include "mini.h"
16
17 /*
18  * mono_get_generic_context_from_code:
19  *
20  *   Return the runtime generic context belonging to the method whose native code
21  * contains CODE.
22  */
23 MonoGenericSharingContext*
24 mono_get_generic_context_from_code (guint8 *code)
25 {
26         MonoJitInfo *jit_info = mono_jit_info_table_find (mono_domain_get (), (char*)code);
27
28         g_assert (jit_info);
29
30         return mono_jit_info_get_generic_sharing_context (jit_info);
31 }
32
33 /*
34  * mini_method_get_context:
35  * @method: a method
36  *
37  * Returns the generic context of a method or NULL if it doesn't have
38  * one.  For an inflated method that's the context stored in the
39  * method.  Otherwise it's in the method's generic container or in the
40  * generic container of the method's class.
41  */
42 MonoGenericContext*
43 mini_method_get_context (MonoMethod *method)
44 {
45         if (method->is_inflated)
46                 return mono_method_get_context (method);
47         if (method->is_generic)
48                 return &(mono_method_get_generic_container (method)->context);
49         if (method->klass->generic_container)
50                 return &method->klass->generic_container->context;
51         return NULL;
52 }
53
54 /*
55  * mono_method_check_context_used:
56  * @method: a method
57  *
58  * Checks whether the method's generic context uses a type variable.
59  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
60  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
61  * context's class or method instantiation uses type variables.
62  */
63 int
64 mono_method_check_context_used (MonoMethod *method)
65 {
66         MonoGenericContext *method_context = mini_method_get_context (method);
67
68         if (!method_context)
69                 return 0;
70
71         return mono_generic_context_check_used (method_context);
72 }
73
74 static gboolean
75 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars)
76 {
77         int i;
78
79         for (i = 0; i < inst->type_argc; ++i) {
80                 MonoType *type = inst->type_argv [i];
81                 int type_type;
82
83                 if (MONO_TYPE_IS_REFERENCE (type))
84                         continue;
85
86                 type_type = mono_type_get_type (type);
87                 if (allow_type_vars && (type_type == MONO_TYPE_VAR || type_type == MONO_TYPE_MVAR))
88                         continue;
89
90                 return FALSE;
91         }
92
93         return TRUE;
94 }
95
96 /*
97  * mono_generic_context_is_sharable:
98  * @context: a generic context
99  *
100  * Returns whether the generic context is sharable.  A generic context
101  * is sharable iff all of its type arguments are reference type.
102  */
103 gboolean
104 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
105 {
106         g_assert (context->class_inst || context->method_inst);
107
108         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars))
109                 return FALSE;
110
111         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars))
112                 return FALSE;
113
114         return TRUE;
115 }
116
117 /*
118  * mono_method_is_generic_impl:
119  * @method: a method
120  *
121  * Returns whether the method is either inflated or part of an
122  * inflated class.
123  */
124 gboolean
125 mono_method_is_generic_impl (MonoMethod *method)
126 {
127         return method->klass->generic_class != NULL && method->is_inflated;
128 }
129
130 /*
131  * mono_method_is_generic_sharable_impl:
132  * @method: a method
133  * @allow_type_vars: whether to regard type variables as reference types
134  *
135  * Returns TRUE iff the method is inflated or part of an inflated
136  * class, its context is sharable and it has no constraints on its
137  * type parameters.  Otherwise returns FALSE.
138  */
139 gboolean
140 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
141 {
142         if (!mono_method_is_generic_impl (method))
143                 return FALSE;
144
145         if (method->is_inflated) {
146                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
147                 MonoGenericContext *context = &inflated->context;
148
149                 if (!mono_generic_context_is_sharable (context, allow_type_vars))
150                         return FALSE;
151
152                 g_assert (inflated->declaring);
153
154                 if (inflated->declaring->is_generic) {
155                         g_assert (mono_method_get_generic_container (inflated->declaring)->type_params);
156
157                         if (mono_method_get_generic_container (inflated->declaring)->type_params->constraints)
158                                 return FALSE;
159                 }
160         }
161
162         if (method->klass->generic_class) {
163                 if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
164                         return FALSE;
165
166                 g_assert (method->klass->generic_class->container_class &&
167                                 method->klass->generic_class->container_class->generic_container &&
168                                 method->klass->generic_class->container_class->generic_container->type_params);
169
170                 if (method->klass->generic_class->container_class->generic_container->type_params->constraints)
171                         return FALSE;
172         }
173
174         return TRUE;
175 }
176
177 static gboolean
178 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
179 {
180         int i;
181
182         if (!inst1) {
183                 g_assert (!inst2);
184                 return TRUE;
185         }
186
187         g_assert (inst2);
188
189         if (inst1->type_argc != inst2->type_argc)
190                 return FALSE;
191
192         for (i = 0; i < inst1->type_argc; ++i)
193                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
194                         return FALSE;
195
196         return TRUE;
197 }
198
199 /*
200  * mono_generic_context_equal_deep:
201  * @context1: a generic context
202  * @context2: a generic context
203  *
204  * Returns whether context1's type arguments are equal to context2's
205  * type arguments.
206  */
207 gboolean
208 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
209 {
210         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
211                 generic_inst_equal (context1->method_inst, context2->method_inst);
212 }
213
214 /*
215  * mini_class_get_container_class:
216  * @class: a generic class
217  *
218  * Returns the class's container class, which is the class itself if
219  * it doesn't have generic_class set.
220  */
221 MonoClass*
222 mini_class_get_container_class (MonoClass *class)
223 {
224         if (class->generic_class)
225                 return class->generic_class->container_class;
226
227         g_assert (class->generic_container);
228         return class;
229 }
230
231 /*
232  * mini_class_get_context:
233  * @class: a generic class
234  *
235  * Returns the class's generic context.
236  */
237 MonoGenericContext*
238 mini_class_get_context (MonoClass *class)
239 {
240         if (class->generic_class)
241                 return &class->generic_class->context;
242
243         g_assert (class->generic_container);
244         return &class->generic_container->context;
245 }
246
247 /*
248  * mini_get_basic_type_from_generic:
249  * @gsctx: a generic sharing context
250  * @type: a type
251  *
252  * Returns a closed type corresponding to the possibly open type
253  * passed to it.
254  */
255 MonoType*
256 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
257 {
258         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
259                 g_assert (gsctx);
260
261         return mono_type_get_basic_type_from_generic (type);
262 }
263
264 /*
265  * mini_type_stack_size:
266  * @gsctx: a generic sharing context
267  * @t: a type
268  * @align: Pointer to an int for returning the alignment
269  *
270  * Returns the type's stack size and the alignment in *align.  The
271  * type is allowed to be open.
272  */
273 int
274 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
275 {
276         return mono_type_stack_size_internal (t, align, gsctx != NULL);
277 }
278
279 /*
280  * mono_generic_sharing_init:
281  *
282  * Register the generic sharing counters.
283  */
284 void
285 mono_generic_sharing_init (void)
286 {
287 }