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 * Return true if this info type has the notion of identify.
365 * Some info types expect that each insert results in a new slot been assigned.
368 other_info_has_identity (int info_type)
370 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
374 * LOCKING: loader lock
377 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
378 int slot, gpointer data, int info_type)
380 static gboolean inited = FALSE;
381 static int num_markers = 0;
382 static int num_data = 0;
385 MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
386 MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
389 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
390 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
394 g_assert (slot >= 0);
402 *oti = alloc_oti (image);
406 g_assert (!(*oti)->data);
408 (*oti)->info_type = info_type;
410 set_other_info_templates (image, template, type_argc, list);
412 if (data == MONO_RGCTX_SLOT_USED_MARKER)
419 * mono_method_get_declaring_generic_method:
420 * @method: an inflated method
422 * Returns an inflated method's declaring method.
425 mono_method_get_declaring_generic_method (MonoMethod *method)
427 MonoMethodInflated *inflated;
429 g_assert (method->is_inflated);
431 inflated = (MonoMethodInflated*)method;
433 return inflated->declaring;
437 * mono_class_get_method_generic:
441 * Given a class and a generic method, which has to be of an
442 * instantiation of the same class that klass is an instantiation of,
443 * returns the corresponding method in klass. Example:
445 * klass is Gen<string>
446 * method is Gen<object>.work<int>
448 * returns: Gen<string>.work<int>
451 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
453 MonoMethod *declaring, *m;
456 if (method->is_inflated)
457 declaring = mono_method_get_declaring_generic_method (method);
462 if (klass->generic_class)
463 m = mono_class_get_inflated_method (klass, declaring);
466 mono_class_setup_methods (klass);
467 if (klass->exception_type)
469 for (i = 0; i < klass->method.count; ++i) {
470 m = klass->methods [i];
473 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
476 if (i >= klass->method.count)
480 if (method != declaring) {
481 MonoGenericContext context;
483 context.class_inst = NULL;
484 context.method_inst = mono_method_get_context (method)->method_inst;
486 m = mono_class_inflate_generic_method (m, &context);
493 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
499 if (data == MONO_RGCTX_SLOT_USED_MARKER)
500 return MONO_RGCTX_SLOT_USED_MARKER;
504 case MONO_RGCTX_INFO_STATIC_DATA:
505 case MONO_RGCTX_INFO_KLASS:
506 case MONO_RGCTX_INFO_VTABLE:
507 case MONO_RGCTX_INFO_TYPE:
508 case MONO_RGCTX_INFO_REFLECTION_TYPE:
509 case MONO_RGCTX_INFO_CAST_CACHE: {
510 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
511 data, context, &error);
512 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
516 case MONO_RGCTX_INFO_METHOD:
517 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
518 case MONO_RGCTX_INFO_METHOD_RGCTX:
519 case MONO_RGCTX_INFO_METHOD_CONTEXT:
520 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
521 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
522 MonoMethod *method = data;
523 MonoMethod *inflated_method;
524 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
525 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
527 mono_metadata_free_type (inflated_type);
529 mono_class_init (inflated_class);
531 g_assert (!method->wrapper_type);
533 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
534 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
535 inflated_method = mono_method_search_in_array_class (inflated_class,
536 method->name, method->signature);
538 inflated_method = mono_class_inflate_generic_method (method, context);
540 mono_class_init (inflated_method->klass);
541 g_assert (inflated_method->klass == inflated_class);
542 return inflated_method;
545 case MONO_RGCTX_INFO_CLASS_FIELD: {
546 MonoClassField *field = data;
547 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
548 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
549 int i = field - field->parent->fields;
550 gpointer dummy = NULL;
552 mono_metadata_free_type (inflated_type);
554 mono_class_get_fields (inflated_class, &dummy);
555 g_assert (inflated_class->fields);
557 return &inflated_class->fields [i];
561 g_assert_not_reached ();
563 /* Not reached, quiet compiler */
568 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
569 MonoGenericContext *context, MonoClass *class, gboolean temporary)
571 return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
575 free_inflated_info (int info_type, gpointer info)
581 case MONO_RGCTX_INFO_STATIC_DATA:
582 case MONO_RGCTX_INFO_KLASS:
583 case MONO_RGCTX_INFO_VTABLE:
584 case MONO_RGCTX_INFO_TYPE:
585 case MONO_RGCTX_INFO_REFLECTION_TYPE:
586 case MONO_RGCTX_INFO_CAST_CACHE:
587 mono_metadata_free_type (info);
594 static MonoRuntimeGenericContextOtherInfoTemplate
595 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
598 class_uninstantiated (MonoClass *class)
600 if (class->generic_class)
601 return class->generic_class->container_class;
606 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
607 gboolean allow_partial)
611 for (i = 0; i < inst->type_argc; ++i) {
612 MonoType *type = inst->type_argv [i];
614 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
618 * Allow non ref arguments, if there is at least one ref argument
620 * FIXME: Allow more types
622 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)))
632 * mono_is_partially_sharable_inst:
634 * Return TRUE if INST has ref and non-ref type arguments.
637 mono_is_partially_sharable_inst (MonoGenericInst *inst)
640 gboolean has_refs = FALSE, has_non_refs = FALSE;
642 for (i = 0; i < inst->type_argc; ++i) {
643 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)
649 return has_refs && has_non_refs;
655 * Return the class used to store information when using generic sharing.
656 * For fully shared classes, it is the generic definition, for partially shared
657 * classes, it is an instance with all ref type arguments replaced by the type parameters
658 * of its generic definition.
661 get_shared_class (MonoClass *class)
664 * FIXME: This conflicts with normal instances. Also, some code in this file
665 * like class_get_rgctx_template_oti treats these as normal generic instances
666 * instead of generic classes.
668 //g_assert_not_reached ();
670 if (class->is_inflated) {
671 MonoGenericContext *context = &class->generic_class->context;
672 MonoGenericContext *container_context;
673 MonoGenericContext shared_context;
674 MonoGenericInst *inst;
675 MonoType **type_argv;
678 inst = context->class_inst;
679 if (mono_is_partially_sharable_inst (inst)) {
680 container_context = &class->generic_class->container_class->generic_container->context;
681 type_argv = g_new0 (MonoType*, inst->type_argc);
682 for (i = 0; i < inst->type_argc; ++i) {
683 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)
684 type_argv [i] = container_context->class_inst->type_argv [i];
686 type_argv [i] = inst->type_argv [i];
689 memset (&shared_context, 0, sizeof (MonoGenericContext));
690 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
693 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
694 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
695 /* Happens for partially shared methods of nono-sharable generic class */
700 return class_uninstantiated (class);
704 * mono_class_get_runtime_generic_context_template:
707 * Looks up or constructs, if necessary, the runtime generic context
710 static MonoRuntimeGenericContextTemplate*
711 mono_class_get_runtime_generic_context_template (MonoClass *class)
713 MonoRuntimeGenericContextTemplate *parent_template, *template;
717 template = class_lookup_rgctx_template (class);
718 mono_loader_unlock ();
723 //g_assert (get_shared_class (class) == class);
725 template = alloc_template (class);
730 if (class->parent->generic_class) {
732 int max_argc, type_argc;
734 parent_template = mono_class_get_runtime_generic_context_template
735 (class->parent->generic_class->container_class);
737 max_argc = template_get_max_argc (parent_template);
739 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
740 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
742 /* FIXME: quadratic! */
743 for (i = 0; i < num_entries; ++i) {
744 MonoRuntimeGenericContextOtherInfoTemplate oti;
746 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
747 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
748 rgctx_template_set_other_slot (class->image, template, type_argc, i,
749 oti.data, oti.info_type);
754 MonoRuntimeGenericContextOtherInfoTemplate *oti;
755 int max_argc, type_argc;
757 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
759 max_argc = template_get_max_argc (parent_template);
761 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
762 /* FIXME: quadratic! */
763 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
764 if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
765 rgctx_template_set_other_slot (class->image, template, type_argc, i,
766 oti->data, oti->info_type);
773 if (class_lookup_rgctx_template (class)) {
774 /* some other thread already set the template */
775 template = class_lookup_rgctx_template (class);
777 class_set_rgctx_template (class, template);
780 register_generic_subclass (class);
783 mono_loader_unlock ();
789 * temporary signifies whether the inflated info (oti.data) will be
790 * used temporarily, in which case it might be heap-allocated, or
791 * permanently, in which case it will be mempool-allocated. If
792 * temporary is set then *do_free will return whether the returned
793 * data must be freed.
795 * LOCKING: loader lock
797 static MonoRuntimeGenericContextOtherInfoTemplate
798 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
800 g_assert ((temporary && do_free) || (!temporary && !do_free));
802 if (class->generic_class && !shared) {
803 MonoRuntimeGenericContextOtherInfoTemplate oti;
804 gboolean tmp_do_free;
806 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
807 type_argc, slot, TRUE, FALSE, &tmp_do_free);
809 gpointer info = oti.data;
810 oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
812 free_inflated_info (oti.info_type, info);
819 MonoRuntimeGenericContextTemplate *template;
820 MonoRuntimeGenericContextOtherInfoTemplate *oti;
822 template = mono_class_get_runtime_generic_context_template (class);
823 oti = rgctx_template_get_other_slot (template, type_argc, slot);
834 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
837 case MONO_RGCTX_INFO_STATIC_DATA: {
838 MonoVTable *vtable = mono_class_vtable (domain, class);
840 mono_raise_exception (mono_class_get_exception_for_failure (class));
843 case MONO_RGCTX_INFO_KLASS:
845 case MONO_RGCTX_INFO_VTABLE: {
846 MonoVTable *vtable = mono_class_vtable (domain, class);
848 mono_raise_exception (mono_class_get_exception_for_failure (class));
851 case MONO_RGCTX_INFO_CAST_CACHE: {
852 /*First slot is the cache itself, the second the vtable.*/
853 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
854 cache_data [1] = (gpointer)class;
858 g_assert_not_reached ();
865 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
866 MonoGenericContext *context, MonoClass *class)
874 switch (oti->info_type) {
875 case MONO_RGCTX_INFO_STATIC_DATA:
876 case MONO_RGCTX_INFO_KLASS:
877 case MONO_RGCTX_INFO_VTABLE:
878 case MONO_RGCTX_INFO_CAST_CACHE:
885 data = inflate_other_info (oti, context, class, temporary);
887 switch (oti->info_type) {
888 case MONO_RGCTX_INFO_STATIC_DATA:
889 case MONO_RGCTX_INFO_KLASS:
890 case MONO_RGCTX_INFO_VTABLE:
891 case MONO_RGCTX_INFO_CAST_CACHE: {
892 MonoClass *arg_class = mono_class_from_mono_type (data);
894 free_inflated_info (oti->info_type, data);
895 g_assert (arg_class);
897 /* The class might be used as an argument to
898 mono_value_copy(), which requires that its GC
899 descriptor has been computed. */
900 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
901 mono_class_compute_gc_descriptor (arg_class);
903 return class_type_info (domain, arg_class, oti->info_type);
905 case MONO_RGCTX_INFO_TYPE:
907 case MONO_RGCTX_INFO_REFLECTION_TYPE:
908 return mono_type_get_object (domain, data);
909 case MONO_RGCTX_INFO_METHOD:
911 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
913 * We can't create a jump trampoline here, as it cannot be patched.
915 return mono_compile_method (data);
916 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
917 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
918 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
919 return mono_domain_alloc0 (domain, sizeof (gpointer));
920 case MONO_RGCTX_INFO_CLASS_FIELD:
922 case MONO_RGCTX_INFO_METHOD_RGCTX: {
923 MonoMethodInflated *method = data;
926 g_assert (method->method.method.is_inflated);
927 g_assert (method->context.method_inst);
929 vtable = mono_class_vtable (domain, method->method.method.klass);
931 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
933 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
935 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
936 MonoMethodInflated *method = data;
938 g_assert (method->method.method.is_inflated);
939 g_assert (method->context.method_inst);
941 return method->context.method_inst;
944 g_assert_not_reached ();
951 * LOCKING: loader lock
954 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
956 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
959 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
961 /* Recurse for all subclasses */
962 if (generic_subclass_hash)
963 subclass = g_hash_table_lookup (generic_subclass_hash, class);
968 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
969 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
971 g_assert (subclass_template);
973 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
974 g_assert (subclass_oti.data);
976 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
978 subclass = subclass_template->next_subclass;
983 * LOCKING: loader lock
986 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
989 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
991 MonoRuntimeGenericContextOtherInfoTemplate *oti;
993 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
998 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
1000 /* Mark the slot as used in all parent classes (until we find
1001 a parent class which already has it marked used). */
1002 parent = class->parent;
1003 while (parent != NULL) {
1004 MonoRuntimeGenericContextTemplate *parent_template;
1005 MonoRuntimeGenericContextOtherInfoTemplate *oti;
1007 if (parent->generic_class)
1008 parent = parent->generic_class->container_class;
1010 parent_template = mono_class_get_runtime_generic_context_template (parent);
1011 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1013 if (oti && oti->data)
1016 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
1017 MONO_RGCTX_SLOT_USED_MARKER, 0);
1019 parent = parent->parent;
1022 /* Fill in the slot in this class and in all subclasses
1024 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1030 other_info_equal (gpointer data1, gpointer data2, int info_type)
1032 switch (info_type) {
1033 case MONO_RGCTX_INFO_STATIC_DATA:
1034 case MONO_RGCTX_INFO_KLASS:
1035 case MONO_RGCTX_INFO_VTABLE:
1036 case MONO_RGCTX_INFO_TYPE:
1037 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1038 case MONO_RGCTX_INFO_CAST_CACHE:
1039 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1040 case MONO_RGCTX_INFO_METHOD:
1041 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1042 case MONO_RGCTX_INFO_CLASS_FIELD:
1043 case MONO_RGCTX_INFO_METHOD_RGCTX:
1044 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1045 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1046 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1047 return data1 == data2;
1049 g_assert_not_reached ();
1056 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
1057 MonoGenericContext *generic_context)
1059 static gboolean inited = FALSE;
1060 static int max_slot = 0;
1062 MonoRuntimeGenericContextTemplate *rgctx_template =
1063 mono_class_get_runtime_generic_context_template (class);
1064 MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
1067 mono_loader_lock ();
1069 if (other_info_has_identity (info_type)) {
1070 oti_list = get_other_info_templates (rgctx_template, type_argc);
1072 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1073 gpointer inflated_data;
1075 if (oti->info_type != info_type || !oti->data)
1078 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
1080 if (other_info_equal (data, inflated_data, info_type)) {
1081 free_inflated_info (info_type, inflated_data);
1082 mono_loader_unlock ();
1085 free_inflated_info (info_type, inflated_data);
1089 /* We haven't found the info */
1090 i = register_other_info (class, type_argc, data, info_type);
1092 mono_loader_unlock ();
1095 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1105 * mono_method_lookup_or_register_other_info:
1107 * @in_mrgctx: whether to put the data into the MRGCTX
1108 * @data: the info data
1109 * @info_type: the type of info to register about data
1110 * @generic_context: a generic context
1112 * Looks up and, if necessary, adds information about other_class in
1113 * method's or method's class runtime generic context. Returns the
1114 * encoded slot number.
1117 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1118 int info_type, MonoGenericContext *generic_context)
1120 MonoClass *class = method->klass;
1121 int type_argc, index;
1124 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1126 g_assert (method->is_inflated && method_inst);
1127 type_argc = method_inst->type_argc;
1128 g_assert (type_argc > 0);
1133 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1135 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1138 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1140 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1144 * mono_class_rgctx_get_array_size:
1145 * @n: The number of the array
1146 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1148 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1149 * number includes the slot for linking and - for MRGCTXs - the two
1150 * slots in the first array for additional information.
1153 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1155 g_assert (n >= 0 && n < 30);
1164 * LOCKING: domain lock
1167 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1169 static gboolean inited = FALSE;
1170 static int rgctx_num_alloced = 0;
1171 static int rgctx_bytes_alloced = 0;
1172 static int mrgctx_num_alloced = 0;
1173 static int mrgctx_bytes_alloced = 0;
1175 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1176 gpointer array = mono_domain_alloc0 (domain, size);
1179 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1180 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1181 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1182 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1187 mrgctx_num_alloced++;
1188 mrgctx_bytes_alloced += size;
1190 rgctx_num_alloced++;
1191 rgctx_bytes_alloced += size;
1198 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1199 MonoGenericInst *method_inst)
1202 int i, first_slot, size;
1203 MonoDomain *domain = class_vtable->domain;
1204 MonoClass *class = class_vtable->klass;
1205 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1206 MonoRuntimeGenericContextOtherInfoTemplate oti;
1207 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1213 mono_domain_lock (domain);
1215 /* First check whether that slot isn't already instantiated.
1216 This might happen because lookup doesn't lock. Allocate
1217 arrays on the way. */
1219 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1221 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1222 for (i = 0; ; ++i) {
1225 if (method_inst && i == 0)
1226 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1230 if (slot < first_slot + size - 1) {
1231 rgctx_index = slot - first_slot + 1 + offset;
1232 info = rgctx [rgctx_index];
1234 mono_domain_unlock (domain);
1239 if (!rgctx [offset + 0])
1240 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1241 rgctx = rgctx [offset + 0];
1242 first_slot += size - 1;
1243 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1246 g_assert (!rgctx [rgctx_index]);
1248 mono_domain_unlock (domain);
1250 oti = class_get_rgctx_template_oti (get_shared_class (class),
1251 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1252 /* This might take the loader lock */
1253 info = instantiate_other_info (domain, &oti, &context, class);
1257 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1260 /*FIXME We should use CAS here, no need to take a lock.*/
1261 mono_domain_lock (domain);
1263 /* Check whether the slot hasn't been instantiated in the
1265 if (rgctx [rgctx_index])
1266 info = rgctx [rgctx_index];
1268 rgctx [rgctx_index] = info;
1270 mono_domain_unlock (domain);
1273 free_inflated_info (oti.info_type, oti.data);
1279 * mono_class_fill_runtime_generic_context:
1280 * @class_vtable: a vtable
1281 * @slot: a slot index to be instantiated
1283 * Instantiates a slot in the RGCTX.
1286 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1288 static gboolean inited = FALSE;
1289 static int num_alloced = 0;
1291 MonoDomain *domain = class_vtable->domain;
1292 MonoRuntimeGenericContext *rgctx;
1295 mono_domain_lock (domain);
1298 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1302 rgctx = class_vtable->runtime_generic_context;
1304 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1305 class_vtable->runtime_generic_context = rgctx;
1309 mono_domain_unlock (domain);
1311 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1317 * mono_method_fill_runtime_generic_context:
1318 * @mrgctx: an MRGCTX
1319 * @slot: a slot index to be instantiated
1321 * Instantiates a slot in the MRGCTX.
1324 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1328 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1329 mrgctx->method_inst);
1335 mrgctx_hash_func (gconstpointer key)
1337 const MonoMethodRuntimeGenericContext *mrgctx = key;
1339 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1343 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1345 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1346 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1348 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1349 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1353 * mono_method_lookup_rgctx:
1354 * @class_vtable: a vtable
1355 * @method_inst: the method inst of a generic method
1357 * Returns the MRGCTX for the generic method(s) with the given
1358 * method_inst of the given class_vtable.
1360 * LOCKING: Take the domain lock.
1362 MonoMethodRuntimeGenericContext*
1363 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1365 MonoDomain *domain = class_vtable->domain;
1366 MonoMethodRuntimeGenericContext *mrgctx;
1367 MonoMethodRuntimeGenericContext key;
1369 g_assert (!class_vtable->klass->generic_container);
1370 g_assert (!method_inst->is_open);
1372 mono_domain_lock (domain);
1373 if (!domain->method_rgctx_hash)
1374 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1376 key.class_vtable = class_vtable;
1377 key.method_inst = method_inst;
1379 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1384 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1385 mrgctx->class_vtable = class_vtable;
1386 mrgctx->method_inst = method_inst;
1388 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1391 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1392 for (i = 0; i < method_inst->type_argc; ++i)
1393 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1398 mono_domain_unlock (domain);
1406 * mono_generic_context_is_sharable_full:
1407 * @context: a generic context
1409 * Returns whether the generic context is sharable. A generic context
1410 * is sharable iff all of its type arguments are reference type, or some of them have a
1411 * reference type, and ALLOW_PARTIAL is TRUE.
1414 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1415 gboolean allow_type_vars,
1416 gboolean allow_partial)
1418 g_assert (context->class_inst || context->method_inst);
1420 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1423 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1430 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1432 return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1436 * mono_method_is_generic_impl:
1439 * Returns whether the method is either generic or part of a generic
1443 mono_method_is_generic_impl (MonoMethod *method)
1445 if (method->is_inflated) {
1446 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1449 /* We don't treat wrappers as generic code, i.e., we never
1450 apply generic sharing to them. This is especially
1451 important for static rgctx invoke wrappers, which only work
1452 if not compiled with sharing. */
1453 if (method->wrapper_type != MONO_WRAPPER_NONE)
1455 if (method->klass->generic_container)
1461 has_constraints (MonoGenericContainer *container)
1467 g_assert (container->type_argc > 0);
1468 g_assert (container->type_params);
1470 for (i = 0; i < container->type_argc; ++i)
1471 if (container->type_params [i].constraints)
1478 * mono_method_is_generic_sharable_impl_full:
1480 * @allow_type_vars: whether to regard type variables as reference types
1481 * @alloc_partial: whether to allow partial sharing
1483 * Returns TRUE iff the method is inflated or part of an inflated
1484 * class, its context is sharable and it has no constraints on its
1485 * type parameters. Otherwise returns FALSE.
1488 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1489 gboolean allow_partial)
1491 if (!mono_method_is_generic_impl (method))
1494 if (method->is_inflated) {
1495 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1496 MonoGenericContext *context = &inflated->context;
1498 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1501 g_assert (inflated->declaring);
1503 if (inflated->declaring->is_generic) {
1504 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1509 if (method->klass->generic_class) {
1510 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1513 g_assert (method->klass->generic_class->container_class &&
1514 method->klass->generic_class->container_class->generic_container);
1516 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1520 if (method->klass->generic_container && !allow_type_vars)
1527 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1529 return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING);
1533 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1535 if (!mono_class_generic_sharing_enabled (method->klass))
1538 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1541 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1544 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1545 method->klass->valuetype) &&
1546 (method->klass->generic_class || method->klass->generic_container);
1549 static MonoGenericInst*
1550 get_object_generic_inst (int type_argc)
1552 MonoType **type_argv;
1555 type_argv = alloca (sizeof (MonoType*) * type_argc);
1557 for (i = 0; i < type_argc; ++i)
1558 type_argv [i] = &mono_defaults.object_class->byval_arg;
1560 return mono_metadata_get_generic_inst (type_argc, type_argv);
1564 * mono_method_construct_object_context:
1567 * Returns a generic context for method with all type variables for
1568 * class and method instantiated with Object.
1571 mono_method_construct_object_context (MonoMethod *method)
1573 MonoGenericContext object_context;
1575 g_assert (!method->klass->generic_class);
1576 if (method->klass->generic_container) {
1577 int type_argc = method->klass->generic_container->type_argc;
1579 object_context.class_inst = get_object_generic_inst (type_argc);
1581 object_context.class_inst = NULL;
1584 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1585 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1587 object_context.method_inst = get_object_generic_inst (type_argc);
1589 object_context.method_inst = NULL;
1592 g_assert (object_context.class_inst || object_context.method_inst);
1594 return object_context;
1597 static gboolean gshared_supported;
1600 mono_set_generic_sharing_supported (gboolean supported)
1602 gshared_supported = supported;
1606 * mono_class_generic_sharing_enabled:
1609 * Returns whether generic sharing is enabled for class.
1611 * This is a stop-gap measure to slowly introduce generic sharing
1612 * until we have all the issues sorted out, at which time this
1613 * function will disappear and generic sharing will always be enabled.
1616 mono_class_generic_sharing_enabled (MonoClass *class)
1618 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1619 static gboolean inited = FALSE;
1624 if (gshared_supported)
1625 generic_sharing = MONO_GENERIC_SHARING_ALL;
1627 generic_sharing = MONO_GENERIC_SHARING_NONE;
1629 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1630 if (strcmp (option, "corlib") == 0)
1631 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1632 else if (strcmp (option, "collections") == 0)
1633 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1634 else if (strcmp (option, "all") == 0)
1635 generic_sharing = MONO_GENERIC_SHARING_ALL;
1636 else if (strcmp (option, "none") == 0)
1637 generic_sharing = MONO_GENERIC_SHARING_NONE;
1639 g_warning ("Unknown generic sharing option `%s'.", option);
1642 if (!gshared_supported)
1643 generic_sharing = MONO_GENERIC_SHARING_NONE;
1648 switch (generic_sharing) {
1649 case MONO_GENERIC_SHARING_NONE:
1651 case MONO_GENERIC_SHARING_ALL:
1653 case MONO_GENERIC_SHARING_CORLIB :
1654 return class->image == mono_defaults.corlib;
1655 case MONO_GENERIC_SHARING_COLLECTIONS:
1656 if (class->image != mono_defaults.corlib)
1658 while (class->nested_in)
1659 class = class->nested_in;
1660 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1662 g_assert_not_reached ();
1668 * mono_get_generic_context_from_code:
1670 * Return the runtime generic context belonging to the method whose native code
1673 MonoGenericSharingContext*
1674 mono_get_generic_context_from_code (guint8 *code)
1676 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1678 g_assert (jit_info);
1680 return mono_jit_info_get_generic_sharing_context (jit_info);
1684 mini_method_get_context (MonoMethod *method)
1686 return mono_method_get_context_general (method, TRUE);
1690 * mono_method_check_context_used:
1693 * Checks whether the method's generic context uses a type variable.
1694 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1695 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1696 * context's class or method instantiation uses type variables.
1699 mono_method_check_context_used (MonoMethod *method)
1701 MonoGenericContext *method_context = mini_method_get_context (method);
1702 int context_used = 0;
1704 if (!method_context) {
1705 /* It might be a method of an array of an open generic type */
1706 if (method->klass->rank)
1707 context_used = mono_class_check_context_used (method->klass);
1709 context_used = mono_generic_context_check_used (method_context);
1710 context_used |= mono_class_check_context_used (method->klass);
1713 return context_used;
1717 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
1728 if (inst1->type_argc != inst2->type_argc)
1731 for (i = 0; i < inst1->type_argc; ++i)
1732 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
1739 * mono_generic_context_equal_deep:
1740 * @context1: a generic context
1741 * @context2: a generic context
1743 * Returns whether context1's type arguments are equal to context2's
1747 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
1749 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
1750 generic_inst_equal (context1->method_inst, context2->method_inst);
1754 * mini_class_get_container_class:
1755 * @class: a generic class
1757 * Returns the class's container class, which is the class itself if
1758 * it doesn't have generic_class set.
1761 mini_class_get_container_class (MonoClass *class)
1763 if (class->generic_class)
1764 return class->generic_class->container_class;
1766 g_assert (class->generic_container);
1771 * mini_class_get_context:
1772 * @class: a generic class
1774 * Returns the class's generic context.
1777 mini_class_get_context (MonoClass *class)
1779 if (class->generic_class)
1780 return &class->generic_class->context;
1782 g_assert (class->generic_container);
1783 return &class->generic_container->context;
1787 * mini_get_basic_type_from_generic:
1788 * @gsctx: a generic sharing context
1791 * Returns a closed type corresponding to the possibly open type
1795 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
1797 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1800 return mono_type_get_basic_type_from_generic (type);
1804 * mini_type_get_underlying_type:
1806 * Return the underlying type of TYPE, taking into account enums, byref and generic
1810 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
1813 return &mono_defaults.int_class->byval_arg;
1814 return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
1818 * mini_type_stack_size:
1819 * @gsctx: a generic sharing context
1821 * @align: Pointer to an int for returning the alignment
1823 * Returns the type's stack size and the alignment in *align. The
1824 * type is allowed to be open.
1827 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
1829 gboolean allow_open = TRUE;
1831 // FIXME: Some callers might not pass in a gsctx
1832 //allow_open = gsctx != NULL;
1833 return mono_type_stack_size_internal (t, align, allow_open);
1837 * mini_type_stack_size_full:
1839 * Same as mini_type_stack_size, but handle pinvoke data types as well.
1842 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
1847 size = mono_type_native_stack_size (t, align);
1852 size = mini_type_stack_size (gsctx, t, &ialign);
1855 size = mini_type_stack_size (gsctx, t, NULL);
1863 * mono_generic_sharing_init:
1865 * Register the generic sharing counters.
1868 mono_generic_sharing_init (void)
1870 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1874 mono_generic_sharing_cleanup (void)
1876 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1878 if (generic_subclass_hash)
1879 g_hash_table_destroy (generic_subclass_hash);