2008-10-23 Gonzalo Paniagua Javier <gonzalo@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 #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         int context_used = 0;
68
69         if (!method_context) {
70                 /* It might be a method of an array of an open generic type */
71                 if (method->klass->rank)
72                         context_used = mono_class_check_context_used (method->klass);
73         } else {
74                 context_used = mono_generic_context_check_used (method_context);
75                 context_used |= mono_class_check_context_used (method->klass);
76         }
77
78         return context_used;
79 }
80
81 static gboolean
82 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
83 {
84         int i;
85
86         if (!inst1) {
87                 g_assert (!inst2);
88                 return TRUE;
89         }
90
91         g_assert (inst2);
92
93         if (inst1->type_argc != inst2->type_argc)
94                 return FALSE;
95
96         for (i = 0; i < inst1->type_argc; ++i)
97                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
98                         return FALSE;
99
100         return TRUE;
101 }
102
103 /*
104  * mono_generic_context_equal_deep:
105  * @context1: a generic context
106  * @context2: a generic context
107  *
108  * Returns whether context1's type arguments are equal to context2's
109  * type arguments.
110  */
111 gboolean
112 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
113 {
114         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
115                 generic_inst_equal (context1->method_inst, context2->method_inst);
116 }
117
118 /*
119  * mini_class_get_container_class:
120  * @class: a generic class
121  *
122  * Returns the class's container class, which is the class itself if
123  * it doesn't have generic_class set.
124  */
125 MonoClass*
126 mini_class_get_container_class (MonoClass *class)
127 {
128         if (class->generic_class)
129                 return class->generic_class->container_class;
130
131         g_assert (class->generic_container);
132         return class;
133 }
134
135 /*
136  * mini_class_get_context:
137  * @class: a generic class
138  *
139  * Returns the class's generic context.
140  */
141 MonoGenericContext*
142 mini_class_get_context (MonoClass *class)
143 {
144         if (class->generic_class)
145                 return &class->generic_class->context;
146
147         g_assert (class->generic_container);
148         return &class->generic_container->context;
149 }
150
151 /*
152  * mini_get_basic_type_from_generic:
153  * @gsctx: a generic sharing context
154  * @type: a type
155  *
156  * Returns a closed type corresponding to the possibly open type
157  * passed to it.
158  */
159 MonoType*
160 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
161 {
162         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
163                 g_assert (gsctx);
164
165         return mono_type_get_basic_type_from_generic (type);
166 }
167
168 /*
169  * mini_type_get_underlying_type:
170  *
171  *   Return the underlying type of TYPE, taking into account enums and generic
172  * sharing.
173  */
174 MonoType*
175 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
176 {
177         return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
178 }
179
180 /*
181  * mini_type_stack_size:
182  * @gsctx: a generic sharing context
183  * @t: a type
184  * @align: Pointer to an int for returning the alignment
185  *
186  * Returns the type's stack size and the alignment in *align.  The
187  * type is allowed to be open.
188  */
189 int
190 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
191 {
192         gboolean allow_open = TRUE;
193
194         // FIXME: Some callers might not pass in a gsctx
195         //allow_open = gsctx != NULL;
196         return mono_type_stack_size_internal (t, align, allow_open);
197 }
198
199 /*
200  * mini_type_stack_size_full:
201  *
202  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
203  */
204 int
205 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
206 {
207         int size;
208
209         if (pinvoke) {
210                 size = mono_type_native_stack_size (t, align);
211         } else {
212                 int ialign;
213
214                 if (align) {
215                         size = mini_type_stack_size (gsctx, t, &ialign);
216                         *align = ialign;
217                 } else {
218                         size = mini_type_stack_size (gsctx, t, NULL);
219                 }
220         }
221         
222         return size;
223 }
224
225 /*
226  * mono_generic_sharing_init:
227  *
228  * Register the generic sharing counters.
229  */
230 void
231 mono_generic_sharing_init (void)
232 {
233 }