2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include <mono/metadata/class.h>
14 #include <mono/utils/mono-counters.h>
18 //#define ALLOW_PARTIAL_SHARING TRUE
19 #define ALLOW_PARTIAL_SHARING FALSE
22 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
25 type_check_context_used (MonoType *type, gboolean recursive)
27 switch (mono_type_get_type (type)) {
29 return MONO_GENERIC_CONTEXT_USED_CLASS;
31 return MONO_GENERIC_CONTEXT_USED_METHOD;
32 case MONO_TYPE_SZARRAY:
33 return mono_class_check_context_used (mono_type_get_class (type));
35 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
38 return mono_class_check_context_used (mono_type_get_class (type));
41 case MONO_TYPE_GENERICINST:
43 MonoGenericClass *gclass = type->data.generic_class;
45 g_assert (gclass->container_class->generic_container);
46 return mono_generic_context_check_used (&gclass->context);
56 inst_check_context_used (MonoGenericInst *inst)
64 for (i = 0; i < inst->type_argc; ++i)
65 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
71 * mono_generic_context_check_used:
72 * @context: a generic context
74 * Checks whether the context uses a type variable. Returns an int
75 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
76 * the context's class instantiation uses type variables.
79 mono_generic_context_check_used (MonoGenericContext *context)
83 context_used |= inst_check_context_used (context->class_inst);
84 context_used |= inst_check_context_used (context->method_inst);
90 * mono_class_check_context_used:
93 * Checks whether the class's generic context uses a type variable.
94 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
95 * reflect whether the context's class instantiation uses type
99 mono_class_check_context_used (MonoClass *class)
101 int context_used = 0;
103 context_used |= type_check_context_used (&class->this_arg, FALSE);
104 context_used |= type_check_context_used (&class->byval_arg, FALSE);
106 if (class->generic_class)
107 context_used |= mono_generic_context_check_used (&class->generic_class->context);
108 else if (class->generic_container)
109 context_used |= mono_generic_context_check_used (&class->generic_container->context);
115 * LOCKING: loader lock
117 static MonoRuntimeGenericContextOtherInfoTemplate*
118 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
120 g_assert (type_argc >= 0);
122 return template->other_infos;
123 return g_slist_nth_data (template->method_templates, type_argc - 1);
127 * LOCKING: loader lock
130 set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
131 MonoRuntimeGenericContextOtherInfoTemplate *oti)
133 g_assert (type_argc >= 0);
135 template->other_infos = oti;
137 int length = g_slist_length (template->method_templates);
140 /* FIXME: quadratic! */
141 while (length < type_argc) {
142 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
146 list = g_slist_nth (template->method_templates, type_argc - 1);
153 * LOCKING: loader lock
156 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
158 return g_slist_length (template->method_templates);
162 * LOCKING: loader lock
164 static MonoRuntimeGenericContextOtherInfoTemplate*
165 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
168 MonoRuntimeGenericContextOtherInfoTemplate *oti;
170 g_assert (slot >= 0);
172 for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
181 * LOCKING: loader lock
184 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
186 MonoRuntimeGenericContextOtherInfoTemplate *oti;
189 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
195 /* Maps from uninstantiated generic classes to GList's of
196 * uninstantiated generic classes whose parent is the key class or an
197 * instance of the key class.
199 * LOCKING: loader lock
201 static GHashTable *generic_subclass_hash;
204 * LOCKING: templates lock
207 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
209 if (!class->image->rgctx_template_hash)
210 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
212 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
216 * LOCKING: loader lock
218 static MonoRuntimeGenericContextTemplate*
219 class_lookup_rgctx_template (MonoClass *class)
221 MonoRuntimeGenericContextTemplate *template;
223 if (!class->image->rgctx_template_hash)
226 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
232 * LOCKING: loader lock
235 register_generic_subclass (MonoClass *class)
237 MonoClass *parent = class->parent;
239 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
241 g_assert (rgctx_template);
243 if (parent->generic_class)
244 parent = parent->generic_class->container_class;
246 if (!generic_subclass_hash)
247 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
249 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
250 rgctx_template->next_subclass = subclass;
251 g_hash_table_insert (generic_subclass_hash, parent, class);
255 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
259 if (class->image == image) {
260 /* The parent class itself is in the image, so all the
261 subclasses must be in the image, too. If not,
262 we're removing an image containing a class which
263 still has a subclass in another image. */
266 g_assert (subclass->image == image);
267 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
275 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
276 MonoClass *next = subclass_template->next_subclass;
278 if (subclass->image != image) {
279 subclass_template->next_subclass = new_list;
287 g_hash_table_insert (generic_subclass_hash, class, new_list);
291 * mono_class_unregister_image_generic_subclasses:
294 * Removes all classes of the image from the generic subclass hash.
295 * Must be called when an image is unloaded.
298 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
300 GHashTable *old_hash;
302 //g_print ("unregistering image %s\n", image->name);
304 if (!generic_subclass_hash)
309 old_hash = generic_subclass_hash;
310 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
312 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
314 mono_loader_unlock ();
316 g_hash_table_destroy (old_hash);
319 static MonoRuntimeGenericContextTemplate*
320 alloc_template (MonoClass *class)
322 static gboolean inited = FALSE;
323 static int num_allocted = 0;
324 static int num_bytes = 0;
326 int size = sizeof (MonoRuntimeGenericContextTemplate);
329 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
330 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
337 return mono_image_alloc0 (class->image, size);
340 static MonoRuntimeGenericContextOtherInfoTemplate*
341 alloc_oti (MonoImage *image)
343 static gboolean inited = FALSE;
344 static int num_allocted = 0;
345 static int num_bytes = 0;
347 int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
350 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
351 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
358 return mono_image_alloc0 (image, size);
361 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
364 * Return true if this info type has the notion of identify.
366 * Some info types expect that each insert results in a new slot been assigned.
369 other_info_has_identity (MonoRgctxInfoType info_type)
371 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
375 * LOCKING: loader lock
378 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
379 int slot, gpointer data, MonoRgctxInfoType info_type)
381 static gboolean inited = FALSE;
382 static int num_markers = 0;
383 static int num_data = 0;
386 MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
387 MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
390 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
391 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
395 g_assert (slot >= 0);
403 *oti = alloc_oti (image);
407 g_assert (!(*oti)->data);
409 (*oti)->info_type = info_type;
411 set_other_info_templates (image, template, type_argc, list);
413 if (data == MONO_RGCTX_SLOT_USED_MARKER)
420 * mono_method_get_declaring_generic_method:
421 * @method: an inflated method
423 * Returns an inflated method's declaring method.
426 mono_method_get_declaring_generic_method (MonoMethod *method)
428 MonoMethodInflated *inflated;
430 g_assert (method->is_inflated);
432 inflated = (MonoMethodInflated*)method;
434 return inflated->declaring;
438 * mono_class_get_method_generic:
442 * Given a class and a generic method, which has to be of an
443 * instantiation of the same class that klass is an instantiation of,
444 * returns the corresponding method in klass. Example:
446 * klass is Gen<string>
447 * method is Gen<object>.work<int>
449 * returns: Gen<string>.work<int>
452 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
454 MonoMethod *declaring, *m;
457 if (method->is_inflated)
458 declaring = mono_method_get_declaring_generic_method (method);
463 if (klass->generic_class)
464 m = mono_class_get_inflated_method (klass, declaring);
467 mono_class_setup_methods (klass);
468 if (klass->exception_type)
470 for (i = 0; i < klass->method.count; ++i) {
471 m = klass->methods [i];
474 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
477 if (i >= klass->method.count)
481 if (method != declaring) {
482 MonoGenericContext context;
484 context.class_inst = NULL;
485 context.method_inst = mono_method_get_context (method)->method_inst;
487 m = mono_class_inflate_generic_method (m, &context);
494 inflate_other_data (gpointer data, MonoRgctxInfoType info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
500 if (data == MONO_RGCTX_SLOT_USED_MARKER)
501 return MONO_RGCTX_SLOT_USED_MARKER;
505 case MONO_RGCTX_INFO_STATIC_DATA:
506 case MONO_RGCTX_INFO_KLASS:
507 case MONO_RGCTX_INFO_VTABLE:
508 case MONO_RGCTX_INFO_TYPE:
509 case MONO_RGCTX_INFO_REFLECTION_TYPE:
510 case MONO_RGCTX_INFO_CAST_CACHE: {
511 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
512 data, context, &error);
513 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
517 case MONO_RGCTX_INFO_METHOD:
518 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
519 case MONO_RGCTX_INFO_METHOD_RGCTX:
520 case MONO_RGCTX_INFO_METHOD_CONTEXT:
521 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
522 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
523 MonoMethod *method = data;
524 MonoMethod *inflated_method;
525 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
526 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
528 mono_metadata_free_type (inflated_type);
530 mono_class_init (inflated_class);
532 g_assert (!method->wrapper_type);
534 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
535 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
536 inflated_method = mono_method_search_in_array_class (inflated_class,
537 method->name, method->signature);
539 inflated_method = mono_class_inflate_generic_method (method, context);
541 mono_class_init (inflated_method->klass);
542 g_assert (inflated_method->klass == inflated_class);
543 return inflated_method;
546 case MONO_RGCTX_INFO_CLASS_FIELD: {
547 MonoClassField *field = data;
548 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
549 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
550 int i = field - field->parent->fields;
551 gpointer dummy = NULL;
553 mono_metadata_free_type (inflated_type);
555 mono_class_get_fields (inflated_class, &dummy);
556 g_assert (inflated_class->fields);
558 return &inflated_class->fields [i];
562 g_assert_not_reached ();
564 /* Not reached, quiet compiler */
569 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
570 MonoGenericContext *context, MonoClass *class, gboolean temporary)
572 return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
576 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
582 case MONO_RGCTX_INFO_STATIC_DATA:
583 case MONO_RGCTX_INFO_KLASS:
584 case MONO_RGCTX_INFO_VTABLE:
585 case MONO_RGCTX_INFO_TYPE:
586 case MONO_RGCTX_INFO_REFLECTION_TYPE:
587 case MONO_RGCTX_INFO_CAST_CACHE:
588 mono_metadata_free_type (info);
595 static MonoRuntimeGenericContextOtherInfoTemplate
596 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
599 class_uninstantiated (MonoClass *class)
601 if (class->generic_class)
602 return class->generic_class->container_class;
607 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
608 gboolean allow_partial)
612 for (i = 0; i < inst->type_argc; ++i) {
613 MonoType *type = inst->type_argv [i];
615 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
619 * Allow non ref arguments, if there is at least one ref argument
621 * FIXME: Allow more types
623 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)))
633 * mono_is_partially_sharable_inst:
635 * Return TRUE if INST has ref and non-ref type arguments.
638 mono_is_partially_sharable_inst (MonoGenericInst *inst)
641 gboolean has_refs = FALSE, has_non_refs = FALSE;
643 for (i = 0; i < inst->type_argc; ++i) {
644 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)
650 return has_refs && has_non_refs;
656 * Return the class used to store information when using generic sharing.
657 * For fully shared classes, it is the generic definition, for partially shared
658 * classes, it is an instance with all ref type arguments replaced by the type parameters
659 * of its generic definition.
662 get_shared_class (MonoClass *class)
665 * FIXME: This conflicts with normal instances. Also, some code in this file
666 * like class_get_rgctx_template_oti treats these as normal generic instances
667 * instead of generic classes.
669 //g_assert_not_reached ();
671 if (class->is_inflated) {
672 MonoGenericContext *context = &class->generic_class->context;
673 MonoGenericContext *container_context;
674 MonoGenericContext shared_context;
675 MonoGenericInst *inst;
676 MonoType **type_argv;
679 inst = context->class_inst;
680 if (mono_is_partially_sharable_inst (inst)) {
681 container_context = &class->generic_class->container_class->generic_container->context;
682 type_argv = g_new0 (MonoType*, inst->type_argc);
683 for (i = 0; i < inst->type_argc; ++i) {
684 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)
685 type_argv [i] = container_context->class_inst->type_argv [i];
687 type_argv [i] = inst->type_argv [i];
690 memset (&shared_context, 0, sizeof (MonoGenericContext));
691 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
694 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
695 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
696 /* Happens for partially shared methods of nono-sharable generic class */
701 return class_uninstantiated (class);
705 * mono_class_get_runtime_generic_context_template:
708 * Looks up or constructs, if necessary, the runtime generic context
711 static MonoRuntimeGenericContextTemplate*
712 mono_class_get_runtime_generic_context_template (MonoClass *class)
714 MonoRuntimeGenericContextTemplate *parent_template, *template;
718 template = class_lookup_rgctx_template (class);
719 mono_loader_unlock ();
724 //g_assert (get_shared_class (class) == class);
726 template = alloc_template (class);
731 if (class->parent->generic_class) {
733 int max_argc, type_argc;
735 parent_template = mono_class_get_runtime_generic_context_template
736 (class->parent->generic_class->container_class);
738 max_argc = template_get_max_argc (parent_template);
740 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
741 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
743 /* FIXME: quadratic! */
744 for (i = 0; i < num_entries; ++i) {
745 MonoRuntimeGenericContextOtherInfoTemplate oti;
747 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
748 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
749 rgctx_template_set_other_slot (class->image, template, type_argc, i,
750 oti.data, oti.info_type);
756 int max_argc, type_argc;
758 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
760 max_argc = template_get_max_argc (parent_template);
762 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
763 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
765 /* FIXME: quadratic! */
766 for (i = 0; i < num_entries; ++i) {
767 MonoRuntimeGenericContextOtherInfoTemplate oti;
769 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
770 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
771 rgctx_template_set_other_slot (class->image, template, type_argc, i,
772 oti.data, oti.info_type);
780 if (class_lookup_rgctx_template (class)) {
781 /* some other thread already set the template */
782 template = class_lookup_rgctx_template (class);
784 class_set_rgctx_template (class, template);
787 register_generic_subclass (class);
790 mono_loader_unlock ();
796 * temporary signifies whether the inflated info (oti.data) will be
797 * used temporarily, in which case it might be heap-allocated, or
798 * permanently, in which case it will be mempool-allocated. If
799 * temporary is set then *do_free will return whether the returned
800 * data must be freed.
802 * LOCKING: loader lock
804 static MonoRuntimeGenericContextOtherInfoTemplate
805 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
807 g_assert ((temporary && do_free) || (!temporary && !do_free));
809 if (class->generic_class && !shared) {
810 MonoRuntimeGenericContextOtherInfoTemplate oti;
811 gboolean tmp_do_free;
813 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
814 type_argc, slot, TRUE, FALSE, &tmp_do_free);
816 gpointer info = oti.data;
817 oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
819 free_inflated_info (oti.info_type, info);
826 MonoRuntimeGenericContextTemplate *template;
827 MonoRuntimeGenericContextOtherInfoTemplate *oti;
829 template = mono_class_get_runtime_generic_context_template (class);
830 oti = rgctx_template_get_other_slot (template, type_argc, slot);
841 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
844 case MONO_RGCTX_INFO_STATIC_DATA: {
845 MonoVTable *vtable = mono_class_vtable (domain, class);
847 mono_raise_exception (mono_class_get_exception_for_failure (class));
848 return mono_vtable_get_static_field_data (vtable);
850 case MONO_RGCTX_INFO_KLASS:
852 case MONO_RGCTX_INFO_VTABLE: {
853 MonoVTable *vtable = mono_class_vtable (domain, class);
855 mono_raise_exception (mono_class_get_exception_for_failure (class));
858 case MONO_RGCTX_INFO_CAST_CACHE: {
859 /*First slot is the cache itself, the second the vtable.*/
860 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
861 cache_data [1] = (gpointer)class;
865 g_assert_not_reached ();
872 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
873 MonoGenericContext *context, MonoClass *class)
881 switch (oti->info_type) {
882 case MONO_RGCTX_INFO_STATIC_DATA:
883 case MONO_RGCTX_INFO_KLASS:
884 case MONO_RGCTX_INFO_VTABLE:
885 case MONO_RGCTX_INFO_CAST_CACHE:
892 data = inflate_other_info (oti, context, class, temporary);
894 switch (oti->info_type) {
895 case MONO_RGCTX_INFO_STATIC_DATA:
896 case MONO_RGCTX_INFO_KLASS:
897 case MONO_RGCTX_INFO_VTABLE:
898 case MONO_RGCTX_INFO_CAST_CACHE: {
899 MonoClass *arg_class = mono_class_from_mono_type (data);
901 free_inflated_info (oti->info_type, data);
902 g_assert (arg_class);
904 /* The class might be used as an argument to
905 mono_value_copy(), which requires that its GC
906 descriptor has been computed. */
907 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
908 mono_class_compute_gc_descriptor (arg_class);
910 return class_type_info (domain, arg_class, oti->info_type);
912 case MONO_RGCTX_INFO_TYPE:
914 case MONO_RGCTX_INFO_REFLECTION_TYPE:
915 return mono_type_get_object (domain, data);
916 case MONO_RGCTX_INFO_METHOD:
918 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
920 * We can't create a jump trampoline here, as it cannot be patched.
922 return mono_compile_method (data);
923 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
924 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
925 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
926 return mono_domain_alloc0 (domain, sizeof (gpointer));
927 case MONO_RGCTX_INFO_CLASS_FIELD:
929 case MONO_RGCTX_INFO_METHOD_RGCTX: {
930 MonoMethodInflated *method = data;
933 g_assert (method->method.method.is_inflated);
934 g_assert (method->context.method_inst);
936 vtable = mono_class_vtable (domain, method->method.method.klass);
938 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
940 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
942 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
943 MonoMethodInflated *method = data;
945 g_assert (method->method.method.is_inflated);
946 g_assert (method->context.method_inst);
948 return method->context.method_inst;
951 g_assert_not_reached ();
958 * LOCKING: loader lock
961 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
963 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
966 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
968 /* Recurse for all subclasses */
969 if (generic_subclass_hash)
970 subclass = g_hash_table_lookup (generic_subclass_hash, class);
975 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
976 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
978 g_assert (subclass_template);
980 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
981 g_assert (subclass_oti.data);
983 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
985 subclass = subclass_template->next_subclass;
990 * LOCKING: loader lock
993 register_other_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
996 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
998 MonoRuntimeGenericContextOtherInfoTemplate *oti;
1000 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1005 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
1007 /* Mark the slot as used in all parent classes (until we find
1008 a parent class which already has it marked used). */
1009 parent = class->parent;
1010 while (parent != NULL) {
1011 MonoRuntimeGenericContextTemplate *parent_template;
1012 MonoRuntimeGenericContextOtherInfoTemplate *oti;
1014 if (parent->generic_class)
1015 parent = parent->generic_class->container_class;
1017 parent_template = mono_class_get_runtime_generic_context_template (parent);
1018 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1020 if (oti && oti->data)
1023 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
1024 MONO_RGCTX_SLOT_USED_MARKER, 0);
1026 parent = parent->parent;
1029 /* Fill in the slot in this class and in all subclasses
1031 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1037 other_info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1039 switch (info_type) {
1040 case MONO_RGCTX_INFO_STATIC_DATA:
1041 case MONO_RGCTX_INFO_KLASS:
1042 case MONO_RGCTX_INFO_VTABLE:
1043 case MONO_RGCTX_INFO_TYPE:
1044 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1045 case MONO_RGCTX_INFO_CAST_CACHE:
1046 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1047 case MONO_RGCTX_INFO_METHOD:
1048 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1049 case MONO_RGCTX_INFO_CLASS_FIELD:
1050 case MONO_RGCTX_INFO_METHOD_RGCTX:
1051 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1052 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1053 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1054 return data1 == data2;
1056 g_assert_not_reached ();
1063 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1064 MonoGenericContext *generic_context)
1066 static gboolean inited = FALSE;
1067 static int max_slot = 0;
1069 MonoRuntimeGenericContextTemplate *rgctx_template =
1070 mono_class_get_runtime_generic_context_template (class);
1071 MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
1074 mono_loader_lock ();
1076 if (other_info_has_identity (info_type)) {
1077 oti_list = get_other_info_templates (rgctx_template, type_argc);
1079 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1080 gpointer inflated_data;
1082 if (oti->info_type != info_type || !oti->data)
1085 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
1087 if (other_info_equal (data, inflated_data, info_type)) {
1088 free_inflated_info (info_type, inflated_data);
1089 mono_loader_unlock ();
1092 free_inflated_info (info_type, inflated_data);
1096 /* We haven't found the info */
1097 i = register_other_info (class, type_argc, data, info_type);
1099 mono_loader_unlock ();
1102 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1112 * mono_method_lookup_or_register_other_info:
1114 * @in_mrgctx: whether to put the data into the MRGCTX
1115 * @data: the info data
1116 * @info_type: the type of info to register about data
1117 * @generic_context: a generic context
1119 * Looks up and, if necessary, adds information about data/info_type in
1120 * method's or method's class runtime generic context. Returns the
1121 * encoded slot number.
1124 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1125 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1127 MonoClass *class = method->klass;
1128 int type_argc, index;
1131 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1133 g_assert (method->is_inflated && method_inst);
1134 type_argc = method_inst->type_argc;
1135 g_assert (type_argc > 0);
1140 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1142 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1145 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1147 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1151 * mono_class_rgctx_get_array_size:
1152 * @n: The number of the array
1153 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1155 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1156 * number includes the slot for linking and - for MRGCTXs - the two
1157 * slots in the first array for additional information.
1160 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1162 g_assert (n >= 0 && n < 30);
1171 * LOCKING: domain lock
1174 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1176 static gboolean inited = FALSE;
1177 static int rgctx_num_alloced = 0;
1178 static int rgctx_bytes_alloced = 0;
1179 static int mrgctx_num_alloced = 0;
1180 static int mrgctx_bytes_alloced = 0;
1182 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1183 gpointer array = mono_domain_alloc0 (domain, size);
1186 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1187 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1188 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1189 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1194 mrgctx_num_alloced++;
1195 mrgctx_bytes_alloced += size;
1197 rgctx_num_alloced++;
1198 rgctx_bytes_alloced += size;
1205 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1206 MonoGenericInst *method_inst)
1209 int i, first_slot, size;
1210 MonoDomain *domain = class_vtable->domain;
1211 MonoClass *class = class_vtable->klass;
1212 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1213 MonoRuntimeGenericContextOtherInfoTemplate oti;
1214 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1220 mono_domain_lock (domain);
1222 /* First check whether that slot isn't already instantiated.
1223 This might happen because lookup doesn't lock. Allocate
1224 arrays on the way. */
1226 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1228 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1229 for (i = 0; ; ++i) {
1232 if (method_inst && i == 0)
1233 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1237 if (slot < first_slot + size - 1) {
1238 rgctx_index = slot - first_slot + 1 + offset;
1239 info = rgctx [rgctx_index];
1241 mono_domain_unlock (domain);
1246 if (!rgctx [offset + 0])
1247 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1248 rgctx = rgctx [offset + 0];
1249 first_slot += size - 1;
1250 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1253 g_assert (!rgctx [rgctx_index]);
1255 mono_domain_unlock (domain);
1257 oti = class_get_rgctx_template_oti (get_shared_class (class),
1258 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1259 /* This might take the loader lock */
1260 info = instantiate_other_info (domain, &oti, &context, class);
1264 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1267 /*FIXME We should use CAS here, no need to take a lock.*/
1268 mono_domain_lock (domain);
1270 /* Check whether the slot hasn't been instantiated in the
1272 if (rgctx [rgctx_index])
1273 info = rgctx [rgctx_index];
1275 rgctx [rgctx_index] = info;
1277 mono_domain_unlock (domain);
1280 free_inflated_info (oti.info_type, oti.data);
1286 * mono_class_fill_runtime_generic_context:
1287 * @class_vtable: a vtable
1288 * @slot: a slot index to be instantiated
1290 * Instantiates a slot in the RGCTX.
1293 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1295 static gboolean inited = FALSE;
1296 static int num_alloced = 0;
1298 MonoDomain *domain = class_vtable->domain;
1299 MonoRuntimeGenericContext *rgctx;
1302 mono_domain_lock (domain);
1305 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1309 rgctx = class_vtable->runtime_generic_context;
1311 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1312 class_vtable->runtime_generic_context = rgctx;
1316 mono_domain_unlock (domain);
1318 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1324 * mono_method_fill_runtime_generic_context:
1325 * @mrgctx: an MRGCTX
1326 * @slot: a slot index to be instantiated
1328 * Instantiates a slot in the MRGCTX.
1331 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1335 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1336 mrgctx->method_inst);
1342 mrgctx_hash_func (gconstpointer key)
1344 const MonoMethodRuntimeGenericContext *mrgctx = key;
1346 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1350 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1352 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1353 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1355 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1356 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1360 * mono_method_lookup_rgctx:
1361 * @class_vtable: a vtable
1362 * @method_inst: the method inst of a generic method
1364 * Returns the MRGCTX for the generic method(s) with the given
1365 * method_inst of the given class_vtable.
1367 * LOCKING: Take the domain lock.
1369 MonoMethodRuntimeGenericContext*
1370 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1372 MonoDomain *domain = class_vtable->domain;
1373 MonoMethodRuntimeGenericContext *mrgctx;
1374 MonoMethodRuntimeGenericContext key;
1376 g_assert (!class_vtable->klass->generic_container);
1377 g_assert (!method_inst->is_open);
1379 mono_domain_lock (domain);
1380 if (!domain->method_rgctx_hash)
1381 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1383 key.class_vtable = class_vtable;
1384 key.method_inst = method_inst;
1386 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1391 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1392 mrgctx->class_vtable = class_vtable;
1393 mrgctx->method_inst = method_inst;
1395 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1398 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1399 for (i = 0; i < method_inst->type_argc; ++i)
1400 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1405 mono_domain_unlock (domain);
1413 * mono_generic_context_is_sharable_full:
1414 * @context: a generic context
1416 * Returns whether the generic context is sharable. A generic context
1417 * is sharable iff all of its type arguments are reference type, or some of them have a
1418 * reference type, and ALLOW_PARTIAL is TRUE.
1421 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1422 gboolean allow_type_vars,
1423 gboolean allow_partial)
1425 g_assert (context->class_inst || context->method_inst);
1427 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1430 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1437 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1439 return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1443 * mono_method_is_generic_impl:
1446 * Returns whether the method is either generic or part of a generic
1450 mono_method_is_generic_impl (MonoMethod *method)
1452 if (method->is_inflated) {
1453 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1456 /* We don't treat wrappers as generic code, i.e., we never
1457 apply generic sharing to them. This is especially
1458 important for static rgctx invoke wrappers, which only work
1459 if not compiled with sharing. */
1460 if (method->wrapper_type != MONO_WRAPPER_NONE)
1462 if (method->klass->generic_container)
1468 has_constraints (MonoGenericContainer *container)
1474 g_assert (container->type_argc > 0);
1475 g_assert (container->type_params);
1477 for (i = 0; i < container->type_argc; ++i)
1478 if (container->type_params [i].constraints)
1485 * mono_method_is_generic_sharable_impl_full:
1487 * @allow_type_vars: whether to regard type variables as reference types
1488 * @alloc_partial: whether to allow partial sharing
1490 * Returns TRUE iff the method is inflated or part of an inflated
1491 * class, its context is sharable and it has no constraints on its
1492 * type parameters. Otherwise returns FALSE.
1495 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1496 gboolean allow_partial)
1498 if (!mono_method_is_generic_impl (method))
1501 if (method->is_inflated) {
1502 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1503 MonoGenericContext *context = &inflated->context;
1505 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1508 g_assert (inflated->declaring);
1510 if (inflated->declaring->is_generic) {
1511 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1516 if (method->klass->generic_class) {
1517 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1520 g_assert (method->klass->generic_class->container_class &&
1521 method->klass->generic_class->container_class->generic_container);
1523 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1527 if (method->klass->generic_container && !allow_type_vars)
1534 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1536 return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING);
1540 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1542 if (!mono_class_generic_sharing_enabled (method->klass))
1545 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1548 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1551 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1552 method->klass->valuetype) &&
1553 (method->klass->generic_class || method->klass->generic_container);
1556 static MonoGenericInst*
1557 get_object_generic_inst (int type_argc)
1559 MonoType **type_argv;
1562 type_argv = alloca (sizeof (MonoType*) * type_argc);
1564 for (i = 0; i < type_argc; ++i)
1565 type_argv [i] = &mono_defaults.object_class->byval_arg;
1567 return mono_metadata_get_generic_inst (type_argc, type_argv);
1571 * mono_method_construct_object_context:
1574 * Returns a generic context for method with all type variables for
1575 * class and method instantiated with Object.
1578 mono_method_construct_object_context (MonoMethod *method)
1580 MonoGenericContext object_context;
1582 g_assert (!method->klass->generic_class);
1583 if (method->klass->generic_container) {
1584 int type_argc = method->klass->generic_container->type_argc;
1586 object_context.class_inst = get_object_generic_inst (type_argc);
1588 object_context.class_inst = NULL;
1591 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1592 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1594 object_context.method_inst = get_object_generic_inst (type_argc);
1596 object_context.method_inst = NULL;
1599 g_assert (object_context.class_inst || object_context.method_inst);
1601 return object_context;
1604 static gboolean gshared_supported;
1607 mono_set_generic_sharing_supported (gboolean supported)
1609 gshared_supported = supported;
1613 * mono_class_generic_sharing_enabled:
1616 * Returns whether generic sharing is enabled for class.
1618 * This is a stop-gap measure to slowly introduce generic sharing
1619 * until we have all the issues sorted out, at which time this
1620 * function will disappear and generic sharing will always be enabled.
1623 mono_class_generic_sharing_enabled (MonoClass *class)
1625 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1626 static gboolean inited = FALSE;
1631 if (gshared_supported)
1632 generic_sharing = MONO_GENERIC_SHARING_ALL;
1634 generic_sharing = MONO_GENERIC_SHARING_NONE;
1636 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1637 if (strcmp (option, "corlib") == 0)
1638 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1639 else if (strcmp (option, "collections") == 0)
1640 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1641 else if (strcmp (option, "all") == 0)
1642 generic_sharing = MONO_GENERIC_SHARING_ALL;
1643 else if (strcmp (option, "none") == 0)
1644 generic_sharing = MONO_GENERIC_SHARING_NONE;
1646 g_warning ("Unknown generic sharing option `%s'.", option);
1649 if (!gshared_supported)
1650 generic_sharing = MONO_GENERIC_SHARING_NONE;
1655 switch (generic_sharing) {
1656 case MONO_GENERIC_SHARING_NONE:
1658 case MONO_GENERIC_SHARING_ALL:
1660 case MONO_GENERIC_SHARING_CORLIB :
1661 return class->image == mono_defaults.corlib;
1662 case MONO_GENERIC_SHARING_COLLECTIONS:
1663 if (class->image != mono_defaults.corlib)
1665 while (class->nested_in)
1666 class = class->nested_in;
1667 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1669 g_assert_not_reached ();
1675 * mono_get_generic_context_from_code:
1677 * Return the runtime generic context belonging to the method whose native code
1680 MonoGenericSharingContext*
1681 mono_get_generic_context_from_code (guint8 *code)
1683 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1685 g_assert (jit_info);
1687 return mono_jit_info_get_generic_sharing_context (jit_info);
1691 mini_method_get_context (MonoMethod *method)
1693 return mono_method_get_context_general (method, TRUE);
1697 * mono_method_check_context_used:
1700 * Checks whether the method's generic context uses a type variable.
1701 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1702 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1703 * context's class or method instantiation uses type variables.
1706 mono_method_check_context_used (MonoMethod *method)
1708 MonoGenericContext *method_context = mini_method_get_context (method);
1709 int context_used = 0;
1711 if (!method_context) {
1712 /* It might be a method of an array of an open generic type */
1713 if (method->klass->rank)
1714 context_used = mono_class_check_context_used (method->klass);
1716 context_used = mono_generic_context_check_used (method_context);
1717 context_used |= mono_class_check_context_used (method->klass);
1720 return context_used;
1724 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
1735 if (inst1->type_argc != inst2->type_argc)
1738 for (i = 0; i < inst1->type_argc; ++i)
1739 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
1746 * mono_generic_context_equal_deep:
1747 * @context1: a generic context
1748 * @context2: a generic context
1750 * Returns whether context1's type arguments are equal to context2's
1754 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
1756 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
1757 generic_inst_equal (context1->method_inst, context2->method_inst);
1761 * mini_class_get_container_class:
1762 * @class: a generic class
1764 * Returns the class's container class, which is the class itself if
1765 * it doesn't have generic_class set.
1768 mini_class_get_container_class (MonoClass *class)
1770 if (class->generic_class)
1771 return class->generic_class->container_class;
1773 g_assert (class->generic_container);
1778 * mini_class_get_context:
1779 * @class: a generic class
1781 * Returns the class's generic context.
1784 mini_class_get_context (MonoClass *class)
1786 if (class->generic_class)
1787 return &class->generic_class->context;
1789 g_assert (class->generic_container);
1790 return &class->generic_container->context;
1794 * mini_get_basic_type_from_generic:
1795 * @gsctx: a generic sharing context
1798 * Returns a closed type corresponding to the possibly open type
1802 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
1804 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1807 return mono_type_get_basic_type_from_generic (type);
1811 * mini_type_get_underlying_type:
1813 * Return the underlying type of TYPE, taking into account enums, byref and generic
1817 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
1820 return &mono_defaults.int_class->byval_arg;
1821 return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
1825 * mini_type_stack_size:
1826 * @gsctx: a generic sharing context
1828 * @align: Pointer to an int for returning the alignment
1830 * Returns the type's stack size and the alignment in *align. The
1831 * type is allowed to be open.
1834 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
1836 gboolean allow_open = TRUE;
1838 // FIXME: Some callers might not pass in a gsctx
1839 //allow_open = gsctx != NULL;
1840 return mono_type_stack_size_internal (t, align, allow_open);
1844 * mini_type_stack_size_full:
1846 * Same as mini_type_stack_size, but handle pinvoke data types as well.
1849 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
1854 size = mono_type_native_stack_size (t, align);
1859 size = mini_type_stack_size (gsctx, t, &ialign);
1862 size = mini_type_stack_size (gsctx, t, NULL);
1870 * mono_generic_sharing_init:
1872 * Register the generic sharing counters.
1875 mono_generic_sharing_init (void)
1877 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1881 mono_generic_sharing_cleanup (void)
1883 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1885 if (generic_subclass_hash)
1886 g_hash_table_destroy (generic_subclass_hash);
1890 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
1892 if (mono_type_is_reference (type))
1894 if (!cfg->generic_sharing_context)
1896 /*FIXME the probably needs better handle under partial sharing*/
1897 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;