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 #define DEBUG(...) __VA_ARGS__
28 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
30 static gboolean partial_supported = FALSE;
32 static inline gboolean
33 partial_sharing_supported (void)
35 if (!ALLOW_PARTIAL_SHARING)
37 /* Enable this when AOT compiling or running in full-aot mode */
40 if (partial_supported)
46 type_check_context_used (MonoType *type, gboolean recursive)
48 switch (mono_type_get_type (type)) {
50 return MONO_GENERIC_CONTEXT_USED_CLASS;
52 return MONO_GENERIC_CONTEXT_USED_METHOD;
53 case MONO_TYPE_SZARRAY:
54 return mono_class_check_context_used (mono_type_get_class (type));
56 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
59 return mono_class_check_context_used (mono_type_get_class (type));
62 case MONO_TYPE_GENERICINST:
64 MonoGenericClass *gclass = type->data.generic_class;
66 g_assert (gclass->container_class->generic_container);
67 return mono_generic_context_check_used (&gclass->context);
77 inst_check_context_used (MonoGenericInst *inst)
85 for (i = 0; i < inst->type_argc; ++i)
86 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
92 * mono_generic_context_check_used:
93 * @context: a generic context
95 * Checks whether the context uses a type variable. Returns an int
96 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
97 * the context's class instantiation uses type variables.
100 mono_generic_context_check_used (MonoGenericContext *context)
102 int context_used = 0;
104 context_used |= inst_check_context_used (context->class_inst);
105 context_used |= inst_check_context_used (context->method_inst);
111 * mono_class_check_context_used:
114 * Checks whether the class's generic context uses a type variable.
115 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
116 * reflect whether the context's class instantiation uses type
120 mono_class_check_context_used (MonoClass *klass)
122 int context_used = 0;
124 context_used |= type_check_context_used (&klass->this_arg, FALSE);
125 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
127 if (klass->generic_class)
128 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
129 else if (klass->generic_container)
130 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
136 * LOCKING: loader lock
138 static MonoRuntimeGenericContextInfoTemplate*
139 get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
141 g_assert (type_argc >= 0);
143 return template->infos;
144 return g_slist_nth_data (template->method_templates, type_argc - 1);
148 * LOCKING: loader lock
151 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
152 MonoRuntimeGenericContextInfoTemplate *oti)
154 g_assert (type_argc >= 0);
156 template->infos = oti;
158 int length = g_slist_length (template->method_templates);
161 /* FIXME: quadratic! */
162 while (length < type_argc) {
163 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
167 list = g_slist_nth (template->method_templates, type_argc - 1);
174 * LOCKING: loader lock
177 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
179 return g_slist_length (template->method_templates);
183 * LOCKING: loader lock
185 static MonoRuntimeGenericContextInfoTemplate*
186 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
189 MonoRuntimeGenericContextInfoTemplate *oti;
191 g_assert (slot >= 0);
193 for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
202 * LOCKING: loader lock
205 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
207 MonoRuntimeGenericContextInfoTemplate *oti;
210 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
216 /* Maps from uninstantiated generic classes to GList's of
217 * uninstantiated generic classes whose parent is the key class or an
218 * instance of the key class.
220 * LOCKING: loader lock
222 static GHashTable *generic_subclass_hash;
225 * LOCKING: templates lock
228 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
230 if (!klass->image->rgctx_template_hash)
231 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
233 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
237 * LOCKING: loader lock
239 static MonoRuntimeGenericContextTemplate*
240 class_lookup_rgctx_template (MonoClass *klass)
242 MonoRuntimeGenericContextTemplate *template;
244 if (!klass->image->rgctx_template_hash)
247 template = g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
253 * LOCKING: loader lock
256 register_generic_subclass (MonoClass *klass)
258 MonoClass *parent = klass->parent;
260 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
262 g_assert (rgctx_template);
264 if (parent->generic_class)
265 parent = parent->generic_class->container_class;
267 if (!generic_subclass_hash)
268 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
270 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
271 rgctx_template->next_subclass = subclass;
272 g_hash_table_insert (generic_subclass_hash, parent, klass);
276 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
280 if (klass->image == image) {
281 /* The parent class itself is in the image, so all the
282 subclasses must be in the image, too. If not,
283 we're removing an image containing a class which
284 still has a subclass in another image. */
287 g_assert (subclass->image == image);
288 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
296 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
297 MonoClass *next = subclass_template->next_subclass;
299 if (subclass->image != image) {
300 subclass_template->next_subclass = new_list;
308 g_hash_table_insert (generic_subclass_hash, klass, new_list);
312 * mono_class_unregister_image_generic_subclasses:
315 * Removes all classes of the image from the generic subclass hash.
316 * Must be called when an image is unloaded.
319 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
321 GHashTable *old_hash;
323 //g_print ("unregistering image %s\n", image->name);
325 if (!generic_subclass_hash)
330 old_hash = generic_subclass_hash;
331 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
333 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
335 mono_loader_unlock ();
337 g_hash_table_destroy (old_hash);
340 static MonoRuntimeGenericContextTemplate*
341 alloc_template (MonoClass *klass)
343 static gboolean inited = FALSE;
344 static int num_allocted = 0;
345 static int num_bytes = 0;
347 int size = sizeof (MonoRuntimeGenericContextTemplate);
350 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
351 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
358 return mono_image_alloc0 (klass->image, size);
361 static MonoRuntimeGenericContextInfoTemplate*
362 alloc_oti (MonoImage *image)
364 static gboolean inited = FALSE;
365 static int num_allocted = 0;
366 static int num_bytes = 0;
368 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
371 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
372 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
379 return mono_image_alloc0 (image, size);
382 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
385 * Return true if this info type has the notion of identify.
387 * Some info types expect that each insert results in a new slot been assigned.
390 info_has_identity (MonoRgctxInfoType info_type)
392 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
396 * LOCKING: loader lock
399 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
400 int slot, gpointer data, MonoRgctxInfoType info_type)
402 static gboolean inited = FALSE;
403 static int num_markers = 0;
404 static int num_data = 0;
407 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
408 MonoRuntimeGenericContextInfoTemplate **oti = &list;
411 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
412 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
416 g_assert (slot >= 0);
424 *oti = alloc_oti (image);
428 g_assert (!(*oti)->data);
430 (*oti)->info_type = info_type;
432 set_info_templates (image, template, type_argc, list);
434 if (data == MONO_RGCTX_SLOT_USED_MARKER)
441 * mono_method_get_declaring_generic_method:
442 * @method: an inflated method
444 * Returns an inflated method's declaring method.
447 mono_method_get_declaring_generic_method (MonoMethod *method)
449 MonoMethodInflated *inflated;
451 g_assert (method->is_inflated);
453 inflated = (MonoMethodInflated*)method;
455 return inflated->declaring;
459 * mono_class_get_method_generic:
463 * Given a class and a generic method, which has to be of an
464 * instantiation of the same class that klass is an instantiation of,
465 * returns the corresponding method in klass. Example:
467 * klass is Gen<string>
468 * method is Gen<object>.work<int>
470 * returns: Gen<string>.work<int>
473 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
475 MonoMethod *declaring, *m;
478 if (method->is_inflated)
479 declaring = mono_method_get_declaring_generic_method (method);
484 if (klass->generic_class)
485 m = mono_class_get_inflated_method (klass, declaring);
488 mono_class_setup_methods (klass);
489 if (klass->exception_type)
491 for (i = 0; i < klass->method.count; ++i) {
492 m = klass->methods [i];
495 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
498 if (i >= klass->method.count)
502 if (method != declaring) {
504 MonoGenericContext context;
506 context.class_inst = NULL;
507 context.method_inst = mono_method_get_context (method)->method_inst;
509 m = mono_class_inflate_generic_method_checked (m, &context, &error);
510 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
517 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
519 gpointer data = oti->data;
520 MonoRgctxInfoType info_type = oti->info_type;
525 if (data == MONO_RGCTX_SLOT_USED_MARKER)
526 return MONO_RGCTX_SLOT_USED_MARKER;
530 case MONO_RGCTX_INFO_STATIC_DATA:
531 case MONO_RGCTX_INFO_KLASS:
532 case MONO_RGCTX_INFO_ELEMENT_KLASS:
533 case MONO_RGCTX_INFO_VTABLE:
534 case MONO_RGCTX_INFO_TYPE:
535 case MONO_RGCTX_INFO_REFLECTION_TYPE:
536 case MONO_RGCTX_INFO_CAST_CACHE:
537 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
538 case MONO_RGCTX_INFO_VALUE_SIZE:
539 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
540 case MONO_RGCTX_INFO_MEMCPY:
541 case MONO_RGCTX_INFO_BZERO:
542 case MONO_RGCTX_INFO_LOCAL_OFFSET:
543 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
544 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
545 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
546 data, context, &error);
547 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
551 case MONO_RGCTX_INFO_METHOD:
552 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
553 case MONO_RGCTX_INFO_METHOD_RGCTX:
554 case MONO_RGCTX_INFO_METHOD_CONTEXT:
555 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
556 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
557 MonoMethod *method = data;
558 MonoMethod *inflated_method;
559 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
560 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
562 mono_metadata_free_type (inflated_type);
564 mono_class_init (inflated_class);
566 g_assert (!method->wrapper_type);
568 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
569 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
570 inflated_method = mono_method_search_in_array_class (inflated_class,
571 method->name, method->signature);
574 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
575 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
577 mono_class_init (inflated_method->klass);
578 g_assert (inflated_method->klass == inflated_class);
579 return inflated_method;
581 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
582 MonoGSharedVtMethodInfo *oinfo = data;
583 MonoGSharedVtMethodInfo *res;
584 MonoDomain *domain = mono_domain_get ();
587 res = mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
589 res->nlocals = info->nlocals;
590 res->locals_types = g_new0 (MonoType*, info->nlocals);
591 for (i = 0; i < info->nlocals; ++i)
592 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
594 res->num_entries = oinfo->num_entries;
595 res->entries = mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
596 for (i = 0; i < oinfo->num_entries; ++i) {
597 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
598 MonoRuntimeGenericContextInfoTemplate *template = &res->entries [i];
600 memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
601 template->data = inflate_info (template, context, klass, FALSE);
605 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
606 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
607 MonoJumpInfoGSharedVtCall *info = data;
608 MonoMethod *method = info->method;
609 MonoMethod *inflated_method;
610 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
611 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
612 MonoJumpInfoGSharedVtCall *res;
613 MonoDomain *domain = mono_domain_get ();
615 res = mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
616 /* Keep the original signature */
617 res->sig = info->sig;
619 mono_metadata_free_type (inflated_type);
621 mono_class_init (inflated_class);
623 g_assert (!method->wrapper_type);
625 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
626 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
627 inflated_method = mono_method_search_in_array_class (inflated_class,
628 method->name, method->signature);
631 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
632 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
634 mono_class_init (inflated_method->klass);
635 g_assert (inflated_method->klass == inflated_class);
636 res->method = inflated_method;
641 case MONO_RGCTX_INFO_CLASS_FIELD:
642 case MONO_RGCTX_INFO_FIELD_OFFSET: {
643 MonoClassField *field = data;
644 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
645 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
646 int i = field - field->parent->fields;
647 gpointer dummy = NULL;
649 mono_metadata_free_type (inflated_type);
651 mono_class_get_fields (inflated_class, &dummy);
652 g_assert (inflated_class->fields);
654 return &inflated_class->fields [i];
656 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
657 MonoMethodSignature *sig = data;
658 MonoMethodSignature *isig;
661 isig = mono_inflate_generic_signature (sig, context, &error);
662 g_assert (mono_error_ok (&error));
665 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
666 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
667 MonoJumpInfoVirtMethod *info = data;
668 MonoJumpInfoVirtMethod *res;
670 MonoDomain *domain = mono_domain_get ();
674 res = mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
675 t = mono_class_inflate_generic_type (&info->klass->byval_arg, context);
676 res->klass = mono_class_from_mono_type (t);
677 mono_metadata_free_type (t);
679 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
680 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
685 g_assert_not_reached ();
687 /* Not reached, quiet compiler */
692 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
698 case MONO_RGCTX_INFO_STATIC_DATA:
699 case MONO_RGCTX_INFO_KLASS:
700 case MONO_RGCTX_INFO_ELEMENT_KLASS:
701 case MONO_RGCTX_INFO_VTABLE:
702 case MONO_RGCTX_INFO_TYPE:
703 case MONO_RGCTX_INFO_REFLECTION_TYPE:
704 case MONO_RGCTX_INFO_CAST_CACHE:
705 mono_metadata_free_type (info);
712 static MonoRuntimeGenericContextInfoTemplate
713 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
716 class_uninstantiated (MonoClass *klass)
718 if (klass->generic_class)
719 return klass->generic_class->container_class;
726 * Return the class used to store information when using generic sharing.
729 get_shared_class (MonoClass *klass)
731 return class_uninstantiated (klass);
735 * mono_class_get_runtime_generic_context_template:
738 * Looks up or constructs, if necessary, the runtime generic context template for class.
739 * The template is the same for all instantiations of a class.
741 static MonoRuntimeGenericContextTemplate*
742 mono_class_get_runtime_generic_context_template (MonoClass *klass)
744 MonoRuntimeGenericContextTemplate *parent_template, *template;
747 klass = get_shared_class (klass);
750 template = class_lookup_rgctx_template (klass);
751 mono_loader_unlock ();
756 //g_assert (get_shared_class (class) == class);
758 template = alloc_template (klass);
764 int max_argc, type_argc;
766 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
767 max_argc = template_get_max_argc (parent_template);
769 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
770 num_entries = rgctx_template_num_infos (parent_template, type_argc);
772 /* FIXME: quadratic! */
773 for (i = 0; i < num_entries; ++i) {
774 MonoRuntimeGenericContextInfoTemplate oti;
776 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
777 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
778 rgctx_template_set_slot (klass->image, template, type_argc, i,
779 oti.data, oti.info_type);
785 if (class_lookup_rgctx_template (klass)) {
786 /* some other thread already set the template */
787 template = class_lookup_rgctx_template (klass);
789 class_set_rgctx_template (klass, template);
792 register_generic_subclass (klass);
795 mono_loader_unlock ();
801 * class_get_rgctx_template_oti:
803 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
804 * temporary signifies whether the inflated info (oti.data) will be
805 * used temporarily, in which case it might be heap-allocated, or
806 * permanently, in which case it will be mempool-allocated. If
807 * temporary is set then *do_free will return whether the returned
808 * data must be freed.
810 * LOCKING: loader lock
812 static MonoRuntimeGenericContextInfoTemplate
813 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
815 g_assert ((temporary && do_free) || (!temporary && !do_free));
817 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
819 if (klass->generic_class && !shared) {
820 MonoRuntimeGenericContextInfoTemplate oti;
821 gboolean tmp_do_free;
823 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
824 type_argc, slot, TRUE, FALSE, &tmp_do_free);
826 gpointer info = oti.data;
827 oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
829 free_inflated_info (oti.info_type, info);
836 MonoRuntimeGenericContextTemplate *template;
837 MonoRuntimeGenericContextInfoTemplate *oti;
839 template = mono_class_get_runtime_generic_context_template (klass);
840 oti = rgctx_template_get_other_slot (template, type_argc, slot);
851 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type)
854 case MONO_RGCTX_INFO_STATIC_DATA: {
855 MonoVTable *vtable = mono_class_vtable (domain, klass);
857 mono_raise_exception (mono_class_get_exception_for_failure (klass));
858 return mono_vtable_get_static_field_data (vtable);
860 case MONO_RGCTX_INFO_KLASS:
862 case MONO_RGCTX_INFO_ELEMENT_KLASS:
863 return klass->element_class;
864 case MONO_RGCTX_INFO_VTABLE: {
865 MonoVTable *vtable = mono_class_vtable (domain, klass);
867 mono_raise_exception (mono_class_get_exception_for_failure (klass));
870 case MONO_RGCTX_INFO_CAST_CACHE: {
871 /*First slot is the cache itself, the second the vtable.*/
872 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
873 cache_data [1] = (gpointer)klass;
876 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
877 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
878 case MONO_RGCTX_INFO_VALUE_SIZE:
879 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
880 return GUINT_TO_POINTER (sizeof (gpointer));
882 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
883 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
884 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
885 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
886 else if (mono_class_is_nullable (klass))
887 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
889 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
890 case MONO_RGCTX_INFO_MEMCPY:
891 case MONO_RGCTX_INFO_BZERO: {
892 static MonoMethod *memcpy_method [17];
893 static MonoMethod *bzero_method [17];
894 MonoJitDomainInfo *domain_info;
898 domain_info = domain_jit_info (domain);
900 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
901 size = sizeof (gpointer);
902 align = sizeof (gpointer);
904 size = mono_class_value_size (klass, &align);
907 if (size != 1 && size != 2 && size != 4 && size != 8)
912 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
913 if (!memcpy_method [size]) {
918 sprintf (name, "memcpy");
920 sprintf (name, "memcpy_aligned_%d", size);
921 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
923 mono_memory_barrier ();
924 memcpy_method [size] = m;
926 if (!domain_info->memcpy_addr [size]) {
927 gpointer addr = mono_compile_method (memcpy_method [size]);
928 mono_memory_barrier ();
929 domain_info->memcpy_addr [size] = addr;
931 return domain_info->memcpy_addr [size];
933 if (!bzero_method [size]) {
938 sprintf (name, "bzero");
940 sprintf (name, "bzero_aligned_%d", size);
941 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
943 mono_memory_barrier ();
944 bzero_method [size] = m;
946 if (!domain_info->bzero_addr [size]) {
947 gpointer addr = mono_compile_method (bzero_method [size]);
948 mono_memory_barrier ();
949 domain_info->bzero_addr [size] = addr;
951 return domain_info->bzero_addr [size];
954 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
955 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
960 if (!mono_class_is_nullable (klass))
961 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
964 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
965 method = mono_class_get_method_from_name (klass, "Box", 1);
967 method = mono_class_get_method_from_name (klass, "Unbox", 1);
969 addr = mono_compile_method (method);
970 // The caller uses the gsharedvt call signature
971 ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
973 if (mini_jit_info_is_gsharedvt (ji))
974 return mono_create_static_rgctx_trampoline (method, addr);
976 MonoMethodSignature *sig, *gsig;
979 /* Need to add an out wrapper */
981 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
982 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
983 sig = mono_method_signature (method);
984 gsig = mono_method_signature (gmethod);
986 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
987 addr = mono_create_static_rgctx_trampoline (method, addr);
992 g_assert_not_reached ();
999 ji_is_gsharedvt (MonoJitInfo *ji)
1001 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1008 * Describes the information used to construct a gsharedvt arg trampoline.
1013 gint32 vcall_offset;
1015 MonoMethodSignature *sig, *gsig;
1016 } GSharedVtTrampInfo;
1019 tramp_info_hash (gconstpointer key)
1021 GSharedVtTrampInfo *tramp = (gpointer)key;
1023 return (gsize)tramp->addr;
1027 tramp_info_equal (gconstpointer a, gconstpointer b)
1029 GSharedVtTrampInfo *tramp1 = (gpointer)a;
1030 GSharedVtTrampInfo *tramp2 = (gpointer)b;
1032 /* The signatures should be internalized */
1033 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1034 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1038 * mini_get_gsharedvt_wrapper:
1040 * Return a gsharedvt in/out wrapper for calling ADDR.
1043 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1045 static gboolean inited = FALSE;
1046 static int num_trampolines;
1048 MonoDomain *domain = mono_domain_get ();
1049 MonoJitDomainInfo *domain_info;
1050 GSharedVtTrampInfo *tramp_info;
1051 GSharedVtTrampInfo tinfo;
1054 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1058 memset (&tinfo, 0, sizeof (tinfo));
1059 tinfo.is_in = gsharedvt_in;
1060 tinfo.calli = calli;
1061 tinfo.vcall_offset = vcall_offset;
1063 tinfo.sig = normal_sig;
1064 tinfo.gsig = gsharedvt_sig;
1066 domain_info = domain_jit_info (domain);
1069 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1071 mono_domain_lock (domain);
1072 if (!domain_info->gsharedvt_arg_tramp_hash)
1073 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1074 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1075 mono_domain_unlock (domain);
1079 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1082 static gpointer tramp_addr;
1083 MonoMethod *wrapper;
1086 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1087 addr = mono_compile_method (wrapper);
1088 mono_memory_barrier ();
1093 static gpointer tramp_addr;
1094 MonoMethod *wrapper;
1097 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1098 addr = mono_compile_method (wrapper);
1099 mono_memory_barrier ();
1106 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1108 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1113 tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1114 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1116 mono_domain_lock (domain);
1117 /* Duplicates are not a problem */
1118 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1119 mono_domain_unlock (domain);
1125 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1126 MonoGenericContext *context, MonoClass *klass)
1134 switch (oti->info_type) {
1135 case MONO_RGCTX_INFO_STATIC_DATA:
1136 case MONO_RGCTX_INFO_KLASS:
1137 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1138 case MONO_RGCTX_INFO_VTABLE:
1139 case MONO_RGCTX_INFO_CAST_CACHE:
1146 data = inflate_info (oti, context, klass, temporary);
1148 switch (oti->info_type) {
1149 case MONO_RGCTX_INFO_STATIC_DATA:
1150 case MONO_RGCTX_INFO_KLASS:
1151 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1152 case MONO_RGCTX_INFO_VTABLE:
1153 case MONO_RGCTX_INFO_CAST_CACHE:
1154 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1155 case MONO_RGCTX_INFO_VALUE_SIZE:
1156 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1157 case MONO_RGCTX_INFO_MEMCPY:
1158 case MONO_RGCTX_INFO_BZERO:
1159 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1160 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1161 MonoClass *arg_class = mono_class_from_mono_type (data);
1163 free_inflated_info (oti->info_type, data);
1164 g_assert (arg_class);
1166 /* The class might be used as an argument to
1167 mono_value_copy(), which requires that its GC
1168 descriptor has been computed. */
1169 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1170 mono_class_compute_gc_descriptor (arg_class);
1172 return class_type_info (domain, arg_class, oti->info_type);
1174 case MONO_RGCTX_INFO_TYPE:
1176 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1177 return mono_type_get_object (domain, data);
1178 case MONO_RGCTX_INFO_METHOD:
1180 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1183 addr = mono_compile_method (data);
1184 return mini_add_method_trampoline (data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1186 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1187 MonoJumpInfoVirtMethod *info = data;
1188 MonoClass *iface_class = info->method->klass;
1194 mono_class_setup_vtable (info->klass);
1195 // FIXME: Check type load
1196 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1197 ioffset = mono_class_interface_offset (info->klass, iface_class);
1198 g_assert (ioffset != -1);
1202 slot = mono_method_get_vtable_slot (info->method);
1203 g_assert (slot != -1);
1204 g_assert (info->klass->vtable);
1205 method = info->klass->vtable [ioffset + slot];
1207 method = mono_class_inflate_generic_method_checked (method, context, &error);
1209 addr = mono_compile_method (method);
1210 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1212 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1213 MonoJumpInfoVirtMethod *info = data;
1214 MonoClass *iface_class = info->method->klass;
1216 MonoClass *impl_class;
1219 mono_class_setup_vtable (info->klass);
1220 // FIXME: Check type load
1221 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1222 ioffset = mono_class_interface_offset (info->klass, iface_class);
1223 g_assert (ioffset != -1);
1227 slot = mono_method_get_vtable_slot (info->method);
1228 g_assert (slot != -1);
1229 g_assert (info->klass->vtable);
1230 method = info->klass->vtable [ioffset + slot];
1232 impl_class = method->klass;
1233 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1234 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1235 else if (mono_class_is_nullable (impl_class))
1236 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1238 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1240 #ifndef DISABLE_REMOTING
1241 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1242 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1244 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1245 return mono_domain_alloc0 (domain, sizeof (gpointer));
1246 case MONO_RGCTX_INFO_CLASS_FIELD:
1248 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1249 MonoClassField *field = data;
1251 /* The value is offset by 1 */
1252 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1253 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1255 return GUINT_TO_POINTER (field->offset + 1);
1257 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1258 MonoMethodInflated *method = data;
1261 g_assert (method->method.method.is_inflated);
1262 g_assert (method->context.method_inst);
1264 vtable = mono_class_vtable (domain, method->method.method.klass);
1266 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1268 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1270 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1271 MonoMethodInflated *method = data;
1273 g_assert (method->method.method.is_inflated);
1274 g_assert (method->context.method_inst);
1276 return method->context.method_inst;
1278 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1279 MonoMethodSignature *gsig = oti->data;
1280 MonoMethodSignature *sig = data;
1284 * This is an indirect call to the address passed by the caller in the rgctx reg.
1286 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1289 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1290 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1291 MonoJumpInfoGSharedVtCall *call_info = data;
1292 MonoMethodSignature *call_sig;
1295 MonoJitInfo *callee_ji;
1296 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1297 gint32 vcall_offset;
1298 gboolean callee_gsharedvt;
1300 /* This is the original generic signature used by the caller */
1301 call_sig = call_info->sig;
1302 /* This is the instantiated method which is called */
1303 method = call_info->method;
1305 g_assert (method->is_inflated);
1308 addr = mono_compile_method (method);
1313 /* Same as in mono_emit_method_call_full () */
1314 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1315 /* See mono_emit_method_call_full () */
1316 /* The gsharedvt trampoline will recognize this constant */
1317 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1318 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1319 guint32 imt_slot = mono_method_get_imt_slot (method);
1320 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1322 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1323 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1329 // FIXME: This loads information in the AOT case
1330 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1331 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1334 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1335 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1336 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1337 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1338 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1339 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1340 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1341 * caller -> out trampoline -> in trampoline -> callee
1342 * This is not very efficient, but it is easy to implement.
1344 if (virtual || !callee_gsharedvt) {
1345 MonoMethodSignature *sig, *gsig;
1347 g_assert (method->is_inflated);
1349 sig = mono_method_signature (method);
1352 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1355 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1357 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1359 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1360 } else if (callee_gsharedvt) {
1361 MonoMethodSignature *sig, *gsig;
1364 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1365 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1368 * public void foo<T1> (T1 t1, T t, object o) {}
1370 * class AClass : Base<long> {
1371 * public void bar<T> (T t, long time, object o) {
1375 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1376 * FIXME: Optimize this.
1379 if (call_sig == mono_method_signature (method)) {
1381 sig = mono_method_signature (method);
1382 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1384 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1386 sig = mono_method_signature (method);
1389 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1391 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1397 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1398 MonoGSharedVtMethodInfo *info = data;
1399 MonoGSharedVtMethodRuntimeInfo *res;
1401 int i, offset, align, size;
1404 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1407 for (i = 0; i < info->num_entries; ++i) {
1408 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1410 switch (template->info_type) {
1411 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1414 size = mono_type_size (t, &align);
1416 if (align < sizeof (gpointer))
1417 align = sizeof (gpointer);
1418 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1419 align = 2 * sizeof (gpointer);
1421 // FIXME: Do the same things as alloc_stack_slots
1422 offset += align - 1;
1423 offset &= ~(align - 1);
1424 res->entries [i] = GINT_TO_POINTER (offset);
1428 res->entries [i] = instantiate_info (domain, template, context, klass);
1432 res->locals_size = offset;
1437 g_assert_not_reached ();
1444 * LOCKING: loader lock
1447 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1449 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (klass);
1450 MonoClass *subclass;
1452 rgctx_template_set_slot (klass->image, template, type_argc, index, data, info_type);
1454 /* Recurse for all subclasses */
1455 if (generic_subclass_hash)
1456 subclass = g_hash_table_lookup (generic_subclass_hash, klass);
1461 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1462 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1464 g_assert (subclass_template);
1466 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1467 g_assert (subclass_oti.data);
1469 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1471 subclass = subclass_template->next_subclass;
1476 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1479 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1480 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1481 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1482 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1483 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1484 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1485 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1486 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1487 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1488 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1489 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1490 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1491 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1492 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1493 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1494 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1495 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1496 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1497 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1498 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1499 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1500 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1501 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1502 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1503 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1504 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1505 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1506 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1508 return "<UNKNOWN RGCTX INFO TYPE>";
1512 G_GNUC_UNUSED static char*
1513 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1515 switch (info_type) {
1516 case MONO_RGCTX_INFO_VTABLE:
1517 return mono_type_full_name ((MonoType*)data);
1519 return g_strdup_printf ("<%p>", data);
1524 * LOCKING: loader lock
1527 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1530 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (klass);
1532 MonoRuntimeGenericContextInfoTemplate *oti;
1534 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1539 DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, mono_rgctx_info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));
1541 /* Mark the slot as used in all parent classes (until we find
1542 a parent class which already has it marked used). */
1543 parent = klass->parent;
1544 while (parent != NULL) {
1545 MonoRuntimeGenericContextTemplate *parent_template;
1546 MonoRuntimeGenericContextInfoTemplate *oti;
1548 if (parent->generic_class)
1549 parent = parent->generic_class->container_class;
1551 parent_template = mono_class_get_runtime_generic_context_template (parent);
1552 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1554 if (oti && oti->data)
1557 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1558 MONO_RGCTX_SLOT_USED_MARKER, 0);
1560 parent = parent->parent;
1563 /* Fill in the slot in this class and in all subclasses
1565 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
1571 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1573 switch (info_type) {
1574 case MONO_RGCTX_INFO_STATIC_DATA:
1575 case MONO_RGCTX_INFO_KLASS:
1576 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1577 case MONO_RGCTX_INFO_VTABLE:
1578 case MONO_RGCTX_INFO_TYPE:
1579 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1580 case MONO_RGCTX_INFO_CAST_CACHE:
1581 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1582 case MONO_RGCTX_INFO_VALUE_SIZE:
1583 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1584 case MONO_RGCTX_INFO_MEMCPY:
1585 case MONO_RGCTX_INFO_BZERO:
1586 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1587 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1588 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1589 case MONO_RGCTX_INFO_METHOD:
1590 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1591 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1592 case MONO_RGCTX_INFO_CLASS_FIELD:
1593 case MONO_RGCTX_INFO_FIELD_OFFSET:
1594 case MONO_RGCTX_INFO_METHOD_RGCTX:
1595 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1596 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1597 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1598 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1599 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1600 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1601 return data1 == data2;
1602 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
1603 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1604 MonoJumpInfoVirtMethod *info1 = data1;
1605 MonoJumpInfoVirtMethod *info2 = data2;
1607 return info1->klass == info2->klass && info1->method == info2->method;
1610 g_assert_not_reached ();
1617 * mini_rgctx_info_type_to_patch_info_type:
1619 * Return the type of the runtime object referred to by INFO_TYPE.
1622 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1624 switch (info_type) {
1625 case MONO_RGCTX_INFO_STATIC_DATA:
1626 case MONO_RGCTX_INFO_KLASS:
1627 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1628 case MONO_RGCTX_INFO_VTABLE:
1629 case MONO_RGCTX_INFO_TYPE:
1630 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1631 case MONO_RGCTX_INFO_CAST_CACHE:
1632 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1633 case MONO_RGCTX_INFO_VALUE_SIZE:
1634 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1635 case MONO_RGCTX_INFO_MEMCPY:
1636 case MONO_RGCTX_INFO_BZERO:
1637 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1638 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1639 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1640 return MONO_PATCH_INFO_CLASS;
1641 case MONO_RGCTX_INFO_FIELD_OFFSET:
1642 return MONO_PATCH_INFO_FIELD;
1644 g_assert_not_reached ();
1650 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1651 MonoGenericContext *generic_context)
1653 static gboolean inited = FALSE;
1654 static int max_slot = 0;
1656 MonoRuntimeGenericContextTemplate *rgctx_template =
1657 mono_class_get_runtime_generic_context_template (klass);
1658 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1661 klass = get_shared_class (klass);
1663 mono_loader_lock ();
1665 if (info_has_identity (info_type)) {
1666 oti_list = get_info_templates (rgctx_template, type_argc);
1668 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1669 gpointer inflated_data;
1671 if (oti->info_type != info_type || !oti->data)
1674 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
1676 if (info_equal (data, inflated_data, info_type)) {
1677 free_inflated_info (info_type, inflated_data);
1678 mono_loader_unlock ();
1681 free_inflated_info (info_type, inflated_data);
1685 /* We haven't found the info */
1686 i = register_info (klass, type_argc, data, info_type);
1688 mono_loader_unlock ();
1691 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1701 * mono_method_lookup_or_register_info:
1703 * @in_mrgctx: whether to put the data into the MRGCTX
1704 * @data: the info data
1705 * @info_type: the type of info to register about data
1706 * @generic_context: a generic context
1708 * Looks up and, if necessary, adds information about data/info_type in
1709 * method's or method's class runtime generic context. Returns the
1710 * encoded slot number.
1713 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1714 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1716 MonoClass *klass = method->klass;
1717 int type_argc, index;
1720 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1722 g_assert (method->is_inflated && method_inst);
1723 type_argc = method_inst->type_argc;
1724 g_assert (type_argc > 0);
1729 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
1731 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1734 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1736 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1740 * mono_class_rgctx_get_array_size:
1741 * @n: The number of the array
1742 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1744 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1745 * number includes the slot for linking and - for MRGCTXs - the two
1746 * slots in the first array for additional information.
1749 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1751 g_assert (n >= 0 && n < 30);
1760 * LOCKING: domain lock
1763 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1765 static gboolean inited = FALSE;
1766 static int rgctx_num_alloced = 0;
1767 static int rgctx_bytes_alloced = 0;
1768 static int mrgctx_num_alloced = 0;
1769 static int mrgctx_bytes_alloced = 0;
1771 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1772 gpointer array = mono_domain_alloc0 (domain, size);
1775 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1776 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1777 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1778 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1783 mrgctx_num_alloced++;
1784 mrgctx_bytes_alloced += size;
1786 rgctx_num_alloced++;
1787 rgctx_bytes_alloced += size;
1794 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1795 MonoGenericInst *method_inst)
1798 int i, first_slot, size;
1799 MonoDomain *domain = class_vtable->domain;
1800 MonoClass *klass = class_vtable->klass;
1801 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
1802 MonoRuntimeGenericContextInfoTemplate oti;
1803 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1809 mono_domain_lock (domain);
1811 /* First check whether that slot isn't already instantiated.
1812 This might happen because lookup doesn't lock. Allocate
1813 arrays on the way. */
1815 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1817 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1818 for (i = 0; ; ++i) {
1821 if (method_inst && i == 0)
1822 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1826 if (slot < first_slot + size - 1) {
1827 rgctx_index = slot - first_slot + 1 + offset;
1828 info = rgctx [rgctx_index];
1830 mono_domain_unlock (domain);
1835 if (!rgctx [offset + 0])
1836 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1837 rgctx = rgctx [offset + 0];
1838 first_slot += size - 1;
1839 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1842 g_assert (!rgctx [rgctx_index]);
1844 mono_domain_unlock (domain);
1846 oti = class_get_rgctx_template_oti (get_shared_class (klass),
1847 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1848 /* This might take the loader lock */
1849 info = instantiate_info (domain, &oti, &context, klass);
1854 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1857 /*FIXME We should use CAS here, no need to take a lock.*/
1858 mono_domain_lock (domain);
1860 /* Check whether the slot hasn't been instantiated in the
1862 if (rgctx [rgctx_index])
1863 info = rgctx [rgctx_index];
1865 rgctx [rgctx_index] = info;
1867 mono_domain_unlock (domain);
1870 free_inflated_info (oti.info_type, oti.data);
1876 * mono_class_fill_runtime_generic_context:
1877 * @class_vtable: a vtable
1878 * @slot: a slot index to be instantiated
1880 * Instantiates a slot in the RGCTX, returning its value.
1883 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1885 static gboolean inited = FALSE;
1886 static int num_alloced = 0;
1888 MonoDomain *domain = class_vtable->domain;
1889 MonoRuntimeGenericContext *rgctx;
1892 mono_domain_lock (domain);
1895 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1899 rgctx = class_vtable->runtime_generic_context;
1901 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1902 class_vtable->runtime_generic_context = rgctx;
1906 mono_domain_unlock (domain);
1908 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1910 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1916 * mono_method_fill_runtime_generic_context:
1917 * @mrgctx: an MRGCTX
1918 * @slot: a slot index to be instantiated
1920 * Instantiates a slot in the MRGCTX.
1923 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1927 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst);
1933 mrgctx_hash_func (gconstpointer key)
1935 const MonoMethodRuntimeGenericContext *mrgctx = key;
1937 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1941 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1943 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1944 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1946 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1947 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1951 * mono_method_lookup_rgctx:
1952 * @class_vtable: a vtable
1953 * @method_inst: the method inst of a generic method
1955 * Returns the MRGCTX for the generic method(s) with the given
1956 * method_inst of the given class_vtable.
1958 * LOCKING: Take the domain lock.
1960 MonoMethodRuntimeGenericContext*
1961 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1963 MonoDomain *domain = class_vtable->domain;
1964 MonoMethodRuntimeGenericContext *mrgctx;
1965 MonoMethodRuntimeGenericContext key;
1967 g_assert (!class_vtable->klass->generic_container);
1968 g_assert (!method_inst->is_open);
1970 mono_domain_lock (domain);
1971 if (!domain->method_rgctx_hash)
1972 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1974 key.class_vtable = class_vtable;
1975 key.method_inst = method_inst;
1977 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1982 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1983 mrgctx->class_vtable = class_vtable;
1984 mrgctx->method_inst = method_inst;
1986 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1989 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1990 for (i = 0; i < method_inst->type_argc; ++i)
1991 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1996 mono_domain_unlock (domain);
2005 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2006 gboolean allow_partial);
2009 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2011 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2012 MonoType *constraint = type->data.generic_param->gshared_constraint;
2018 if (MONO_TYPE_IS_REFERENCE (type))
2021 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2022 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) || (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)))
2025 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2026 MonoGenericClass *gclass = type->data.generic_class;
2028 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2030 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2032 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2041 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2042 gboolean allow_partial)
2046 for (i = 0; i < inst->type_argc; ++i) {
2047 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2055 * mono_is_partially_sharable_inst:
2057 * Return TRUE if INST has ref and non-ref type arguments.
2060 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2063 gboolean has_refs = FALSE, has_non_refs = FALSE;
2065 for (i = 0; i < inst->type_argc; ++i) {
2066 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)
2069 has_non_refs = TRUE;
2072 return has_refs && has_non_refs;
2076 * mono_generic_context_is_sharable_full:
2077 * @context: a generic context
2079 * Returns whether the generic context is sharable. A generic context
2080 * is sharable iff all of its type arguments are reference type, or some of them have a
2081 * reference type, and ALLOW_PARTIAL is TRUE.
2084 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2085 gboolean allow_type_vars,
2086 gboolean allow_partial)
2088 g_assert (context->class_inst || context->method_inst);
2090 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2093 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2100 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2102 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2106 * mono_method_is_generic_impl:
2109 * Returns whether the method is either generic or part of a generic
2113 mono_method_is_generic_impl (MonoMethod *method)
2115 if (method->is_inflated)
2117 /* We don't treat wrappers as generic code, i.e., we never
2118 apply generic sharing to them. This is especially
2119 important for static rgctx invoke wrappers, which only work
2120 if not compiled with sharing. */
2121 if (method->wrapper_type != MONO_WRAPPER_NONE)
2123 if (method->klass->generic_container)
2129 has_constraints (MonoGenericContainer *container)
2135 g_assert (container->type_argc > 0);
2136 g_assert (container->type_params);
2138 for (i = 0; i < container->type_argc; ++i)
2139 if (container->type_params [i].constraints)
2146 mini_method_is_open (MonoMethod *method)
2148 if (method->is_inflated) {
2149 MonoGenericContext *ctx = mono_method_get_context (method);
2151 if (ctx->class_inst && ctx->class_inst->is_open)
2153 if (ctx->method_inst && ctx->method_inst->is_open)
2159 static G_GNUC_UNUSED gboolean
2160 is_async_state_machine_class (MonoClass *klass)
2162 static MonoClass *iclass;
2163 static gboolean iclass_set;
2168 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2169 mono_memory_barrier ();
2173 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2178 static G_GNUC_UNUSED gboolean
2179 is_async_method (MonoMethod *method)
2181 MonoCustomAttrInfo *cattr;
2182 MonoMethodSignature *sig;
2183 gboolean res = FALSE;
2184 static MonoClass *attr_class;
2185 static gboolean attr_class_set;
2189 if (!attr_class_set) {
2190 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2191 mono_memory_barrier ();
2192 attr_class_set = TRUE;
2195 /* Do less expensive checks first */
2196 sig = mono_method_signature (method);
2197 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2198 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2199 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2200 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2201 cattr = mono_custom_attrs_from_method (method);
2203 if (mono_custom_attrs_has_attr (cattr, attr_class))
2205 mono_custom_attrs_free (cattr);
2212 * mono_method_is_generic_sharable_full:
2214 * @allow_type_vars: whether to regard type variables as reference types
2215 * @allow_partial: whether to allow partial sharing
2216 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2218 * Returns TRUE iff the method is inflated or part of an inflated
2219 * class, its context is sharable and it has no constraints on its
2220 * type parameters. Otherwise returns FALSE.
2223 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2224 gboolean allow_partial, gboolean allow_gsharedvt)
2226 if (!mono_method_is_generic_impl (method))
2230 if (!mono_debug_count ())
2231 allow_partial = FALSE;
2234 if (!partial_sharing_supported ())
2235 allow_partial = FALSE;
2237 if (mono_class_is_nullable (method->klass))
2239 allow_partial = FALSE;
2241 if (method->klass->image->dynamic)
2243 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2244 * instance_size is 0.
2246 allow_partial = FALSE;
2249 * Generic async methods have an associated state machine class which is a generic struct. This struct
2250 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2251 * of the async method and the state machine class.
2253 if (is_async_state_machine_class (method->klass))
2256 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2257 if (is_async_method (method))
2262 if (method->is_inflated) {
2263 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2264 MonoGenericContext *context = &inflated->context;
2266 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2269 g_assert (inflated->declaring);
2271 if (inflated->declaring->is_generic) {
2272 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2277 if (method->klass->generic_class) {
2278 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2281 g_assert (method->klass->generic_class->container_class &&
2282 method->klass->generic_class->container_class->generic_container);
2284 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2288 if (method->klass->generic_container && !allow_type_vars)
2291 /* This does potentially expensive cattr checks, so do it at the end */
2292 if (is_async_method (method)) {
2293 if (mini_method_is_open (method))
2294 /* The JIT can't compile these without sharing */
2303 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2305 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2309 * mono_method_needs_static_rgctx_invoke:
2311 * Return whenever METHOD needs an rgctx argument.
2312 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2313 * have a this argument which can be used to load the rgctx.
2316 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2318 if (!mono_class_generic_sharing_enabled (method->klass))
2321 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2324 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2327 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2328 method->klass->valuetype) &&
2329 (method->klass->generic_class || method->klass->generic_container);
2332 static MonoGenericInst*
2333 get_object_generic_inst (int type_argc)
2335 MonoType **type_argv;
2338 type_argv = alloca (sizeof (MonoType*) * type_argc);
2340 for (i = 0; i < type_argc; ++i)
2341 type_argv [i] = &mono_defaults.object_class->byval_arg;
2343 return mono_metadata_get_generic_inst (type_argc, type_argv);
2347 * mono_method_construct_object_context:
2350 * Returns a generic context for method with all type variables for
2351 * class and method instantiated with Object.
2354 mono_method_construct_object_context (MonoMethod *method)
2356 MonoGenericContext object_context;
2358 g_assert (!method->klass->generic_class);
2359 if (method->klass->generic_container) {
2360 int type_argc = method->klass->generic_container->type_argc;
2362 object_context.class_inst = get_object_generic_inst (type_argc);
2364 object_context.class_inst = NULL;
2367 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2368 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2370 object_context.method_inst = get_object_generic_inst (type_argc);
2372 object_context.method_inst = NULL;
2375 g_assert (object_context.class_inst || object_context.method_inst);
2377 return object_context;
2380 static gboolean gshared_supported;
2381 static gboolean gsharedvt_supported;
2384 mono_set_generic_sharing_supported (gboolean supported)
2386 gshared_supported = supported;
2390 mono_set_generic_sharing_vt_supported (gboolean supported)
2392 gsharedvt_supported = supported;
2396 mono_set_partial_sharing_supported (gboolean supported)
2398 partial_supported = supported;
2402 * mono_class_generic_sharing_enabled:
2405 * Returns whether generic sharing is enabled for class.
2407 * This is a stop-gap measure to slowly introduce generic sharing
2408 * until we have all the issues sorted out, at which time this
2409 * function will disappear and generic sharing will always be enabled.
2412 mono_class_generic_sharing_enabled (MonoClass *klass)
2414 if (gshared_supported)
2421 mini_method_get_context (MonoMethod *method)
2423 return mono_method_get_context_general (method, TRUE);
2427 * mono_method_check_context_used:
2430 * Checks whether the method's generic context uses a type variable.
2431 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2432 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2433 * context's class or method instantiation uses type variables.
2436 mono_method_check_context_used (MonoMethod *method)
2438 MonoGenericContext *method_context = mini_method_get_context (method);
2439 int context_used = 0;
2441 if (!method_context) {
2442 /* It might be a method of an array of an open generic type */
2443 if (method->klass->rank)
2444 context_used = mono_class_check_context_used (method->klass);
2446 context_used = mono_generic_context_check_used (method_context);
2447 context_used |= mono_class_check_context_used (method->klass);
2450 return context_used;
2454 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2465 if (inst1->type_argc != inst2->type_argc)
2468 for (i = 0; i < inst1->type_argc; ++i)
2469 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2476 * mono_generic_context_equal_deep:
2477 * @context1: a generic context
2478 * @context2: a generic context
2480 * Returns whether context1's type arguments are equal to context2's
2484 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2486 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2487 generic_inst_equal (context1->method_inst, context2->method_inst);
2491 * mini_class_get_container_class:
2492 * @class: a generic class
2494 * Returns the class's container class, which is the class itself if
2495 * it doesn't have generic_class set.
2498 mini_class_get_container_class (MonoClass *klass)
2500 if (klass->generic_class)
2501 return klass->generic_class->container_class;
2503 g_assert (klass->generic_container);
2508 * mini_class_get_context:
2509 * @class: a generic class
2511 * Returns the class's generic context.
2514 mini_class_get_context (MonoClass *klass)
2516 if (klass->generic_class)
2517 return &klass->generic_class->context;
2519 g_assert (klass->generic_container);
2520 return &klass->generic_container->context;
2524 * mini_get_basic_type_from_generic:
2527 * Returns a closed type corresponding to the possibly open type
2531 mini_get_basic_type_from_generic (MonoType *type)
2533 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2535 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2536 MonoType *constraint = type->data.generic_param->gshared_constraint;
2537 /* The gparam serial encodes the type this gparam can represent */
2539 return &mono_defaults.object_class->byval_arg;
2543 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2544 klass = mono_class_from_mono_type (constraint);
2545 return &klass->byval_arg;
2548 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2553 * mini_type_get_underlying_type:
2555 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2559 mini_type_get_underlying_type (MonoType *type)
2561 type = mini_native_type_replace_type (type);
2564 return &mono_defaults.int_class->byval_arg;
2565 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2567 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
2568 switch (type->type) {
2569 case MONO_TYPE_BOOLEAN:
2570 return &mono_defaults.byte_class->byval_arg;
2571 case MONO_TYPE_CHAR:
2572 return &mono_defaults.uint16_class->byval_arg;
2579 * mini_type_stack_size:
2581 * @align: Pointer to an int for returning the alignment
2583 * Returns the type's stack size and the alignment in *align.
2586 mini_type_stack_size (MonoType *t, int *align)
2588 return mono_type_stack_size_internal (t, align, TRUE);
2592 * mini_type_stack_size_full:
2594 * Same as mini_type_stack_size, but handle pinvoke data types as well.
2597 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
2601 //g_assert (!mini_is_gsharedvt_type (t));
2604 size = mono_type_native_stack_size (t, align);
2609 size = mini_type_stack_size (t, &ialign);
2612 size = mini_type_stack_size (t, NULL);
2620 * mono_generic_sharing_init:
2622 * Register the generic sharing counters.
2625 mono_generic_sharing_init (void)
2627 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2631 mono_generic_sharing_cleanup (void)
2633 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2635 if (generic_subclass_hash)
2636 g_hash_table_destroy (generic_subclass_hash);
2640 * mini_type_var_is_vt:
2642 * Return whenever T is a type variable instantiated with a vtype.
2645 mini_type_var_is_vt (MonoType *type)
2647 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
2648 return type->data.generic_param->gshared_constraint && type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
2650 g_assert_not_reached ();
2656 mini_type_is_reference (MonoType *type)
2658 type = mini_type_get_underlying_type (type);
2659 return mono_type_is_reference (type);
2663 * mini_method_get_rgctx:
2665 * Return the RGCTX which needs to be passed to M when it is called.
2668 mini_method_get_rgctx (MonoMethod *m)
2670 if (mini_method_get_context (m)->method_inst)
2671 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2673 return mono_class_vtable (mono_domain_get (), m->klass);
2677 * mini_type_is_vtype:
2679 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2680 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2683 mini_type_is_vtype (MonoType *t)
2685 t = mini_type_get_underlying_type (t);
2687 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
2691 mini_class_is_generic_sharable (MonoClass *klass)
2693 if (klass->generic_class && is_async_state_machine_class (klass))
2696 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2700 mini_is_gsharedvt_variable_klass (MonoClass *klass)
2702 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
2706 mini_is_gsharedvt_gparam (MonoType *t)
2708 /* Matches get_gsharedvt_type () */
2709 return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
2713 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
2715 if (constraint == MONO_TYPE_VALUETYPE) {
2716 return g_strdup_printf ("%s_GSHAREDVT", name);
2717 } else if (constraint == MONO_TYPE_OBJECT) {
2718 return g_strdup_printf ("%s_REF", name);
2719 } else if (constraint == MONO_TYPE_GENERICINST) {
2720 return g_strdup_printf ("%s_INST", name);
2723 char *tname, *tname2, *res;
2725 memset (&t, 0, sizeof (t));
2726 t.type = constraint;
2727 tname = mono_type_full_name (&t);
2728 tname2 = g_utf8_strup (tname, strlen (tname));
2729 res = g_strdup_printf ("%s_%s", name, tname2);
2737 shared_gparam_hash (gconstpointer data)
2739 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
2742 hash = mono_metadata_generic_param_hash (p->parent);
2743 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
2749 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
2751 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
2752 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
2756 if (p1->parent != p2->parent)
2758 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
2764 * mini_get_shared_gparam:
2766 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
2769 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
2771 MonoGenericParam *par = t->data.generic_param;
2772 MonoGSharedGenericParam *copy, key;
2774 MonoImage *image = NULL;
2777 memset (&key, 0, sizeof (key));
2779 key.param.param.gshared_constraint = constraint;
2781 g_assert (mono_generic_param_info (par));
2782 /* image might not be set for sre */
2783 if (par->owner && par->owner->image) {
2784 image = par->owner->image;
2787 * Need a cache to ensure the newly created gparam
2788 * is unique wrt T/CONSTRAINT.
2790 mono_image_lock (image);
2791 if (!image->gshared_types) {
2792 image->gshared_types_len = MONO_TYPE_INTERNAL;
2793 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
2795 if (!image->gshared_types [constraint->type])
2796 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
2797 res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
2798 mono_image_unlock (image);
2801 copy = mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
2802 memcpy (©->param, par, sizeof (MonoGenericParamFull));
2803 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
2804 copy->param.info.name = mono_image_strdup (image, name);
2807 /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
2808 copy = g_new0 (MonoGSharedGenericParam, 1);
2809 memcpy (©->param, par, sizeof (MonoGenericParam));
2811 copy->param.param.owner = NULL;
2813 copy->param.param.image = image ? image : mono_defaults.corlib;
2815 copy->param.param.gshared_constraint = constraint;
2817 res = mono_metadata_type_dup (NULL, t);
2818 res->data.generic_param = (MonoGenericParam*)copy;
2821 mono_image_lock (image);
2822 /* Duplicates are ok */
2823 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
2824 mono_image_unlock (image);
2830 static MonoGenericInst*
2831 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
2834 get_shared_type (MonoType *t, MonoType *type)
2838 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2839 MonoGenericClass *gclass = type->data.generic_class;
2840 MonoGenericContext context;
2843 memset (&context, 0, sizeof (context));
2844 if (gclass->context.class_inst)
2845 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
2846 if (gclass->context.method_inst)
2847 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
2849 k = mono_class_inflate_generic_class (gclass->container_class, &context);
2851 return mini_get_shared_gparam (t, &k->byval_arg);
2852 } else if (MONO_TYPE_ISSTRUCT (type)) {
2856 /* Create a type variable with a constraint which encodes which types can match it */
2858 if (type->type == MONO_TYPE_VALUETYPE) {
2859 ttype = mono_class_enum_basetype (type->data.klass)->type;
2860 } else if (MONO_TYPE_IS_REFERENCE (type)) {
2861 ttype = MONO_TYPE_OBJECT;
2862 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
2863 if (type->data.generic_param->gshared_constraint)
2864 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
2865 ttype = MONO_TYPE_OBJECT;
2872 memset (&t2, 0, sizeof (t2));
2874 klass = mono_class_from_mono_type (&t2);
2876 return mini_get_shared_gparam (t, &klass->byval_arg);
2881 get_gsharedvt_type (MonoType *t)
2883 /* Use TypeHandle as the constraint type since its a valuetype */
2884 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
2887 static MonoGenericInst*
2888 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
2890 MonoGenericInst *res;
2891 MonoType **type_argv;
2894 type_argv = g_new0 (MonoType*, inst->type_argc);
2895 for (i = 0; i < inst->type_argc; ++i) {
2896 if (all_vt || gsharedvt) {
2897 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2899 /* These types match the ones in generic_inst_is_sharable () */
2900 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
2904 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
2910 * mini_get_shared_method_full:
2912 * Return the method which is actually compiled/registered when doing generic sharing.
2913 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
2914 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
2915 * METHOD can be a non-inflated generic method.
2918 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
2921 MonoGenericContext shared_context;
2922 MonoMethod *declaring_method, *res;
2923 gboolean partial = FALSE;
2924 gboolean gsharedvt = FALSE;
2925 MonoGenericContainer *class_container, *method_container = NULL;
2926 MonoGenericContext *context = mono_method_get_context (method);
2927 MonoGenericInst *inst;
2929 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
2930 declaring_method = method;
2932 declaring_method = mono_method_get_declaring_generic_method (method);
2935 /* shared_context is the context containing type variables. */
2936 if (declaring_method->is_generic)
2937 shared_context = mono_method_get_generic_container (declaring_method)->context;
2939 shared_context = declaring_method->klass->generic_container->context;
2942 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
2944 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
2946 class_container = declaring_method->klass->generic_container;
2947 method_container = mono_method_get_generic_container (declaring_method);
2950 * Create the shared context by replacing the ref type arguments with
2951 * type parameters, and keeping the rest.
2954 inst = context->class_inst;
2956 inst = shared_context.class_inst;
2958 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
2961 inst = context->method_inst;
2963 inst = shared_context.method_inst;
2965 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
2967 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
2968 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2970 //printf ("%s\n", mono_method_full_name (res, 1));
2976 mini_get_shared_method (MonoMethod *method)
2978 return mini_get_shared_method_full (method, FALSE, FALSE);
2982 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
2986 switch (entry->data->type) {
2987 case MONO_PATCH_INFO_CLASS:
2988 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
2990 case MONO_PATCH_INFO_METHOD:
2991 case MONO_PATCH_INFO_METHODCONST:
2992 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
2994 case MONO_PATCH_INFO_FIELD:
2995 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
2997 case MONO_PATCH_INFO_SIGNATURE:
2998 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method));
3000 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3001 MonoJumpInfoGSharedVtCall *call_info = g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3003 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3004 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3007 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3008 MonoGSharedVtMethodInfo *info;
3009 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3012 /* Make a copy into the domain mempool */
3013 info = g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3014 info->method = oinfo->method;
3015 info->num_entries = oinfo->num_entries;
3016 info->entries = g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3017 for (i = 0; i < oinfo->num_entries; ++i) {
3018 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3019 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
3021 memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3023 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3026 case MONO_PATCH_INFO_VIRT_METHOD: {
3027 MonoJumpInfoVirtMethod *info;
3028 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3030 info = g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3031 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3032 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3036 g_assert_not_reached ();
3043 #if defined(ENABLE_GSHAREDVT)
3045 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3050 mini_is_gsharedvt_type (MonoType *t)
3056 mini_is_gsharedvt_klass (MonoClass *klass)
3062 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3068 mini_is_gsharedvt_variable_type (MonoType *t)
3074 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3080 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3085 #endif /* !MONOTOUCH */