2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * (C) 2007 Novell, Inc.
12 #include <mono/metadata/class.h>
13 #include <mono/utils/mono-counters.h>
18 * mono_get_generic_context_from_code:
20 * Return the runtime generic context belonging to the method whose native code
23 MonoGenericSharingContext*
24 mono_get_generic_context_from_code (guint8 *code)
26 MonoJitInfo *jit_info = mono_jit_info_table_find (mono_domain_get (), (char*)code);
30 return mono_jit_info_get_generic_sharing_context (jit_info);
34 * mini_method_get_context:
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.
43 mini_method_get_context (MonoMethod *method)
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;
55 * mono_method_check_context_used:
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.
64 mono_method_check_context_used (MonoMethod *method)
66 MonoGenericContext *method_context = mini_method_get_context (method);
72 context_used = mono_generic_context_check_used (method_context);
73 context_used |= mono_class_check_context_used (method->klass);
79 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars)
83 for (i = 0; i < inst->type_argc; ++i) {
84 MonoType *type = inst->type_argv [i];
87 if (MONO_TYPE_IS_REFERENCE (type))
90 type_type = mono_type_get_type (type);
91 if (allow_type_vars && (type_type == MONO_TYPE_VAR || type_type == MONO_TYPE_MVAR))
101 * mono_generic_context_is_sharable:
102 * @context: a generic context
104 * Returns whether the generic context is sharable. A generic context
105 * is sharable iff all of its type arguments are reference type.
108 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
110 g_assert (context->class_inst || context->method_inst);
112 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars))
115 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars))
122 * mono_method_is_generic_impl:
125 * Returns whether the method is either generic or part of a generic
129 mono_method_is_generic_impl (MonoMethod *method)
131 if (method->is_inflated) {
132 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
135 /* We don't treat wrappers as generic code, i.e., we never
136 apply generic sharing to them. This is especially
137 important for static rgctx invoke wrappers, which only work
138 if not compiled with sharing. */
139 if (method->wrapper_type != MONO_WRAPPER_NONE)
141 if (method->klass->generic_container)
147 * mono_method_is_generic_sharable_impl:
149 * @allow_type_vars: whether to regard type variables as reference types
151 * Returns TRUE iff the method is inflated or part of an inflated
152 * class, its context is sharable and it has no constraints on its
153 * type parameters. Otherwise returns FALSE.
156 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
158 if (!mono_method_is_generic_impl (method))
161 if (method->is_inflated) {
162 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
163 MonoGenericContext *context = &inflated->context;
165 if (!mono_generic_context_is_sharable (context, allow_type_vars))
168 g_assert (inflated->declaring);
170 if (inflated->declaring->is_generic) {
171 g_assert (mono_method_get_generic_container (inflated->declaring)->type_params);
173 if (mono_method_get_generic_container (inflated->declaring)->type_params->constraints)
178 if (method->klass->generic_class) {
179 if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
182 g_assert (method->klass->generic_class->container_class &&
183 method->klass->generic_class->container_class->generic_container &&
184 method->klass->generic_class->container_class->generic_container->type_params);
186 if (method->klass->generic_class->container_class->generic_container->type_params->constraints)
190 if (method->klass->generic_container && !allow_type_vars)
197 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
208 if (inst1->type_argc != inst2->type_argc)
211 for (i = 0; i < inst1->type_argc; ++i)
212 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
219 * mono_generic_context_equal_deep:
220 * @context1: a generic context
221 * @context2: a generic context
223 * Returns whether context1's type arguments are equal to context2's
227 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
229 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
230 generic_inst_equal (context1->method_inst, context2->method_inst);
234 * mini_class_get_container_class:
235 * @class: a generic class
237 * Returns the class's container class, which is the class itself if
238 * it doesn't have generic_class set.
241 mini_class_get_container_class (MonoClass *class)
243 if (class->generic_class)
244 return class->generic_class->container_class;
246 g_assert (class->generic_container);
251 * mini_class_get_context:
252 * @class: a generic class
254 * Returns the class's generic context.
257 mini_class_get_context (MonoClass *class)
259 if (class->generic_class)
260 return &class->generic_class->context;
262 g_assert (class->generic_container);
263 return &class->generic_container->context;
267 * mini_get_basic_type_from_generic:
268 * @gsctx: a generic sharing context
271 * Returns a closed type corresponding to the possibly open type
275 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
277 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
280 return mono_type_get_basic_type_from_generic (type);
284 * mini_type_get_underlying_type:
286 * Return the underlying type of TYPE, taking into account enums and generic
290 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
292 return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
296 * mini_type_stack_size:
297 * @gsctx: a generic sharing context
299 * @align: Pointer to an int for returning the alignment
301 * Returns the type's stack size and the alignment in *align. The
302 * type is allowed to be open.
305 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
307 gboolean allow_open = TRUE;
309 // FIXME: Some callers might not pass in a gsctx
310 //allow_open = gsctx != NULL;
311 return mono_type_stack_size_internal (t, align, allow_open);
315 * mini_type_stack_size_full:
317 * Same as mini_type_stack_size, but handle pinvoke data types as well.
320 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
325 size = mono_type_native_stack_size (t, align);
330 size = mini_type_stack_size (gsctx, t, &ialign);
333 size = mini_type_stack_size (gsctx, t, NULL);
341 * mono_generic_sharing_init:
343 * Register the generic sharing counters.
346 mono_generic_sharing_init (void)