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>
17 //#define ALLOW_PARTIAL_SHARING TRUE
18 #define ALLOW_PARTIAL_SHARING FALSE
21 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
24 type_check_context_used (MonoType *type, gboolean recursive)
26 switch (mono_type_get_type (type)) {
28 return MONO_GENERIC_CONTEXT_USED_CLASS;
30 return MONO_GENERIC_CONTEXT_USED_METHOD;
31 case MONO_TYPE_SZARRAY:
32 return mono_class_check_context_used (mono_type_get_class (type));
34 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
37 return mono_class_check_context_used (mono_type_get_class (type));
40 case MONO_TYPE_GENERICINST:
42 MonoGenericClass *gclass = type->data.generic_class;
44 g_assert (gclass->container_class->generic_container);
45 return mono_generic_context_check_used (&gclass->context);
55 inst_check_context_used (MonoGenericInst *inst)
63 for (i = 0; i < inst->type_argc; ++i)
64 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
70 * mono_generic_context_check_used:
71 * @context: a generic context
73 * Checks whether the context uses a type variable. Returns an int
74 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
75 * the context's class instantiation uses type variables.
78 mono_generic_context_check_used (MonoGenericContext *context)
82 context_used |= inst_check_context_used (context->class_inst);
83 context_used |= inst_check_context_used (context->method_inst);
89 * mono_class_check_context_used:
92 * Checks whether the class's generic context uses a type variable.
93 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
94 * reflect whether the context's class instantiation uses type
98 mono_class_check_context_used (MonoClass *class)
100 int context_used = 0;
102 context_used |= type_check_context_used (&class->this_arg, FALSE);
103 context_used |= type_check_context_used (&class->byval_arg, FALSE);
105 if (class->generic_class)
106 context_used |= mono_generic_context_check_used (&class->generic_class->context);
107 else if (class->generic_container)
108 context_used |= mono_generic_context_check_used (&class->generic_container->context);
114 * LOCKING: loader lock
116 static MonoRuntimeGenericContextOtherInfoTemplate*
117 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
119 g_assert (type_argc >= 0);
121 return template->other_infos;
122 return g_slist_nth_data (template->method_templates, type_argc - 1);
126 * LOCKING: loader lock
129 set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
130 MonoRuntimeGenericContextOtherInfoTemplate *oti)
132 g_assert (type_argc >= 0);
134 template->other_infos = oti;
136 int length = g_slist_length (template->method_templates);
139 /* FIXME: quadratic! */
140 while (length < type_argc) {
141 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
145 list = g_slist_nth (template->method_templates, type_argc - 1);
152 * LOCKING: loader lock
155 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
157 return g_slist_length (template->method_templates);
161 * LOCKING: loader lock
163 static MonoRuntimeGenericContextOtherInfoTemplate*
164 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
167 MonoRuntimeGenericContextOtherInfoTemplate *oti;
169 g_assert (slot >= 0);
171 for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
180 * LOCKING: loader lock
183 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
185 MonoRuntimeGenericContextOtherInfoTemplate *oti;
188 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
194 /* Maps from uninstantiated generic classes to GList's of
195 * uninstantiated generic classes whose parent is the key class or an
196 * instance of the key class.
198 * LOCKING: loader lock
200 static GHashTable *generic_subclass_hash;
203 * LOCKING: templates lock
206 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
208 if (!class->image->rgctx_template_hash)
209 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
211 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
215 * LOCKING: loader lock
217 static MonoRuntimeGenericContextTemplate*
218 class_lookup_rgctx_template (MonoClass *class)
220 MonoRuntimeGenericContextTemplate *template;
222 if (!class->image->rgctx_template_hash)
225 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
231 * LOCKING: loader lock
234 register_generic_subclass (MonoClass *class)
236 MonoClass *parent = class->parent;
238 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
239 static gboolean hook_installed;
241 if (!hook_installed) {
242 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
243 hook_installed = TRUE;
246 g_assert (rgctx_template);
248 if (parent->generic_class)
249 parent = parent->generic_class->container_class;
251 if (!generic_subclass_hash)
252 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
254 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
255 rgctx_template->next_subclass = subclass;
256 g_hash_table_insert (generic_subclass_hash, parent, class);
260 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
264 if (class->image == image) {
265 /* The parent class itself is in the image, so all the
266 subclasses must be in the image, too. If not,
267 we're removing an image containing a class which
268 still has a subclass in another image. */
271 g_assert (subclass->image == image);
272 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
280 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
281 MonoClass *next = subclass_template->next_subclass;
283 if (subclass->image != image) {
284 subclass_template->next_subclass = new_list;
292 g_hash_table_insert (generic_subclass_hash, class, new_list);
296 * mono_class_unregister_image_generic_subclasses:
299 * Removes all classes of the image from the generic subclass hash.
300 * Must be called when an image is unloaded.
303 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
305 GHashTable *old_hash;
307 //g_print ("unregistering image %s\n", image->name);
309 if (!generic_subclass_hash)
314 old_hash = generic_subclass_hash;
315 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
317 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
319 mono_loader_unlock ();
321 g_hash_table_destroy (old_hash);
324 static MonoRuntimeGenericContextTemplate*
325 alloc_template (MonoClass *class)
327 static gboolean inited = FALSE;
328 static int num_allocted = 0;
329 static int num_bytes = 0;
331 int size = sizeof (MonoRuntimeGenericContextTemplate);
334 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
335 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
342 return mono_image_alloc0 (class->image, size);
345 static MonoRuntimeGenericContextOtherInfoTemplate*
346 alloc_oti (MonoImage *image)
348 static gboolean inited = FALSE;
349 static int num_allocted = 0;
350 static int num_bytes = 0;
352 int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
355 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
356 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
363 return mono_image_alloc0 (image, size);
366 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
369 * LOCKING: loader lock
372 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
373 int slot, gpointer data, int info_type)
375 static gboolean inited = FALSE;
376 static int num_markers = 0;
377 static int num_data = 0;
380 MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
381 MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
384 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
385 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
389 g_assert (slot >= 0);
397 *oti = alloc_oti (image);
401 g_assert (!(*oti)->data);
403 (*oti)->info_type = info_type;
405 set_other_info_templates (image, template, type_argc, list);
407 if (data == MONO_RGCTX_SLOT_USED_MARKER)
414 * mono_method_get_declaring_generic_method:
415 * @method: an inflated method
417 * Returns an inflated method's declaring method.
420 mono_method_get_declaring_generic_method (MonoMethod *method)
422 MonoMethodInflated *inflated;
424 g_assert (method->is_inflated);
426 inflated = (MonoMethodInflated*)method;
428 return inflated->declaring;
432 * mono_class_get_method_generic:
436 * Given a class and a generic method, which has to be of an
437 * instantiation of the same class that klass is an instantiation of,
438 * returns the corresponding method in klass. Example:
440 * klass is Gen<string>
441 * method is Gen<object>.work<int>
443 * returns: Gen<string>.work<int>
446 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
448 MonoMethod *declaring, *m;
451 if (method->is_inflated)
452 declaring = mono_method_get_declaring_generic_method (method);
457 if (klass->generic_class)
458 m = mono_class_get_inflated_method (klass, declaring);
461 mono_class_setup_methods (klass);
462 if (klass->exception_type)
464 for (i = 0; i < klass->method.count; ++i) {
465 m = klass->methods [i];
468 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
471 if (i >= klass->method.count)
475 if (method != declaring) {
476 MonoGenericContext context;
478 context.class_inst = NULL;
479 context.method_inst = mono_method_get_context (method)->method_inst;
481 m = mono_class_inflate_generic_method (m, &context);
488 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
494 if (data == MONO_RGCTX_SLOT_USED_MARKER)
495 return MONO_RGCTX_SLOT_USED_MARKER;
499 case MONO_RGCTX_INFO_STATIC_DATA:
500 case MONO_RGCTX_INFO_KLASS:
501 case MONO_RGCTX_INFO_VTABLE:
502 case MONO_RGCTX_INFO_TYPE:
503 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
504 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
505 data, context, &error);
506 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
510 case MONO_RGCTX_INFO_METHOD:
511 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
512 case MONO_RGCTX_INFO_METHOD_RGCTX:
513 case MONO_RGCTX_INFO_METHOD_CONTEXT:
514 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
515 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
516 MonoMethod *method = data;
517 MonoMethod *inflated_method;
518 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
519 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
521 mono_metadata_free_type (inflated_type);
523 mono_class_init (inflated_class);
525 g_assert (!method->wrapper_type);
527 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
528 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
529 inflated_method = mono_method_search_in_array_class (inflated_class,
530 method->name, method->signature);
532 inflated_method = mono_class_inflate_generic_method (method, context);
534 mono_class_init (inflated_method->klass);
535 g_assert (inflated_method->klass == inflated_class);
536 return inflated_method;
539 case MONO_RGCTX_INFO_CLASS_FIELD: {
540 MonoClassField *field = data;
541 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
542 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
543 int i = field - field->parent->fields;
544 gpointer dummy = NULL;
546 mono_metadata_free_type (inflated_type);
548 mono_class_get_fields (inflated_class, &dummy);
549 g_assert (inflated_class->fields);
551 return &inflated_class->fields [i];
555 g_assert_not_reached ();
557 /* Not reached, quiet compiler */
562 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
563 MonoGenericContext *context, MonoClass *class, gboolean temporary)
565 return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
569 free_inflated_info (int info_type, gpointer info)
575 case MONO_RGCTX_INFO_STATIC_DATA:
576 case MONO_RGCTX_INFO_KLASS:
577 case MONO_RGCTX_INFO_VTABLE:
578 case MONO_RGCTX_INFO_TYPE:
579 case MONO_RGCTX_INFO_REFLECTION_TYPE:
580 mono_metadata_free_type (info);
587 static MonoRuntimeGenericContextOtherInfoTemplate
588 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
591 class_uninstantiated (MonoClass *class)
593 if (class->generic_class)
594 return class->generic_class->container_class;
599 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
600 gboolean allow_partial)
606 for (i = 0; i < inst->type_argc; ++i) {
607 MonoType *type = inst->type_argv [i];
609 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
613 for (i = 0; i < inst->type_argc; ++i) {
614 MonoType *type = inst->type_argv [i];
616 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
620 * Allow non ref arguments, if there is at least one ref argument
622 * FIXME: Allow more types
624 if (allow_partial && !type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U)))
634 * mono_is_partially_sharable_inst:
636 * Return TRUE if INST has ref and non-ref type arguments.
639 mono_is_partially_sharable_inst (MonoGenericInst *inst)
642 gboolean has_refs = FALSE, has_non_refs = FALSE;
644 for (i = 0; i < inst->type_argc; ++i) {
645 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
651 return has_refs && has_non_refs;
657 * Return the class used to store information when using generic sharing.
658 * For fully shared classes, it is the generic definition, for partially shared
659 * classes, it is an instance with all ref type arguments replaced by the type parameters
660 * of its generic definition.
663 get_shared_class (MonoClass *class)
666 * FIXME: This conflicts with normal instances. Also, some code in this file
667 * like class_get_rgctx_template_oti treats these as normal generic instances
668 * instead of generic classes.
670 //g_assert_not_reached ();
672 if (class->is_inflated) {
673 MonoGenericContext *context = &class->generic_class->context;
674 MonoGenericContext *container_context;
675 MonoGenericContext shared_context;
676 MonoGenericInst *inst;
677 MonoType **type_argv;
680 inst = context->class_inst;
681 if (mono_is_partially_sharable_inst (inst)) {
682 container_context = &class->generic_class->container_class->generic_container->context;
683 type_argv = g_new0 (MonoType*, inst->type_argc);
684 for (i = 0; i < inst->type_argc; ++i) {
685 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
686 type_argv [i] = container_context->class_inst->type_argv [i];
688 type_argv [i] = inst->type_argv [i];
691 memset (&shared_context, 0, sizeof (MonoGenericContext));
692 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
695 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
696 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
697 /* Happens for partially shared methods of nono-sharable generic class */
702 return class_uninstantiated (class);
706 * mono_class_get_runtime_generic_context_template:
709 * Looks up or constructs, if necessary, the runtime generic context
712 static MonoRuntimeGenericContextTemplate*
713 mono_class_get_runtime_generic_context_template (MonoClass *class)
715 MonoRuntimeGenericContextTemplate *parent_template, *template;
719 template = class_lookup_rgctx_template (class);
720 mono_loader_unlock ();
725 //g_assert (get_shared_class (class) == class);
727 template = alloc_template (class);
732 if (class->parent->generic_class) {
734 int max_argc, type_argc;
736 parent_template = mono_class_get_runtime_generic_context_template
737 (class->parent->generic_class->container_class);
739 max_argc = template_get_max_argc (parent_template);
741 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
742 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
744 /* FIXME: quadratic! */
745 for (i = 0; i < num_entries; ++i) {
746 MonoRuntimeGenericContextOtherInfoTemplate oti;
748 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
749 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
750 rgctx_template_set_other_slot (class->image, template, type_argc, i,
751 oti.data, oti.info_type);
756 MonoRuntimeGenericContextOtherInfoTemplate *oti;
757 int max_argc, type_argc;
759 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
761 max_argc = template_get_max_argc (parent_template);
763 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
764 /* FIXME: quadratic! */
765 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
766 if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
767 rgctx_template_set_other_slot (class->image, template, type_argc, i,
768 oti->data, oti->info_type);
775 if (class_lookup_rgctx_template (class)) {
776 /* some other thread already set the template */
777 template = class_lookup_rgctx_template (class);
779 class_set_rgctx_template (class, template);
782 register_generic_subclass (class);
785 mono_loader_unlock ();
791 * temporary signifies whether the inflated info (oti.data) will be
792 * used temporarily, in which case it might be heap-allocated, or
793 * permanently, in which case it will be mempool-allocated. If
794 * temporary is set then *do_free will return whether the returned
795 * data must be freed.
797 * LOCKING: loader lock
799 static MonoRuntimeGenericContextOtherInfoTemplate
800 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
802 g_assert ((temporary && do_free) || (!temporary && !do_free));
804 if (class->generic_class && !shared) {
805 MonoRuntimeGenericContextOtherInfoTemplate oti;
806 gboolean tmp_do_free;
808 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
809 type_argc, slot, TRUE, FALSE, &tmp_do_free);
811 gpointer info = oti.data;
812 oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
814 free_inflated_info (oti.info_type, info);
821 MonoRuntimeGenericContextTemplate *template;
822 MonoRuntimeGenericContextOtherInfoTemplate *oti;
824 template = mono_class_get_runtime_generic_context_template (class);
825 oti = rgctx_template_get_other_slot (template, type_argc, slot);
836 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
839 case MONO_RGCTX_INFO_STATIC_DATA: {
840 MonoVTable *vtable = mono_class_vtable (domain, class);
842 mono_raise_exception (mono_class_get_exception_for_failure (class));
845 case MONO_RGCTX_INFO_KLASS:
847 case MONO_RGCTX_INFO_VTABLE: {
848 MonoVTable *vtable = mono_class_vtable (domain, class);
850 mono_raise_exception (mono_class_get_exception_for_failure (class));
854 g_assert_not_reached ();
861 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
862 MonoGenericContext *context, MonoClass *class)
870 switch (oti->info_type) {
871 case MONO_RGCTX_INFO_STATIC_DATA:
872 case MONO_RGCTX_INFO_KLASS:
873 case MONO_RGCTX_INFO_VTABLE:
880 data = inflate_other_info (oti, context, class, temporary);
882 switch (oti->info_type) {
883 case MONO_RGCTX_INFO_STATIC_DATA:
884 case MONO_RGCTX_INFO_KLASS:
885 case MONO_RGCTX_INFO_VTABLE: {
886 MonoClass *arg_class = mono_class_from_mono_type (data);
888 free_inflated_info (oti->info_type, data);
889 g_assert (arg_class);
891 /* The class might be used as an argument to
892 mono_value_copy(), which requires that its GC
893 descriptor has been computed. */
894 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
895 mono_class_compute_gc_descriptor (arg_class);
897 return class_type_info (domain, arg_class, oti->info_type);
899 case MONO_RGCTX_INFO_TYPE:
901 case MONO_RGCTX_INFO_REFLECTION_TYPE:
902 return mono_type_get_object (domain, data);
903 case MONO_RGCTX_INFO_METHOD:
905 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
907 * We can't create a jump trampoline here, as it cannot be patched.
909 return mono_compile_method (data);
910 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
911 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
912 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
913 return mono_domain_alloc0 (domain, sizeof (gpointer));
914 case MONO_RGCTX_INFO_CLASS_FIELD:
916 case MONO_RGCTX_INFO_METHOD_RGCTX: {
917 MonoMethodInflated *method = data;
920 g_assert (method->method.method.is_inflated);
921 g_assert (method->context.method_inst);
923 vtable = mono_class_vtable (domain, method->method.method.klass);
925 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
927 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
929 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
930 MonoMethodInflated *method = data;
932 g_assert (method->method.method.is_inflated);
933 g_assert (method->context.method_inst);
935 return method->context.method_inst;
938 g_assert_not_reached ();
945 * LOCKING: loader lock
948 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
950 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
953 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
955 /* Recurse for all subclasses */
956 if (generic_subclass_hash)
957 subclass = g_hash_table_lookup (generic_subclass_hash, class);
962 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
963 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
965 g_assert (subclass_template);
967 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
968 g_assert (subclass_oti.data);
970 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
972 subclass = subclass_template->next_subclass;
977 * LOCKING: loader lock
980 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
983 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
985 MonoRuntimeGenericContextOtherInfoTemplate *oti;
987 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
992 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
994 /* Mark the slot as used in all parent classes (until we find
995 a parent class which already has it marked used). */
996 parent = class->parent;
997 while (parent != NULL) {
998 MonoRuntimeGenericContextTemplate *parent_template;
999 MonoRuntimeGenericContextOtherInfoTemplate *oti;
1001 if (parent->generic_class)
1002 parent = parent->generic_class->container_class;
1004 parent_template = mono_class_get_runtime_generic_context_template (parent);
1005 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1007 if (oti && oti->data)
1010 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
1011 MONO_RGCTX_SLOT_USED_MARKER, 0);
1013 parent = parent->parent;
1016 /* Fill in the slot in this class and in all subclasses
1018 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1024 other_info_equal (gpointer data1, gpointer data2, int info_type)
1026 switch (info_type) {
1027 case MONO_RGCTX_INFO_STATIC_DATA:
1028 case MONO_RGCTX_INFO_KLASS:
1029 case MONO_RGCTX_INFO_VTABLE:
1030 case MONO_RGCTX_INFO_TYPE:
1031 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1032 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1033 case MONO_RGCTX_INFO_METHOD:
1034 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1035 case MONO_RGCTX_INFO_CLASS_FIELD:
1036 case MONO_RGCTX_INFO_METHOD_RGCTX:
1037 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1038 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1039 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1040 return data1 == data2;
1042 g_assert_not_reached ();
1049 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
1050 MonoGenericContext *generic_context)
1052 static gboolean inited = FALSE;
1053 static int max_slot = 0;
1055 MonoRuntimeGenericContextTemplate *rgctx_template =
1056 mono_class_get_runtime_generic_context_template (class);
1057 MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
1060 mono_loader_lock ();
1062 oti_list = get_other_info_templates (rgctx_template, type_argc);
1064 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1065 gpointer inflated_data;
1067 if (oti->info_type != info_type || !oti->data)
1070 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
1072 if (other_info_equal (data, inflated_data, info_type)) {
1073 free_inflated_info (info_type, inflated_data);
1074 mono_loader_unlock ();
1077 free_inflated_info (info_type, inflated_data);
1080 /* We haven't found the info */
1081 i = register_other_info (class, type_argc, data, info_type);
1083 mono_loader_unlock ();
1086 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1096 * mono_method_lookup_or_register_other_info:
1098 * @in_mrgctx: whether to put the data into the MRGCTX
1099 * @data: the info data
1100 * @info_type: the type of info to register about data
1101 * @generic_context: a generic context
1103 * Looks up and, if necessary, adds information about other_class in
1104 * method's or method's class runtime generic context. Returns the
1105 * encoded slot number.
1108 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1109 int info_type, MonoGenericContext *generic_context)
1111 MonoClass *class = method->klass;
1112 int type_argc, index;
1115 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1117 g_assert (method->is_inflated && method_inst);
1118 type_argc = method_inst->type_argc;
1119 g_assert (type_argc > 0);
1124 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1126 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1129 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1131 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1135 * mono_class_rgctx_get_array_size:
1136 * @n: The number of the array
1137 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1139 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1140 * number includes the slot for linking and - for MRGCTXs - the two
1141 * slots in the first array for additional information.
1144 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1146 g_assert (n >= 0 && n < 30);
1155 * LOCKING: domain lock
1158 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1160 static gboolean inited = FALSE;
1161 static int rgctx_num_alloced = 0;
1162 static int rgctx_bytes_alloced = 0;
1163 static int mrgctx_num_alloced = 0;
1164 static int mrgctx_bytes_alloced = 0;
1166 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1167 gpointer array = mono_domain_alloc0 (domain, size);
1170 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1171 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1172 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1173 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1178 mrgctx_num_alloced++;
1179 mrgctx_bytes_alloced += size;
1181 rgctx_num_alloced++;
1182 rgctx_bytes_alloced += size;
1189 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1190 MonoGenericInst *method_inst)
1193 int i, first_slot, size;
1194 MonoDomain *domain = class_vtable->domain;
1195 MonoClass *class = class_vtable->klass;
1196 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1197 MonoRuntimeGenericContextOtherInfoTemplate oti;
1198 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1204 mono_domain_lock (domain);
1206 /* First check whether that slot isn't already instantiated.
1207 This might happen because lookup doesn't lock. Allocate
1208 arrays on the way. */
1210 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1212 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1213 for (i = 0; ; ++i) {
1216 if (method_inst && i == 0)
1217 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1221 if (slot < first_slot + size - 1) {
1222 rgctx_index = slot - first_slot + 1 + offset;
1223 info = rgctx [rgctx_index];
1225 mono_domain_unlock (domain);
1230 if (!rgctx [offset + 0])
1231 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1232 rgctx = rgctx [offset + 0];
1233 first_slot += size - 1;
1234 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1237 g_assert (!rgctx [rgctx_index]);
1239 mono_domain_unlock (domain);
1241 oti = class_get_rgctx_template_oti (get_shared_class (class),
1242 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1243 /* This might take the loader lock */
1244 info = instantiate_other_info (domain, &oti, &context, class);
1248 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1251 /*FIXME We should use CAS here, no need to take a lock.*/
1252 mono_domain_lock (domain);
1254 /* Check whether the slot hasn't been instantiated in the
1256 if (rgctx [rgctx_index])
1257 info = rgctx [rgctx_index];
1259 rgctx [rgctx_index] = info;
1261 mono_domain_unlock (domain);
1264 free_inflated_info (oti.info_type, oti.data);
1270 * mono_class_fill_runtime_generic_context:
1271 * @class_vtable: a vtable
1272 * @slot: a slot index to be instantiated
1274 * Instantiates a slot in the RGCTX.
1277 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1279 static gboolean inited = FALSE;
1280 static int num_alloced = 0;
1282 MonoDomain *domain = class_vtable->domain;
1283 MonoRuntimeGenericContext *rgctx;
1286 mono_domain_lock (domain);
1289 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1293 rgctx = class_vtable->runtime_generic_context;
1295 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1296 class_vtable->runtime_generic_context = rgctx;
1300 mono_domain_unlock (domain);
1302 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1308 * mono_method_fill_runtime_generic_context:
1309 * @mrgctx: an MRGCTX
1310 * @slot: a slot index to be instantiated
1312 * Instantiates a slot in the MRGCTX.
1315 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1319 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1320 mrgctx->method_inst);
1326 mrgctx_hash_func (gconstpointer key)
1328 const MonoMethodRuntimeGenericContext *mrgctx = key;
1330 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1334 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1336 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1337 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1339 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1340 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1344 * mono_method_lookup_rgctx:
1345 * @class_vtable: a vtable
1346 * @method_inst: the method inst of a generic method
1348 * Returns the MRGCTX for the generic method(s) with the given
1349 * method_inst of the given class_vtable.
1351 * LOCKING: Take the domain lock.
1353 MonoMethodRuntimeGenericContext*
1354 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1356 MonoDomain *domain = class_vtable->domain;
1357 MonoMethodRuntimeGenericContext *mrgctx;
1358 MonoMethodRuntimeGenericContext key;
1360 g_assert (!class_vtable->klass->generic_container);
1361 g_assert (!method_inst->is_open);
1363 mono_domain_lock (domain);
1364 if (!domain->method_rgctx_hash)
1365 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1367 key.class_vtable = class_vtable;
1368 key.method_inst = method_inst;
1370 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1375 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1376 mrgctx->class_vtable = class_vtable;
1377 mrgctx->method_inst = method_inst;
1379 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1382 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1383 for (i = 0; i < method_inst->type_argc; ++i)
1384 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1389 mono_domain_unlock (domain);
1397 * mono_generic_context_is_sharable_full:
1398 * @context: a generic context
1400 * Returns whether the generic context is sharable. A generic context
1401 * is sharable iff all of its type arguments are reference type, or some of them have a
1402 * reference type, and ALLOW_PARTIAL is TRUE.
1405 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1406 gboolean allow_type_vars,
1407 gboolean allow_partial)
1409 g_assert (context->class_inst || context->method_inst);
1411 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1414 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1421 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1423 return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1427 * mono_method_is_generic_impl:
1430 * Returns whether the method is either generic or part of a generic
1434 mono_method_is_generic_impl (MonoMethod *method)
1436 if (method->is_inflated) {
1437 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1440 /* We don't treat wrappers as generic code, i.e., we never
1441 apply generic sharing to them. This is especially
1442 important for static rgctx invoke wrappers, which only work
1443 if not compiled with sharing. */
1444 if (method->wrapper_type != MONO_WRAPPER_NONE)
1446 if (method->klass->generic_container)
1452 has_constraints (MonoGenericContainer *container)
1458 g_assert (container->type_argc > 0);
1459 g_assert (container->type_params);
1461 for (i = 0; i < container->type_argc; ++i)
1462 if (container->type_params [i].constraints)
1469 * mono_method_is_generic_sharable_impl_full:
1471 * @allow_type_vars: whether to regard type variables as reference types
1472 * @alloc_partial: whether to allow partial sharing
1474 * Returns TRUE iff the method is inflated or part of an inflated
1475 * class, its context is sharable and it has no constraints on its
1476 * type parameters. Otherwise returns FALSE.
1479 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1480 gboolean allow_partial)
1482 if (!mono_method_is_generic_impl (method))
1485 if (method->is_inflated) {
1486 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1487 MonoGenericContext *context = &inflated->context;
1489 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1492 g_assert (inflated->declaring);
1494 if (inflated->declaring->is_generic) {
1495 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1500 if (method->klass->generic_class) {
1501 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1504 g_assert (method->klass->generic_class->container_class &&
1505 method->klass->generic_class->container_class->generic_container);
1507 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1511 if (method->klass->generic_container && !allow_type_vars)
1518 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1520 return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING);
1524 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1526 if (!mono_class_generic_sharing_enabled (method->klass))
1529 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1532 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1535 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1536 method->klass->valuetype) &&
1537 (method->klass->generic_class || method->klass->generic_container);
1540 static MonoGenericInst*
1541 get_object_generic_inst (int type_argc)
1543 MonoType **type_argv;
1546 type_argv = alloca (sizeof (MonoType*) * type_argc);
1548 for (i = 0; i < type_argc; ++i)
1549 type_argv [i] = &mono_defaults.object_class->byval_arg;
1551 return mono_metadata_get_generic_inst (type_argc, type_argv);
1555 * mono_method_construct_object_context:
1558 * Returns a generic context for method with all type variables for
1559 * class and method instantiated with Object.
1562 mono_method_construct_object_context (MonoMethod *method)
1564 MonoGenericContext object_context;
1566 g_assert (!method->klass->generic_class);
1567 if (method->klass->generic_container) {
1568 int type_argc = method->klass->generic_container->type_argc;
1570 object_context.class_inst = get_object_generic_inst (type_argc);
1572 object_context.class_inst = NULL;
1575 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1576 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1578 object_context.method_inst = get_object_generic_inst (type_argc);
1580 object_context.method_inst = NULL;
1583 g_assert (object_context.class_inst || object_context.method_inst);
1585 return object_context;
1588 static gboolean gshared_supported;
1591 mono_set_generic_sharing_supported (gboolean supported)
1593 gshared_supported = supported;
1597 * mono_class_generic_sharing_enabled:
1600 * Returns whether generic sharing is enabled for class.
1602 * This is a stop-gap measure to slowly introduce generic sharing
1603 * until we have all the issues sorted out, at which time this
1604 * function will disappear and generic sharing will always be enabled.
1607 mono_class_generic_sharing_enabled (MonoClass *class)
1609 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1610 static gboolean inited = FALSE;
1615 if (gshared_supported)
1616 generic_sharing = MONO_GENERIC_SHARING_ALL;
1618 generic_sharing = MONO_GENERIC_SHARING_NONE;
1620 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1621 if (strcmp (option, "corlib") == 0)
1622 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1623 else if (strcmp (option, "collections") == 0)
1624 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1625 else if (strcmp (option, "all") == 0)
1626 generic_sharing = MONO_GENERIC_SHARING_ALL;
1627 else if (strcmp (option, "none") == 0)
1628 generic_sharing = MONO_GENERIC_SHARING_NONE;
1630 g_warning ("Unknown generic sharing option `%s'.", option);
1633 if (!gshared_supported)
1634 generic_sharing = MONO_GENERIC_SHARING_NONE;
1639 switch (generic_sharing) {
1640 case MONO_GENERIC_SHARING_NONE:
1642 case MONO_GENERIC_SHARING_ALL:
1644 case MONO_GENERIC_SHARING_CORLIB :
1645 return class->image == mono_defaults.corlib;
1646 case MONO_GENERIC_SHARING_COLLECTIONS:
1647 if (class->image != mono_defaults.corlib)
1649 while (class->nested_in)
1650 class = class->nested_in;
1651 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1653 g_assert_not_reached ();
1659 * mono_get_generic_context_from_code:
1661 * Return the runtime generic context belonging to the method whose native code
1664 MonoGenericSharingContext*
1665 mono_get_generic_context_from_code (guint8 *code)
1667 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1669 g_assert (jit_info);
1671 return mono_jit_info_get_generic_sharing_context (jit_info);
1675 mini_method_get_context (MonoMethod *method)
1677 return mono_method_get_context_general (method, TRUE);
1681 * mono_method_check_context_used:
1684 * Checks whether the method's generic context uses a type variable.
1685 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1686 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1687 * context's class or method instantiation uses type variables.
1690 mono_method_check_context_used (MonoMethod *method)
1692 MonoGenericContext *method_context = mini_method_get_context (method);
1693 int context_used = 0;
1695 if (!method_context) {
1696 /* It might be a method of an array of an open generic type */
1697 if (method->klass->rank)
1698 context_used = mono_class_check_context_used (method->klass);
1700 context_used = mono_generic_context_check_used (method_context);
1701 context_used |= mono_class_check_context_used (method->klass);
1704 return context_used;
1708 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
1719 if (inst1->type_argc != inst2->type_argc)
1722 for (i = 0; i < inst1->type_argc; ++i)
1723 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
1730 * mono_generic_context_equal_deep:
1731 * @context1: a generic context
1732 * @context2: a generic context
1734 * Returns whether context1's type arguments are equal to context2's
1738 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
1740 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
1741 generic_inst_equal (context1->method_inst, context2->method_inst);
1745 * mini_class_get_container_class:
1746 * @class: a generic class
1748 * Returns the class's container class, which is the class itself if
1749 * it doesn't have generic_class set.
1752 mini_class_get_container_class (MonoClass *class)
1754 if (class->generic_class)
1755 return class->generic_class->container_class;
1757 g_assert (class->generic_container);
1762 * mini_class_get_context:
1763 * @class: a generic class
1765 * Returns the class's generic context.
1768 mini_class_get_context (MonoClass *class)
1770 if (class->generic_class)
1771 return &class->generic_class->context;
1773 g_assert (class->generic_container);
1774 return &class->generic_container->context;
1778 * mini_get_basic_type_from_generic:
1779 * @gsctx: a generic sharing context
1782 * Returns a closed type corresponding to the possibly open type
1786 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
1788 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1791 return mono_type_get_basic_type_from_generic (type);
1795 * mini_type_get_underlying_type:
1797 * Return the underlying type of TYPE, taking into account enums, byref and generic
1801 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
1804 return &mono_defaults.int_class->byval_arg;
1805 return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
1809 * mini_type_stack_size:
1810 * @gsctx: a generic sharing context
1812 * @align: Pointer to an int for returning the alignment
1814 * Returns the type's stack size and the alignment in *align. The
1815 * type is allowed to be open.
1818 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
1820 gboolean allow_open = TRUE;
1822 // FIXME: Some callers might not pass in a gsctx
1823 //allow_open = gsctx != NULL;
1824 return mono_type_stack_size_internal (t, align, allow_open);
1828 * mini_type_stack_size_full:
1830 * Same as mini_type_stack_size, but handle pinvoke data types as well.
1833 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
1838 size = mono_type_native_stack_size (t, align);
1843 size = mini_type_stack_size (gsctx, t, &ialign);
1846 size = mini_type_stack_size (gsctx, t, NULL);
1854 * mono_generic_sharing_init:
1856 * Register the generic sharing counters.
1859 mono_generic_sharing_init (void)