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);
240 g_assert (rgctx_template);
242 if (parent->generic_class)
243 parent = parent->generic_class->container_class;
245 if (!generic_subclass_hash)
246 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
248 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
249 rgctx_template->next_subclass = subclass;
250 g_hash_table_insert (generic_subclass_hash, parent, class);
254 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
258 if (class->image == image) {
259 /* The parent class itself is in the image, so all the
260 subclasses must be in the image, too. If not,
261 we're removing an image containing a class which
262 still has a subclass in another image. */
265 g_assert (subclass->image == image);
266 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
274 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
275 MonoClass *next = subclass_template->next_subclass;
277 if (subclass->image != image) {
278 subclass_template->next_subclass = new_list;
286 g_hash_table_insert (generic_subclass_hash, class, new_list);
290 * mono_class_unregister_image_generic_subclasses:
293 * Removes all classes of the image from the generic subclass hash.
294 * Must be called when an image is unloaded.
297 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
299 GHashTable *old_hash;
301 //g_print ("unregistering image %s\n", image->name);
303 if (!generic_subclass_hash)
308 old_hash = generic_subclass_hash;
309 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
311 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
313 mono_loader_unlock ();
315 g_hash_table_destroy (old_hash);
318 static MonoRuntimeGenericContextTemplate*
319 alloc_template (MonoClass *class)
321 static gboolean inited = FALSE;
322 static int num_allocted = 0;
323 static int num_bytes = 0;
325 int size = sizeof (MonoRuntimeGenericContextTemplate);
328 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
329 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
336 return mono_image_alloc0 (class->image, size);
339 static MonoRuntimeGenericContextOtherInfoTemplate*
340 alloc_oti (MonoImage *image)
342 static gboolean inited = FALSE;
343 static int num_allocted = 0;
344 static int num_bytes = 0;
346 int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
349 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
350 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
357 return mono_image_alloc0 (image, size);
360 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
363 * LOCKING: loader lock
366 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
367 int slot, gpointer data, int info_type)
369 static gboolean inited = FALSE;
370 static int num_markers = 0;
371 static int num_data = 0;
374 MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
375 MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
378 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
379 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
383 g_assert (slot >= 0);
391 *oti = alloc_oti (image);
395 g_assert (!(*oti)->data);
397 (*oti)->info_type = info_type;
399 set_other_info_templates (image, template, type_argc, list);
401 if (data == MONO_RGCTX_SLOT_USED_MARKER)
408 * mono_method_get_declaring_generic_method:
409 * @method: an inflated method
411 * Returns an inflated method's declaring method.
414 mono_method_get_declaring_generic_method (MonoMethod *method)
416 MonoMethodInflated *inflated;
418 g_assert (method->is_inflated);
420 inflated = (MonoMethodInflated*)method;
422 return inflated->declaring;
426 * mono_class_get_method_generic:
430 * Given a class and a generic method, which has to be of an
431 * instantiation of the same class that klass is an instantiation of,
432 * returns the corresponding method in klass. Example:
434 * klass is Gen<string>
435 * method is Gen<object>.work<int>
437 * returns: Gen<string>.work<int>
440 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
442 MonoMethod *declaring, *m;
445 if (method->is_inflated)
446 declaring = mono_method_get_declaring_generic_method (method);
451 if (klass->generic_class)
452 m = mono_class_get_inflated_method (klass, declaring);
455 mono_class_setup_methods (klass);
456 if (klass->exception_type)
458 for (i = 0; i < klass->method.count; ++i) {
459 m = klass->methods [i];
462 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
465 if (i >= klass->method.count)
469 if (method != declaring) {
470 MonoGenericContext context;
472 context.class_inst = NULL;
473 context.method_inst = mono_method_get_context (method)->method_inst;
475 m = mono_class_inflate_generic_method (m, &context);
482 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
488 if (data == MONO_RGCTX_SLOT_USED_MARKER)
489 return MONO_RGCTX_SLOT_USED_MARKER;
493 case MONO_RGCTX_INFO_STATIC_DATA:
494 case MONO_RGCTX_INFO_KLASS:
495 case MONO_RGCTX_INFO_VTABLE:
496 case MONO_RGCTX_INFO_TYPE:
497 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
498 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
499 data, context, &error);
500 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
504 case MONO_RGCTX_INFO_METHOD:
505 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
506 case MONO_RGCTX_INFO_METHOD_RGCTX:
507 case MONO_RGCTX_INFO_METHOD_CONTEXT:
508 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
509 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
510 MonoMethod *method = data;
511 MonoMethod *inflated_method;
512 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
513 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
515 mono_metadata_free_type (inflated_type);
517 mono_class_init (inflated_class);
519 g_assert (!method->wrapper_type);
521 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
522 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
523 inflated_method = mono_method_search_in_array_class (inflated_class,
524 method->name, method->signature);
526 inflated_method = mono_class_inflate_generic_method (method, context);
528 mono_class_init (inflated_method->klass);
529 g_assert (inflated_method->klass == inflated_class);
530 return inflated_method;
533 case MONO_RGCTX_INFO_CLASS_FIELD: {
534 MonoClassField *field = data;
535 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
536 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
537 int i = field - field->parent->fields;
538 gpointer dummy = NULL;
540 mono_metadata_free_type (inflated_type);
542 mono_class_get_fields (inflated_class, &dummy);
543 g_assert (inflated_class->fields);
545 return &inflated_class->fields [i];
549 g_assert_not_reached ();
551 /* Not reached, quiet compiler */
556 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
557 MonoGenericContext *context, MonoClass *class, gboolean temporary)
559 return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
563 free_inflated_info (int info_type, gpointer info)
569 case MONO_RGCTX_INFO_STATIC_DATA:
570 case MONO_RGCTX_INFO_KLASS:
571 case MONO_RGCTX_INFO_VTABLE:
572 case MONO_RGCTX_INFO_TYPE:
573 case MONO_RGCTX_INFO_REFLECTION_TYPE:
574 mono_metadata_free_type (info);
581 static MonoRuntimeGenericContextOtherInfoTemplate
582 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
585 class_uninstantiated (MonoClass *class)
587 if (class->generic_class)
588 return class->generic_class->container_class;
593 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
594 gboolean allow_partial)
600 for (i = 0; i < inst->type_argc; ++i) {
601 MonoType *type = inst->type_argv [i];
603 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
607 for (i = 0; i < inst->type_argc; ++i) {
608 MonoType *type = inst->type_argv [i];
610 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
614 * Allow non ref arguments, if there is at least one ref argument
616 * FIXME: Allow more types
618 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)))
628 * mono_is_partially_sharable_inst:
630 * Return TRUE if INST has ref and non-ref type arguments.
633 mono_is_partially_sharable_inst (MonoGenericInst *inst)
636 gboolean has_refs = FALSE, has_non_refs = FALSE;
638 for (i = 0; i < inst->type_argc; ++i) {
639 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)
645 return has_refs && has_non_refs;
651 * Return the class used to store information when using generic sharing.
652 * For fully shared classes, it is the generic definition, for partially shared
653 * classes, it is an instance with all ref type arguments replaced by the type parameters
654 * of its generic definition.
657 get_shared_class (MonoClass *class)
660 * FIXME: This conflicts with normal instances. Also, some code in this file
661 * like class_get_rgctx_template_oti treats these as normal generic instances
662 * instead of generic classes.
664 //g_assert_not_reached ();
666 if (class->is_inflated) {
667 MonoGenericContext *context = &class->generic_class->context;
668 MonoGenericContext *container_context;
669 MonoGenericContext shared_context;
670 MonoGenericInst *inst;
671 MonoType **type_argv;
674 inst = context->class_inst;
675 if (mono_is_partially_sharable_inst (inst)) {
676 container_context = &class->generic_class->container_class->generic_container->context;
677 type_argv = g_new0 (MonoType*, inst->type_argc);
678 for (i = 0; i < inst->type_argc; ++i) {
679 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)
680 type_argv [i] = container_context->class_inst->type_argv [i];
682 type_argv [i] = inst->type_argv [i];
685 memset (&shared_context, 0, sizeof (MonoGenericContext));
686 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
689 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
690 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
691 /* Happens for partially shared methods of nono-sharable generic class */
696 return class_uninstantiated (class);
700 * mono_class_get_runtime_generic_context_template:
703 * Looks up or constructs, if necessary, the runtime generic context
706 static MonoRuntimeGenericContextTemplate*
707 mono_class_get_runtime_generic_context_template (MonoClass *class)
709 MonoRuntimeGenericContextTemplate *parent_template, *template;
713 template = class_lookup_rgctx_template (class);
714 mono_loader_unlock ();
719 //g_assert (get_shared_class (class) == class);
721 template = alloc_template (class);
726 if (class->parent->generic_class) {
728 int max_argc, type_argc;
730 parent_template = mono_class_get_runtime_generic_context_template
731 (class->parent->generic_class->container_class);
733 max_argc = template_get_max_argc (parent_template);
735 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
736 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
738 /* FIXME: quadratic! */
739 for (i = 0; i < num_entries; ++i) {
740 MonoRuntimeGenericContextOtherInfoTemplate oti;
742 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
743 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
744 rgctx_template_set_other_slot (class->image, template, type_argc, i,
745 oti.data, oti.info_type);
750 MonoRuntimeGenericContextOtherInfoTemplate *oti;
751 int max_argc, type_argc;
753 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
755 max_argc = template_get_max_argc (parent_template);
757 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
758 /* FIXME: quadratic! */
759 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
760 if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
761 rgctx_template_set_other_slot (class->image, template, type_argc, i,
762 oti->data, oti->info_type);
769 if (class_lookup_rgctx_template (class)) {
770 /* some other thread already set the template */
771 template = class_lookup_rgctx_template (class);
773 class_set_rgctx_template (class, template);
776 register_generic_subclass (class);
779 mono_loader_unlock ();
785 * temporary signifies whether the inflated info (oti.data) will be
786 * used temporarily, in which case it might be heap-allocated, or
787 * permanently, in which case it will be mempool-allocated. If
788 * temporary is set then *do_free will return whether the returned
789 * data must be freed.
791 * LOCKING: loader lock
793 static MonoRuntimeGenericContextOtherInfoTemplate
794 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
796 g_assert ((temporary && do_free) || (!temporary && !do_free));
798 if (class->generic_class && !shared) {
799 MonoRuntimeGenericContextOtherInfoTemplate oti;
800 gboolean tmp_do_free;
802 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
803 type_argc, slot, TRUE, FALSE, &tmp_do_free);
805 gpointer info = oti.data;
806 oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
808 free_inflated_info (oti.info_type, info);
815 MonoRuntimeGenericContextTemplate *template;
816 MonoRuntimeGenericContextOtherInfoTemplate *oti;
818 template = mono_class_get_runtime_generic_context_template (class);
819 oti = rgctx_template_get_other_slot (template, type_argc, slot);
830 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
833 case MONO_RGCTX_INFO_STATIC_DATA: {
834 MonoVTable *vtable = mono_class_vtable (domain, class);
836 mono_raise_exception (mono_class_get_exception_for_failure (class));
839 case MONO_RGCTX_INFO_KLASS:
841 case MONO_RGCTX_INFO_VTABLE: {
842 MonoVTable *vtable = mono_class_vtable (domain, class);
844 mono_raise_exception (mono_class_get_exception_for_failure (class));
848 g_assert_not_reached ();
855 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
856 MonoGenericContext *context, MonoClass *class)
864 switch (oti->info_type) {
865 case MONO_RGCTX_INFO_STATIC_DATA:
866 case MONO_RGCTX_INFO_KLASS:
867 case MONO_RGCTX_INFO_VTABLE:
874 data = inflate_other_info (oti, context, class, temporary);
876 switch (oti->info_type) {
877 case MONO_RGCTX_INFO_STATIC_DATA:
878 case MONO_RGCTX_INFO_KLASS:
879 case MONO_RGCTX_INFO_VTABLE: {
880 MonoClass *arg_class = mono_class_from_mono_type (data);
882 free_inflated_info (oti->info_type, data);
883 g_assert (arg_class);
885 /* The class might be used as an argument to
886 mono_value_copy(), which requires that its GC
887 descriptor has been computed. */
888 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
889 mono_class_compute_gc_descriptor (arg_class);
891 return class_type_info (domain, arg_class, oti->info_type);
893 case MONO_RGCTX_INFO_TYPE:
895 case MONO_RGCTX_INFO_REFLECTION_TYPE:
896 return mono_type_get_object (domain, data);
897 case MONO_RGCTX_INFO_METHOD:
899 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
901 * We can't create a jump trampoline here, as it cannot be patched.
903 return mono_compile_method (data);
904 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
905 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
906 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
907 return mono_domain_alloc0 (domain, sizeof (gpointer));
908 case MONO_RGCTX_INFO_CLASS_FIELD:
910 case MONO_RGCTX_INFO_METHOD_RGCTX: {
911 MonoMethodInflated *method = data;
914 g_assert (method->method.method.is_inflated);
915 g_assert (method->context.method_inst);
917 vtable = mono_class_vtable (domain, method->method.method.klass);
919 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
921 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
923 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
924 MonoMethodInflated *method = data;
926 g_assert (method->method.method.is_inflated);
927 g_assert (method->context.method_inst);
929 return method->context.method_inst;
932 g_assert_not_reached ();
939 * LOCKING: loader lock
942 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
944 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
947 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
949 /* Recurse for all subclasses */
950 if (generic_subclass_hash)
951 subclass = g_hash_table_lookup (generic_subclass_hash, class);
956 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
957 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
959 g_assert (subclass_template);
961 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
962 g_assert (subclass_oti.data);
964 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
966 subclass = subclass_template->next_subclass;
971 * LOCKING: loader lock
974 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
977 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
979 MonoRuntimeGenericContextOtherInfoTemplate *oti;
981 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
986 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
988 /* Mark the slot as used in all parent classes (until we find
989 a parent class which already has it marked used). */
990 parent = class->parent;
991 while (parent != NULL) {
992 MonoRuntimeGenericContextTemplate *parent_template;
993 MonoRuntimeGenericContextOtherInfoTemplate *oti;
995 if (parent->generic_class)
996 parent = parent->generic_class->container_class;
998 parent_template = mono_class_get_runtime_generic_context_template (parent);
999 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1001 if (oti && oti->data)
1004 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
1005 MONO_RGCTX_SLOT_USED_MARKER, 0);
1007 parent = parent->parent;
1010 /* Fill in the slot in this class and in all subclasses
1012 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1018 other_info_equal (gpointer data1, gpointer data2, int info_type)
1020 switch (info_type) {
1021 case MONO_RGCTX_INFO_STATIC_DATA:
1022 case MONO_RGCTX_INFO_KLASS:
1023 case MONO_RGCTX_INFO_VTABLE:
1024 case MONO_RGCTX_INFO_TYPE:
1025 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1026 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1027 case MONO_RGCTX_INFO_METHOD:
1028 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1029 case MONO_RGCTX_INFO_CLASS_FIELD:
1030 case MONO_RGCTX_INFO_METHOD_RGCTX:
1031 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1032 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1033 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1034 return data1 == data2;
1036 g_assert_not_reached ();
1043 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
1044 MonoGenericContext *generic_context)
1046 static gboolean inited = FALSE;
1047 static int max_slot = 0;
1049 MonoRuntimeGenericContextTemplate *rgctx_template =
1050 mono_class_get_runtime_generic_context_template (class);
1051 MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
1054 mono_loader_lock ();
1056 oti_list = get_other_info_templates (rgctx_template, type_argc);
1058 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1059 gpointer inflated_data;
1061 if (oti->info_type != info_type || !oti->data)
1064 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
1066 if (other_info_equal (data, inflated_data, info_type)) {
1067 free_inflated_info (info_type, inflated_data);
1068 mono_loader_unlock ();
1071 free_inflated_info (info_type, inflated_data);
1074 /* We haven't found the info */
1075 i = register_other_info (class, type_argc, data, info_type);
1077 mono_loader_unlock ();
1080 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1090 * mono_method_lookup_or_register_other_info:
1092 * @in_mrgctx: whether to put the data into the MRGCTX
1093 * @data: the info data
1094 * @info_type: the type of info to register about data
1095 * @generic_context: a generic context
1097 * Looks up and, if necessary, adds information about other_class in
1098 * method's or method's class runtime generic context. Returns the
1099 * encoded slot number.
1102 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1103 int info_type, MonoGenericContext *generic_context)
1105 MonoClass *class = method->klass;
1106 int type_argc, index;
1109 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1111 g_assert (method->is_inflated && method_inst);
1112 type_argc = method_inst->type_argc;
1113 g_assert (type_argc > 0);
1118 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1120 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1123 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1125 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1129 * mono_class_rgctx_get_array_size:
1130 * @n: The number of the array
1131 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1133 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1134 * number includes the slot for linking and - for MRGCTXs - the two
1135 * slots in the first array for additional information.
1138 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1140 g_assert (n >= 0 && n < 30);
1149 * LOCKING: domain lock
1152 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1154 static gboolean inited = FALSE;
1155 static int rgctx_num_alloced = 0;
1156 static int rgctx_bytes_alloced = 0;
1157 static int mrgctx_num_alloced = 0;
1158 static int mrgctx_bytes_alloced = 0;
1160 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1161 gpointer array = mono_domain_alloc0 (domain, size);
1164 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1165 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1166 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1167 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1172 mrgctx_num_alloced++;
1173 mrgctx_bytes_alloced += size;
1175 rgctx_num_alloced++;
1176 rgctx_bytes_alloced += size;
1183 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1184 MonoGenericInst *method_inst)
1187 int i, first_slot, size;
1188 MonoDomain *domain = class_vtable->domain;
1189 MonoClass *class = class_vtable->klass;
1190 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1191 MonoRuntimeGenericContextOtherInfoTemplate oti;
1192 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1198 mono_domain_lock (domain);
1200 /* First check whether that slot isn't already instantiated.
1201 This might happen because lookup doesn't lock. Allocate
1202 arrays on the way. */
1204 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1206 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1207 for (i = 0; ; ++i) {
1210 if (method_inst && i == 0)
1211 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1215 if (slot < first_slot + size - 1) {
1216 rgctx_index = slot - first_slot + 1 + offset;
1217 info = rgctx [rgctx_index];
1219 mono_domain_unlock (domain);
1224 if (!rgctx [offset + 0])
1225 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1226 rgctx = rgctx [offset + 0];
1227 first_slot += size - 1;
1228 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1231 g_assert (!rgctx [rgctx_index]);
1233 mono_domain_unlock (domain);
1235 oti = class_get_rgctx_template_oti (get_shared_class (class),
1236 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1237 /* This might take the loader lock */
1238 info = instantiate_other_info (domain, &oti, &context, class);
1242 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1245 /*FIXME We should use CAS here, no need to take a lock.*/
1246 mono_domain_lock (domain);
1248 /* Check whether the slot hasn't been instantiated in the
1250 if (rgctx [rgctx_index])
1251 info = rgctx [rgctx_index];
1253 rgctx [rgctx_index] = info;
1255 mono_domain_unlock (domain);
1258 free_inflated_info (oti.info_type, oti.data);
1264 * mono_class_fill_runtime_generic_context:
1265 * @class_vtable: a vtable
1266 * @slot: a slot index to be instantiated
1268 * Instantiates a slot in the RGCTX.
1271 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1273 static gboolean inited = FALSE;
1274 static int num_alloced = 0;
1276 MonoDomain *domain = class_vtable->domain;
1277 MonoRuntimeGenericContext *rgctx;
1280 mono_domain_lock (domain);
1283 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1287 rgctx = class_vtable->runtime_generic_context;
1289 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1290 class_vtable->runtime_generic_context = rgctx;
1294 mono_domain_unlock (domain);
1296 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1302 * mono_method_fill_runtime_generic_context:
1303 * @mrgctx: an MRGCTX
1304 * @slot: a slot index to be instantiated
1306 * Instantiates a slot in the MRGCTX.
1309 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1313 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1314 mrgctx->method_inst);
1320 mrgctx_hash_func (gconstpointer key)
1322 const MonoMethodRuntimeGenericContext *mrgctx = key;
1324 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1328 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1330 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1331 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1333 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1334 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1338 * mono_method_lookup_rgctx:
1339 * @class_vtable: a vtable
1340 * @method_inst: the method inst of a generic method
1342 * Returns the MRGCTX for the generic method(s) with the given
1343 * method_inst of the given class_vtable.
1345 * LOCKING: Take the domain lock.
1347 MonoMethodRuntimeGenericContext*
1348 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1350 MonoDomain *domain = class_vtable->domain;
1351 MonoMethodRuntimeGenericContext *mrgctx;
1352 MonoMethodRuntimeGenericContext key;
1354 g_assert (!class_vtable->klass->generic_container);
1355 g_assert (!method_inst->is_open);
1357 mono_domain_lock (domain);
1358 if (!domain->method_rgctx_hash)
1359 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1361 key.class_vtable = class_vtable;
1362 key.method_inst = method_inst;
1364 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1369 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1370 mrgctx->class_vtable = class_vtable;
1371 mrgctx->method_inst = method_inst;
1373 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1376 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1377 for (i = 0; i < method_inst->type_argc; ++i)
1378 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1383 mono_domain_unlock (domain);
1391 * mono_generic_context_is_sharable_full:
1392 * @context: a generic context
1394 * Returns whether the generic context is sharable. A generic context
1395 * is sharable iff all of its type arguments are reference type, or some of them have a
1396 * reference type, and ALLOW_PARTIAL is TRUE.
1399 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1400 gboolean allow_type_vars,
1401 gboolean allow_partial)
1403 g_assert (context->class_inst || context->method_inst);
1405 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1408 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1415 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1417 return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1421 * mono_method_is_generic_impl:
1424 * Returns whether the method is either generic or part of a generic
1428 mono_method_is_generic_impl (MonoMethod *method)
1430 if (method->is_inflated) {
1431 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1434 /* We don't treat wrappers as generic code, i.e., we never
1435 apply generic sharing to them. This is especially
1436 important for static rgctx invoke wrappers, which only work
1437 if not compiled with sharing. */
1438 if (method->wrapper_type != MONO_WRAPPER_NONE)
1440 if (method->klass->generic_container)
1446 has_constraints (MonoGenericContainer *container)
1452 g_assert (container->type_argc > 0);
1453 g_assert (container->type_params);
1455 for (i = 0; i < container->type_argc; ++i)
1456 if (container->type_params [i].constraints)
1463 * mono_method_is_generic_sharable_impl_full:
1465 * @allow_type_vars: whether to regard type variables as reference types
1466 * @alloc_partial: whether to allow partial sharing
1468 * Returns TRUE iff the method is inflated or part of an inflated
1469 * class, its context is sharable and it has no constraints on its
1470 * type parameters. Otherwise returns FALSE.
1473 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1474 gboolean allow_partial)
1476 if (!mono_method_is_generic_impl (method))
1479 if (method->is_inflated) {
1480 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1481 MonoGenericContext *context = &inflated->context;
1483 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1486 g_assert (inflated->declaring);
1488 if (inflated->declaring->is_generic) {
1489 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1494 if (method->klass->generic_class) {
1495 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1498 g_assert (method->klass->generic_class->container_class &&
1499 method->klass->generic_class->container_class->generic_container);
1501 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1505 if (method->klass->generic_container && !allow_type_vars)
1512 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1514 return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING);
1518 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1520 if (!mono_class_generic_sharing_enabled (method->klass))
1523 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1526 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1529 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1530 method->klass->valuetype) &&
1531 (method->klass->generic_class || method->klass->generic_container);
1534 static MonoGenericInst*
1535 get_object_generic_inst (int type_argc)
1537 MonoType **type_argv;
1540 type_argv = alloca (sizeof (MonoType*) * type_argc);
1542 for (i = 0; i < type_argc; ++i)
1543 type_argv [i] = &mono_defaults.object_class->byval_arg;
1545 return mono_metadata_get_generic_inst (type_argc, type_argv);
1549 * mono_method_construct_object_context:
1552 * Returns a generic context for method with all type variables for
1553 * class and method instantiated with Object.
1556 mono_method_construct_object_context (MonoMethod *method)
1558 MonoGenericContext object_context;
1560 g_assert (!method->klass->generic_class);
1561 if (method->klass->generic_container) {
1562 int type_argc = method->klass->generic_container->type_argc;
1564 object_context.class_inst = get_object_generic_inst (type_argc);
1566 object_context.class_inst = NULL;
1569 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1570 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1572 object_context.method_inst = get_object_generic_inst (type_argc);
1574 object_context.method_inst = NULL;
1577 g_assert (object_context.class_inst || object_context.method_inst);
1579 return object_context;
1582 static gboolean gshared_supported;
1585 mono_set_generic_sharing_supported (gboolean supported)
1587 gshared_supported = supported;
1591 * mono_class_generic_sharing_enabled:
1594 * Returns whether generic sharing is enabled for class.
1596 * This is a stop-gap measure to slowly introduce generic sharing
1597 * until we have all the issues sorted out, at which time this
1598 * function will disappear and generic sharing will always be enabled.
1601 mono_class_generic_sharing_enabled (MonoClass *class)
1603 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1604 static gboolean inited = FALSE;
1609 if (gshared_supported)
1610 generic_sharing = MONO_GENERIC_SHARING_ALL;
1612 generic_sharing = MONO_GENERIC_SHARING_NONE;
1614 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1615 if (strcmp (option, "corlib") == 0)
1616 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1617 else if (strcmp (option, "collections") == 0)
1618 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1619 else if (strcmp (option, "all") == 0)
1620 generic_sharing = MONO_GENERIC_SHARING_ALL;
1621 else if (strcmp (option, "none") == 0)
1622 generic_sharing = MONO_GENERIC_SHARING_NONE;
1624 g_warning ("Unknown generic sharing option `%s'.", option);
1627 if (!gshared_supported)
1628 generic_sharing = MONO_GENERIC_SHARING_NONE;
1633 switch (generic_sharing) {
1634 case MONO_GENERIC_SHARING_NONE:
1636 case MONO_GENERIC_SHARING_ALL:
1638 case MONO_GENERIC_SHARING_CORLIB :
1639 return class->image == mono_defaults.corlib;
1640 case MONO_GENERIC_SHARING_COLLECTIONS:
1641 if (class->image != mono_defaults.corlib)
1643 while (class->nested_in)
1644 class = class->nested_in;
1645 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1647 g_assert_not_reached ();
1653 * mono_get_generic_context_from_code:
1655 * Return the runtime generic context belonging to the method whose native code
1658 MonoGenericSharingContext*
1659 mono_get_generic_context_from_code (guint8 *code)
1661 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1663 g_assert (jit_info);
1665 return mono_jit_info_get_generic_sharing_context (jit_info);
1669 mini_method_get_context (MonoMethod *method)
1671 return mono_method_get_context_general (method, TRUE);
1675 * mono_method_check_context_used:
1678 * Checks whether the method's generic context uses a type variable.
1679 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1680 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1681 * context's class or method instantiation uses type variables.
1684 mono_method_check_context_used (MonoMethod *method)
1686 MonoGenericContext *method_context = mini_method_get_context (method);
1687 int context_used = 0;
1689 if (!method_context) {
1690 /* It might be a method of an array of an open generic type */
1691 if (method->klass->rank)
1692 context_used = mono_class_check_context_used (method->klass);
1694 context_used = mono_generic_context_check_used (method_context);
1695 context_used |= mono_class_check_context_used (method->klass);
1698 return context_used;
1702 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
1713 if (inst1->type_argc != inst2->type_argc)
1716 for (i = 0; i < inst1->type_argc; ++i)
1717 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
1724 * mono_generic_context_equal_deep:
1725 * @context1: a generic context
1726 * @context2: a generic context
1728 * Returns whether context1's type arguments are equal to context2's
1732 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
1734 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
1735 generic_inst_equal (context1->method_inst, context2->method_inst);
1739 * mini_class_get_container_class:
1740 * @class: a generic class
1742 * Returns the class's container class, which is the class itself if
1743 * it doesn't have generic_class set.
1746 mini_class_get_container_class (MonoClass *class)
1748 if (class->generic_class)
1749 return class->generic_class->container_class;
1751 g_assert (class->generic_container);
1756 * mini_class_get_context:
1757 * @class: a generic class
1759 * Returns the class's generic context.
1762 mini_class_get_context (MonoClass *class)
1764 if (class->generic_class)
1765 return &class->generic_class->context;
1767 g_assert (class->generic_container);
1768 return &class->generic_container->context;
1772 * mini_get_basic_type_from_generic:
1773 * @gsctx: a generic sharing context
1776 * Returns a closed type corresponding to the possibly open type
1780 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
1782 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1785 return mono_type_get_basic_type_from_generic (type);
1789 * mini_type_get_underlying_type:
1791 * Return the underlying type of TYPE, taking into account enums, byref and generic
1795 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
1798 return &mono_defaults.int_class->byval_arg;
1799 return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
1803 * mini_type_stack_size:
1804 * @gsctx: a generic sharing context
1806 * @align: Pointer to an int for returning the alignment
1808 * Returns the type's stack size and the alignment in *align. The
1809 * type is allowed to be open.
1812 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
1814 gboolean allow_open = TRUE;
1816 // FIXME: Some callers might not pass in a gsctx
1817 //allow_open = gsctx != NULL;
1818 return mono_type_stack_size_internal (t, align, allow_open);
1822 * mini_type_stack_size_full:
1824 * Same as mini_type_stack_size, but handle pinvoke data types as well.
1827 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
1832 size = mono_type_native_stack_size (t, align);
1837 size = mini_type_stack_size (gsctx, t, &ialign);
1840 size = mini_type_stack_size (gsctx, t, NULL);
1848 * mono_generic_sharing_init:
1850 * Register the generic sharing counters.
1853 mono_generic_sharing_init (void)
1855 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1859 mono_generic_sharing_cleanup (void)
1861 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1863 if (generic_subclass_hash)
1864 g_hash_table_destroy (generic_subclass_hash);