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 *class)
122 int context_used = 0;
124 context_used |= type_check_context_used (&class->this_arg, FALSE);
125 context_used |= type_check_context_used (&class->byval_arg, FALSE);
127 if (class->generic_class)
128 context_used |= mono_generic_context_check_used (&class->generic_class->context);
129 else if (class->generic_container)
130 context_used |= mono_generic_context_check_used (&class->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 *class, MonoRuntimeGenericContextTemplate *rgctx_template)
230 if (!class->image->rgctx_template_hash)
231 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
233 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
237 * LOCKING: loader lock
239 static MonoRuntimeGenericContextTemplate*
240 class_lookup_rgctx_template (MonoClass *class)
242 MonoRuntimeGenericContextTemplate *template;
244 if (!class->image->rgctx_template_hash)
247 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
253 * LOCKING: loader lock
256 register_generic_subclass (MonoClass *class)
258 MonoClass *parent = class->parent;
260 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
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, class);
276 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
280 if (class->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, class, 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 *class)
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 (class->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 *class, 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 : class->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, class, 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 *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
716 class_uninstantiated (MonoClass *class)
718 if (class->generic_class)
719 return class->generic_class->container_class;
726 * Return the class used to store information when using generic sharing.
729 get_shared_class (MonoClass *class)
731 return class_uninstantiated (class);
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 *class)
744 MonoRuntimeGenericContextTemplate *parent_template, *template;
747 class = get_shared_class (class);
750 template = class_lookup_rgctx_template (class);
751 mono_loader_unlock ();
756 //g_assert (get_shared_class (class) == class);
758 template = alloc_template (class);
764 int max_argc, type_argc;
766 parent_template = mono_class_get_runtime_generic_context_template (class->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 (class->parent, type_argc, i, FALSE, FALSE, NULL);
777 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
778 rgctx_template_set_slot (class->image, template, type_argc, i,
779 oti.data, oti.info_type);
785 if (class_lookup_rgctx_template (class)) {
786 /* some other thread already set the template */
787 template = class_lookup_rgctx_template (class);
789 class_set_rgctx_template (class, template);
792 register_generic_subclass (class);
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 *class, 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 (class->generic_class && !shared) {
820 MonoRuntimeGenericContextInfoTemplate oti;
821 gboolean tmp_do_free;
823 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
824 type_argc, slot, TRUE, FALSE, &tmp_do_free);
826 gpointer info = oti.data;
827 oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
829 free_inflated_info (oti.info_type, info);
836 MonoRuntimeGenericContextTemplate *template;
837 MonoRuntimeGenericContextInfoTemplate *oti;
839 template = mono_class_get_runtime_generic_context_template (class);
840 oti = rgctx_template_get_other_slot (template, type_argc, slot);
851 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
854 case MONO_RGCTX_INFO_STATIC_DATA: {
855 MonoVTable *vtable = mono_class_vtable (domain, class);
857 mono_raise_exception (mono_class_get_exception_for_failure (class));
858 return mono_vtable_get_static_field_data (vtable);
860 case MONO_RGCTX_INFO_KLASS:
862 case MONO_RGCTX_INFO_ELEMENT_KLASS:
863 return class->element_class;
864 case MONO_RGCTX_INFO_VTABLE: {
865 MonoVTable *vtable = mono_class_vtable (domain, class);
867 mono_raise_exception (mono_class_get_exception_for_failure (class));
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)class;
876 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
877 return GUINT_TO_POINTER (mono_class_array_element_size (class));
878 case MONO_RGCTX_INFO_VALUE_SIZE:
879 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
880 return GUINT_TO_POINTER (sizeof (gpointer));
882 return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
883 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
884 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
885 return GUINT_TO_POINTER (1);
886 else if (mono_class_is_nullable (class))
887 return GUINT_TO_POINTER (2);
889 return GUINT_TO_POINTER (0);
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 (&class->byval_arg)) {
901 size = sizeof (gpointer);
902 align = sizeof (gpointer);
904 size = mono_class_value_size (class, &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: {
959 MonoGenericContext *ctx;
961 if (!mono_class_is_nullable (class))
962 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
965 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
966 method = mono_class_get_method_from_name (class, "Box", 1);
968 method = mono_class_get_method_from_name (class, "Unbox", 1);
970 addr = mono_compile_method (method);
971 // The caller uses the gsharedvt call signature
972 ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
974 if (mini_jit_info_is_gsharedvt (ji))
975 return mono_create_static_rgctx_trampoline (method, addr);
977 MonoGenericSharingContext gsctx;
978 MonoMethodSignature *sig, *gsig;
981 /* Need to add an out wrapper */
983 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
984 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
985 sig = mono_method_signature (method);
986 gsig = mono_method_signature (gmethod);
987 ctx = mono_method_get_context (gmethod);
988 mini_init_gsctx (NULL, NULL, ctx, &gsctx);
990 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, &gsctx, -1, FALSE);
991 addr = mono_create_static_rgctx_trampoline (method, addr);
996 g_assert_not_reached ();
1003 ji_is_gsharedvt (MonoJitInfo *ji)
1005 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1012 * Describes the information used to construct a gsharedvt arg trampoline.
1017 gint32 vcall_offset;
1019 MonoMethodSignature *sig, *gsig;
1020 } GSharedVtTrampInfo;
1023 tramp_info_hash (gconstpointer key)
1025 GSharedVtTrampInfo *tramp = (gpointer)key;
1027 return (gsize)tramp->addr;
1031 tramp_info_equal (gconstpointer a, gconstpointer b)
1033 GSharedVtTrampInfo *tramp1 = (gpointer)a;
1034 GSharedVtTrampInfo *tramp2 = (gpointer)b;
1036 /* The signatures should be internalized */
1037 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1038 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1042 * mini_get_gsharedvt_wrapper:
1044 * Return a gsharedvt in/out wrapper for calling ADDR.
1047 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
1048 gint32 vcall_offset, gboolean calli)
1050 static gboolean inited = FALSE;
1051 static int num_trampolines;
1053 MonoDomain *domain = mono_domain_get ();
1054 MonoJitDomainInfo *domain_info;
1055 GSharedVtTrampInfo *tramp_info;
1056 GSharedVtTrampInfo tinfo;
1059 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1063 memset (&tinfo, 0, sizeof (tinfo));
1064 tinfo.is_in = gsharedvt_in;
1065 tinfo.calli = calli;
1066 tinfo.vcall_offset = vcall_offset;
1068 tinfo.sig = normal_sig;
1069 tinfo.gsig = gsharedvt_sig;
1071 domain_info = domain_jit_info (domain);
1074 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1076 mono_domain_lock (domain);
1077 if (!domain_info->gsharedvt_arg_tramp_hash)
1078 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1079 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1080 mono_domain_unlock (domain);
1084 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1087 static gpointer tramp_addr;
1088 MonoMethod *wrapper;
1091 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1092 addr = mono_compile_method (wrapper);
1093 mono_memory_barrier ();
1098 static gpointer tramp_addr;
1099 MonoMethod *wrapper;
1102 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1103 addr = mono_compile_method (wrapper);
1104 mono_memory_barrier ();
1111 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1113 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1118 tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1119 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1121 mono_domain_lock (domain);
1122 /* Duplicates are not a problem */
1123 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1124 mono_domain_unlock (domain);
1130 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1131 MonoGenericContext *context, MonoClass *class)
1139 switch (oti->info_type) {
1140 case MONO_RGCTX_INFO_STATIC_DATA:
1141 case MONO_RGCTX_INFO_KLASS:
1142 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1143 case MONO_RGCTX_INFO_VTABLE:
1144 case MONO_RGCTX_INFO_CAST_CACHE:
1151 data = inflate_info (oti, context, class, temporary);
1153 switch (oti->info_type) {
1154 case MONO_RGCTX_INFO_STATIC_DATA:
1155 case MONO_RGCTX_INFO_KLASS:
1156 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1157 case MONO_RGCTX_INFO_VTABLE:
1158 case MONO_RGCTX_INFO_CAST_CACHE:
1159 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1160 case MONO_RGCTX_INFO_VALUE_SIZE:
1161 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1162 case MONO_RGCTX_INFO_MEMCPY:
1163 case MONO_RGCTX_INFO_BZERO:
1164 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1165 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1166 MonoClass *arg_class = mono_class_from_mono_type (data);
1168 free_inflated_info (oti->info_type, data);
1169 g_assert (arg_class);
1171 /* The class might be used as an argument to
1172 mono_value_copy(), which requires that its GC
1173 descriptor has been computed. */
1174 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1175 mono_class_compute_gc_descriptor (arg_class);
1177 return class_type_info (domain, arg_class, oti->info_type);
1179 case MONO_RGCTX_INFO_TYPE:
1181 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1182 return mono_type_get_object (domain, data);
1183 case MONO_RGCTX_INFO_METHOD:
1185 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1188 addr = mono_compile_method (data);
1189 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1191 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1192 MonoJumpInfoVirtMethod *info = data;
1193 MonoClass *iface_class = info->method->klass;
1198 mono_class_setup_vtable (info->klass);
1199 // FIXME: Check type load
1200 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1201 ioffset = mono_class_interface_offset (info->klass, iface_class);
1202 g_assert (ioffset != -1);
1206 slot = mono_method_get_vtable_slot (info->method);
1207 g_assert (slot != -1);
1208 g_assert (info->klass->vtable);
1209 method = info->klass->vtable [ioffset + slot];
1211 addr = mono_compile_method (method);
1212 return mini_add_method_trampoline (NULL, method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1214 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1215 MonoJumpInfoVirtMethod *info = data;
1216 MonoClass *iface_class = info->method->klass;
1218 MonoClass *impl_class;
1221 mono_class_setup_vtable (info->klass);
1222 // FIXME: Check type load
1223 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1224 ioffset = mono_class_interface_offset (info->klass, iface_class);
1225 g_assert (ioffset != -1);
1229 slot = mono_method_get_vtable_slot (info->method);
1230 g_assert (slot != -1);
1231 g_assert (info->klass->vtable);
1232 method = info->klass->vtable [ioffset + slot];
1234 impl_class = method->klass;
1235 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1236 return GUINT_TO_POINTER (1);
1237 else if (mono_class_is_nullable (impl_class))
1238 return GUINT_TO_POINTER (2);
1240 return GUINT_TO_POINTER (0);
1242 #ifndef DISABLE_REMOTING
1243 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1244 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1246 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1247 return mono_domain_alloc0 (domain, sizeof (gpointer));
1248 case MONO_RGCTX_INFO_CLASS_FIELD:
1250 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1251 MonoClassField *field = data;
1253 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1254 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1256 return GUINT_TO_POINTER (field->offset);
1258 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1259 MonoMethodInflated *method = data;
1262 g_assert (method->method.method.is_inflated);
1263 g_assert (method->context.method_inst);
1265 vtable = mono_class_vtable (domain, method->method.method.klass);
1267 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1269 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1271 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1272 MonoMethodInflated *method = data;
1274 g_assert (method->method.method.is_inflated);
1275 g_assert (method->context.method_inst);
1277 return method->context.method_inst;
1279 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1280 MonoMethodSignature *gsig = oti->data;
1281 MonoMethodSignature *sig = data;
1285 * This is an indirect call to the address passed by the caller in the rgctx reg.
1287 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, NULL, -1, TRUE);
1290 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1291 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1292 MonoJumpInfoGSharedVtCall *call_info = data;
1293 MonoMethodSignature *call_sig;
1296 MonoJitInfo *callee_ji;
1297 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1298 gint32 vcall_offset;
1299 gboolean callee_gsharedvt;
1301 /* This is the original generic signature used by the caller */
1302 call_sig = call_info->sig;
1303 /* This is the instantiated method which is called */
1304 method = call_info->method;
1306 g_assert (method->is_inflated);
1309 addr = mono_compile_method (method);
1314 /* Same as in mono_emit_method_call_full () */
1315 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1316 /* See mono_emit_method_call_full () */
1317 /* The gsharedvt trampoline will recognize this constant */
1318 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1319 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1320 guint32 imt_slot = mono_method_get_imt_slot (method);
1321 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1323 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1324 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1330 // FIXME: This loads information in the AOT case
1331 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1332 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1335 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1336 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1337 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1338 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1339 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1340 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1341 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1342 * caller -> out trampoline -> in trampoline -> callee
1343 * This is not very efficient, but it is easy to implement.
1345 if (virtual || !callee_gsharedvt) {
1346 MonoMethodSignature *sig, *gsig;
1348 g_assert (method->is_inflated);
1350 sig = mono_method_signature (method);
1353 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, NULL, vcall_offset, FALSE);
1356 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1358 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1360 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1361 } else if (callee_gsharedvt) {
1362 MonoMethodSignature *sig, *gsig;
1365 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1366 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1369 * public void foo<T1> (T1 t1, T t, object o) {}
1371 * class AClass : Base<long> {
1372 * public void bar<T> (T t, long time, object o) {
1376 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1377 * FIXME: Optimize this.
1380 if (call_sig == mono_method_signature (method)) {
1382 sig = mono_method_signature (method);
1383 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1385 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, NULL, -1, FALSE);
1387 sig = mono_method_signature (method);
1390 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, NULL, -1, FALSE);
1392 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1398 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1399 MonoGSharedVtMethodInfo *info = data;
1400 MonoGSharedVtMethodRuntimeInfo *res;
1402 int i, offset, align, size;
1405 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1408 for (i = 0; i < info->num_entries; ++i) {
1409 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1411 switch (template->info_type) {
1412 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1415 size = mono_type_size (t, &align);
1417 if (align < sizeof (gpointer))
1418 align = sizeof (gpointer);
1419 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1420 align = 2 * sizeof (gpointer);
1422 // FIXME: Do the same things as alloc_stack_slots
1423 offset += align - 1;
1424 offset &= ~(align - 1);
1425 res->entries [i] = GINT_TO_POINTER (offset);
1429 res->entries [i] = instantiate_info (domain, template, context, class);
1433 res->locals_size = offset;
1438 g_assert_not_reached ();
1445 * LOCKING: loader lock
1448 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1450 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1451 MonoClass *subclass;
1453 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1455 /* Recurse for all subclasses */
1456 if (generic_subclass_hash)
1457 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1462 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1463 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1465 g_assert (subclass_template);
1467 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1468 g_assert (subclass_oti.data);
1470 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1472 subclass = subclass_template->next_subclass;
1477 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1480 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1481 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1482 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1483 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1484 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1485 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1486 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1487 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1488 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1489 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1490 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1491 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1492 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1493 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1494 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1495 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1496 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1497 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1498 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1499 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1500 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1501 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1502 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1503 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1504 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1505 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1506 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1507 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1509 return "<UNKNOWN RGCTX INFO TYPE>";
1513 G_GNUC_UNUSED static char*
1514 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1516 switch (info_type) {
1517 case MONO_RGCTX_INFO_VTABLE:
1518 return mono_type_full_name ((MonoType*)data);
1520 return g_strdup_printf ("<%p>", data);
1525 * LOCKING: loader lock
1528 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1531 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1533 MonoRuntimeGenericContextInfoTemplate *oti;
1535 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1540 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)));
1542 /* Mark the slot as used in all parent classes (until we find
1543 a parent class which already has it marked used). */
1544 parent = class->parent;
1545 while (parent != NULL) {
1546 MonoRuntimeGenericContextTemplate *parent_template;
1547 MonoRuntimeGenericContextInfoTemplate *oti;
1549 if (parent->generic_class)
1550 parent = parent->generic_class->container_class;
1552 parent_template = mono_class_get_runtime_generic_context_template (parent);
1553 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1555 if (oti && oti->data)
1558 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1559 MONO_RGCTX_SLOT_USED_MARKER, 0);
1561 parent = parent->parent;
1564 /* Fill in the slot in this class and in all subclasses
1566 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1572 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1574 switch (info_type) {
1575 case MONO_RGCTX_INFO_STATIC_DATA:
1576 case MONO_RGCTX_INFO_KLASS:
1577 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1578 case MONO_RGCTX_INFO_VTABLE:
1579 case MONO_RGCTX_INFO_TYPE:
1580 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1581 case MONO_RGCTX_INFO_CAST_CACHE:
1582 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1583 case MONO_RGCTX_INFO_VALUE_SIZE:
1584 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1585 case MONO_RGCTX_INFO_MEMCPY:
1586 case MONO_RGCTX_INFO_BZERO:
1587 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1588 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1589 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1590 case MONO_RGCTX_INFO_METHOD:
1591 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1592 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1593 case MONO_RGCTX_INFO_CLASS_FIELD:
1594 case MONO_RGCTX_INFO_FIELD_OFFSET:
1595 case MONO_RGCTX_INFO_METHOD_RGCTX:
1596 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1597 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1598 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1599 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1600 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1601 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1602 return data1 == data2;
1603 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
1604 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1605 MonoJumpInfoVirtMethod *info1 = data1;
1606 MonoJumpInfoVirtMethod *info2 = data2;
1608 return info1->klass == info2->klass && info1->method == info2->method;
1611 g_assert_not_reached ();
1618 * mini_rgctx_info_type_to_patch_info_type:
1620 * Return the type of the runtime object referred to by INFO_TYPE.
1623 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1625 switch (info_type) {
1626 case MONO_RGCTX_INFO_STATIC_DATA:
1627 case MONO_RGCTX_INFO_KLASS:
1628 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1629 case MONO_RGCTX_INFO_VTABLE:
1630 case MONO_RGCTX_INFO_TYPE:
1631 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1632 case MONO_RGCTX_INFO_CAST_CACHE:
1633 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1634 case MONO_RGCTX_INFO_VALUE_SIZE:
1635 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1636 case MONO_RGCTX_INFO_MEMCPY:
1637 case MONO_RGCTX_INFO_BZERO:
1638 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1639 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1640 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1641 return MONO_PATCH_INFO_CLASS;
1642 case MONO_RGCTX_INFO_FIELD_OFFSET:
1643 return MONO_PATCH_INFO_FIELD;
1645 g_assert_not_reached ();
1651 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1652 MonoGenericContext *generic_context)
1654 static gboolean inited = FALSE;
1655 static int max_slot = 0;
1657 MonoRuntimeGenericContextTemplate *rgctx_template =
1658 mono_class_get_runtime_generic_context_template (class);
1659 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1662 class = get_shared_class (class);
1664 mono_loader_lock ();
1666 if (info_has_identity (info_type)) {
1667 oti_list = get_info_templates (rgctx_template, type_argc);
1669 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1670 gpointer inflated_data;
1672 if (oti->info_type != info_type || !oti->data)
1675 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1677 if (info_equal (data, inflated_data, info_type)) {
1678 free_inflated_info (info_type, inflated_data);
1679 mono_loader_unlock ();
1682 free_inflated_info (info_type, inflated_data);
1686 /* We haven't found the info */
1687 i = register_info (class, type_argc, data, info_type);
1689 mono_loader_unlock ();
1692 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1702 * mono_method_lookup_or_register_info:
1704 * @in_mrgctx: whether to put the data into the MRGCTX
1705 * @data: the info data
1706 * @info_type: the type of info to register about data
1707 * @generic_context: a generic context
1709 * Looks up and, if necessary, adds information about data/info_type in
1710 * method's or method's class runtime generic context. Returns the
1711 * encoded slot number.
1714 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1715 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1717 MonoClass *class = method->klass;
1718 int type_argc, index;
1721 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1723 g_assert (method->is_inflated && method_inst);
1724 type_argc = method_inst->type_argc;
1725 g_assert (type_argc > 0);
1730 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1732 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1735 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1737 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1741 * mono_class_rgctx_get_array_size:
1742 * @n: The number of the array
1743 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1745 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1746 * number includes the slot for linking and - for MRGCTXs - the two
1747 * slots in the first array for additional information.
1750 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1752 g_assert (n >= 0 && n < 30);
1761 * LOCKING: domain lock
1764 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1766 static gboolean inited = FALSE;
1767 static int rgctx_num_alloced = 0;
1768 static int rgctx_bytes_alloced = 0;
1769 static int mrgctx_num_alloced = 0;
1770 static int mrgctx_bytes_alloced = 0;
1772 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1773 gpointer array = mono_domain_alloc0 (domain, size);
1776 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1777 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1778 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1779 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1784 mrgctx_num_alloced++;
1785 mrgctx_bytes_alloced += size;
1787 rgctx_num_alloced++;
1788 rgctx_bytes_alloced += size;
1795 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1796 MonoGenericInst *method_inst)
1799 int i, first_slot, size;
1800 MonoDomain *domain = class_vtable->domain;
1801 MonoClass *class = class_vtable->klass;
1802 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1803 MonoRuntimeGenericContextInfoTemplate oti;
1804 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1810 mono_domain_lock (domain);
1812 /* First check whether that slot isn't already instantiated.
1813 This might happen because lookup doesn't lock. Allocate
1814 arrays on the way. */
1816 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1818 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1819 for (i = 0; ; ++i) {
1822 if (method_inst && i == 0)
1823 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1827 if (slot < first_slot + size - 1) {
1828 rgctx_index = slot - first_slot + 1 + offset;
1829 info = rgctx [rgctx_index];
1831 mono_domain_unlock (domain);
1836 if (!rgctx [offset + 0])
1837 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1838 rgctx = rgctx [offset + 0];
1839 first_slot += size - 1;
1840 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1843 g_assert (!rgctx [rgctx_index]);
1845 mono_domain_unlock (domain);
1847 oti = class_get_rgctx_template_oti (get_shared_class (class),
1848 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1849 /* This might take the loader lock */
1850 info = instantiate_info (domain, &oti, &context, class);
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 (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
2014 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2015 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)))
2018 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2019 MonoGenericClass *gclass = type->data.generic_class;
2021 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2023 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2025 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2034 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2035 gboolean allow_partial)
2039 for (i = 0; i < inst->type_argc; ++i) {
2040 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2048 * mono_is_partially_sharable_inst:
2050 * Return TRUE if INST has ref and non-ref type arguments.
2053 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2056 gboolean has_refs = FALSE, has_non_refs = FALSE;
2058 for (i = 0; i < inst->type_argc; ++i) {
2059 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)
2062 has_non_refs = TRUE;
2065 return has_refs && has_non_refs;
2069 * mono_generic_context_is_sharable_full:
2070 * @context: a generic context
2072 * Returns whether the generic context is sharable. A generic context
2073 * is sharable iff all of its type arguments are reference type, or some of them have a
2074 * reference type, and ALLOW_PARTIAL is TRUE.
2077 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2078 gboolean allow_type_vars,
2079 gboolean allow_partial)
2081 g_assert (context->class_inst || context->method_inst);
2083 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2086 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2093 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2095 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2099 * mono_method_is_generic_impl:
2102 * Returns whether the method is either generic or part of a generic
2106 mono_method_is_generic_impl (MonoMethod *method)
2108 if (method->is_inflated)
2110 /* We don't treat wrappers as generic code, i.e., we never
2111 apply generic sharing to them. This is especially
2112 important for static rgctx invoke wrappers, which only work
2113 if not compiled with sharing. */
2114 if (method->wrapper_type != MONO_WRAPPER_NONE)
2116 if (method->klass->generic_container)
2122 has_constraints (MonoGenericContainer *container)
2128 g_assert (container->type_argc > 0);
2129 g_assert (container->type_params);
2131 for (i = 0; i < container->type_argc; ++i)
2132 if (container->type_params [i].constraints)
2139 mini_method_is_open (MonoMethod *method)
2141 if (method->is_inflated) {
2142 MonoGenericContext *ctx = mono_method_get_context (method);
2144 if (ctx->class_inst && ctx->class_inst->is_open)
2146 if (ctx->method_inst && ctx->method_inst->is_open)
2152 static G_GNUC_UNUSED gboolean
2153 is_async_state_machine_class (MonoClass *klass)
2155 static MonoClass *iclass;
2156 static gboolean iclass_set;
2161 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2162 mono_memory_barrier ();
2166 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2171 static G_GNUC_UNUSED gboolean
2172 is_async_method (MonoMethod *method)
2174 MonoCustomAttrInfo *cattr;
2175 MonoMethodSignature *sig;
2176 gboolean res = FALSE;
2177 static MonoClass *attr_class;
2178 static gboolean attr_class_set;
2182 if (!attr_class_set) {
2183 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2184 mono_memory_barrier ();
2185 attr_class_set = TRUE;
2188 /* Do less expensive checks first */
2189 sig = mono_method_signature (method);
2190 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2191 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2192 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2193 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2194 cattr = mono_custom_attrs_from_method (method);
2196 if (mono_custom_attrs_has_attr (cattr, attr_class))
2198 mono_custom_attrs_free (cattr);
2205 * mono_method_is_generic_sharable_full:
2207 * @allow_type_vars: whether to regard type variables as reference types
2208 * @allow_partial: whether to allow partial sharing
2209 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2211 * Returns TRUE iff the method is inflated or part of an inflated
2212 * class, its context is sharable and it has no constraints on its
2213 * type parameters. Otherwise returns FALSE.
2216 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2217 gboolean allow_partial, gboolean allow_gsharedvt)
2219 if (!mono_method_is_generic_impl (method))
2223 if (!mono_debug_count ())
2224 allow_partial = FALSE;
2227 if (!partial_sharing_supported ())
2228 allow_partial = FALSE;
2230 if (mono_class_is_nullable (method->klass))
2232 allow_partial = FALSE;
2234 if (method->klass->image->dynamic)
2236 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2237 * instance_size is 0.
2239 allow_partial = FALSE;
2242 * Generic async methods have an associated state machine class which is a generic struct. This struct
2243 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2244 * of the async method and the state machine class.
2246 if (is_async_state_machine_class (method->klass))
2249 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2250 if (is_async_method (method))
2255 if (method->is_inflated) {
2256 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2257 MonoGenericContext *context = &inflated->context;
2259 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2262 g_assert (inflated->declaring);
2264 if (inflated->declaring->is_generic) {
2265 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2270 if (method->klass->generic_class) {
2271 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2274 g_assert (method->klass->generic_class->container_class &&
2275 method->klass->generic_class->container_class->generic_container);
2277 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2281 if (method->klass->generic_container && !allow_type_vars)
2284 /* This does potentially expensive cattr checks, so do it at the end */
2285 if (is_async_method (method)) {
2286 if (mini_method_is_open (method))
2287 /* The JIT can't compile these without sharing */
2296 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2298 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2302 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2304 if (!mono_class_generic_sharing_enabled (method->klass))
2307 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2310 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2313 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2314 method->klass->valuetype) &&
2315 (method->klass->generic_class || method->klass->generic_container);
2318 static MonoGenericInst*
2319 get_object_generic_inst (int type_argc)
2321 MonoType **type_argv;
2324 type_argv = alloca (sizeof (MonoType*) * type_argc);
2326 for (i = 0; i < type_argc; ++i)
2327 type_argv [i] = &mono_defaults.object_class->byval_arg;
2329 return mono_metadata_get_generic_inst (type_argc, type_argv);
2333 * mono_method_construct_object_context:
2336 * Returns a generic context for method with all type variables for
2337 * class and method instantiated with Object.
2340 mono_method_construct_object_context (MonoMethod *method)
2342 MonoGenericContext object_context;
2344 g_assert (!method->klass->generic_class);
2345 if (method->klass->generic_container) {
2346 int type_argc = method->klass->generic_container->type_argc;
2348 object_context.class_inst = get_object_generic_inst (type_argc);
2350 object_context.class_inst = NULL;
2353 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2354 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2356 object_context.method_inst = get_object_generic_inst (type_argc);
2358 object_context.method_inst = NULL;
2361 g_assert (object_context.class_inst || object_context.method_inst);
2363 return object_context;
2366 static gboolean gshared_supported;
2367 static gboolean gsharedvt_supported;
2370 mono_set_generic_sharing_supported (gboolean supported)
2372 gshared_supported = supported;
2376 mono_set_generic_sharing_vt_supported (gboolean supported)
2378 gsharedvt_supported = supported;
2382 mono_set_partial_sharing_supported (gboolean supported)
2384 partial_supported = supported;
2388 * mono_class_generic_sharing_enabled:
2391 * Returns whether generic sharing is enabled for class.
2393 * This is a stop-gap measure to slowly introduce generic sharing
2394 * until we have all the issues sorted out, at which time this
2395 * function will disappear and generic sharing will always be enabled.
2398 mono_class_generic_sharing_enabled (MonoClass *class)
2400 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2401 static gboolean inited = FALSE;
2406 if (gshared_supported)
2407 generic_sharing = MONO_GENERIC_SHARING_ALL;
2409 generic_sharing = MONO_GENERIC_SHARING_NONE;
2411 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2412 if (strcmp (option, "corlib") == 0)
2413 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2414 else if (strcmp (option, "collections") == 0)
2415 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2416 else if (strcmp (option, "all") == 0)
2417 generic_sharing = MONO_GENERIC_SHARING_ALL;
2418 else if (strcmp (option, "none") == 0)
2419 generic_sharing = MONO_GENERIC_SHARING_NONE;
2421 g_warning ("Unknown generic sharing option `%s'.", option);
2424 if (!gshared_supported)
2425 generic_sharing = MONO_GENERIC_SHARING_NONE;
2430 switch (generic_sharing) {
2431 case MONO_GENERIC_SHARING_NONE:
2433 case MONO_GENERIC_SHARING_ALL:
2435 case MONO_GENERIC_SHARING_CORLIB :
2436 return class->image == mono_defaults.corlib;
2437 case MONO_GENERIC_SHARING_COLLECTIONS:
2438 if (class->image != mono_defaults.corlib)
2440 while (class->nested_in)
2441 class = class->nested_in;
2442 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2444 g_assert_not_reached ();
2450 * mono_get_generic_context_from_code:
2452 * Return the runtime generic context belonging to the method whose native code
2455 MonoGenericSharingContext*
2456 mono_get_generic_context_from_code (guint8 *code)
2458 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2460 g_assert (jit_info);
2462 return mono_jit_info_get_generic_sharing_context (jit_info);
2466 mini_method_get_context (MonoMethod *method)
2468 return mono_method_get_context_general (method, TRUE);
2472 * mono_method_check_context_used:
2475 * Checks whether the method's generic context uses a type variable.
2476 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2477 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2478 * context's class or method instantiation uses type variables.
2481 mono_method_check_context_used (MonoMethod *method)
2483 MonoGenericContext *method_context = mini_method_get_context (method);
2484 int context_used = 0;
2486 if (!method_context) {
2487 /* It might be a method of an array of an open generic type */
2488 if (method->klass->rank)
2489 context_used = mono_class_check_context_used (method->klass);
2491 context_used = mono_generic_context_check_used (method_context);
2492 context_used |= mono_class_check_context_used (method->klass);
2495 return context_used;
2499 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2510 if (inst1->type_argc != inst2->type_argc)
2513 for (i = 0; i < inst1->type_argc; ++i)
2514 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2521 * mono_generic_context_equal_deep:
2522 * @context1: a generic context
2523 * @context2: a generic context
2525 * Returns whether context1's type arguments are equal to context2's
2529 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2531 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2532 generic_inst_equal (context1->method_inst, context2->method_inst);
2536 * mini_class_get_container_class:
2537 * @class: a generic class
2539 * Returns the class's container class, which is the class itself if
2540 * it doesn't have generic_class set.
2543 mini_class_get_container_class (MonoClass *class)
2545 if (class->generic_class)
2546 return class->generic_class->container_class;
2548 g_assert (class->generic_container);
2553 * mini_class_get_context:
2554 * @class: a generic class
2556 * Returns the class's generic context.
2559 mini_class_get_context (MonoClass *class)
2561 if (class->generic_class)
2562 return &class->generic_class->context;
2564 g_assert (class->generic_container);
2565 return &class->generic_container->context;
2569 * mini_get_basic_type_from_generic:
2570 * @gsctx: a generic sharing context
2573 * Returns a closed type corresponding to the possibly open type
2577 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2579 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2581 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2584 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2586 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2587 MonoType *constraint = type->data.generic_param->gshared_constraint;
2588 /* The gparam serial encodes the type this gparam can represent */
2590 return &mono_defaults.object_class->byval_arg;
2594 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2595 klass = mono_class_from_mono_type (constraint);
2596 return &klass->byval_arg;
2599 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2604 * mini_type_get_underlying_type:
2606 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2610 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2612 type = mini_native_type_replace_type (type);
2615 return &mono_defaults.int_class->byval_arg;
2616 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2618 type = mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2619 switch (type->type) {
2620 case MONO_TYPE_BOOLEAN:
2621 return &mono_defaults.byte_class->byval_arg;
2622 case MONO_TYPE_CHAR:
2623 return &mono_defaults.uint16_class->byval_arg;
2630 * mini_type_stack_size:
2631 * @gsctx: a generic sharing context
2633 * @align: Pointer to an int for returning the alignment
2635 * Returns the type's stack size and the alignment in *align. The
2636 * type is allowed to be open.
2639 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2641 gboolean allow_open = TRUE;
2643 // FIXME: Some callers might not pass in a gsctx
2644 //allow_open = gsctx != NULL;
2645 return mono_type_stack_size_internal (t, align, allow_open);
2649 * mini_type_stack_size_full:
2651 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2654 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2659 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2663 //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2666 size = mono_type_native_stack_size (t, align);
2671 size = mini_type_stack_size (gsctx, t, &ialign);
2674 size = mini_type_stack_size (gsctx, t, NULL);
2682 * mono_generic_sharing_init:
2684 * Register the generic sharing counters.
2687 mono_generic_sharing_init (void)
2689 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2693 mono_generic_sharing_cleanup (void)
2695 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2697 if (generic_subclass_hash)
2698 g_hash_table_destroy (generic_subclass_hash);
2702 * mini_type_var_is_vt:
2704 * Return whenever T is a type variable instantiated with a vtype.
2707 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2709 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
2710 return type->data.generic_param->gshared_constraint && type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
2712 g_assert_not_reached ();
2718 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2720 if (cfg->generic_sharing_context)
2721 type = mini_get_underlying_type (cfg, type);
2722 return mono_type_is_reference (type);
2726 * mini_method_get_rgctx:
2728 * Return the RGCTX which needs to be passed to M when it is called.
2731 mini_method_get_rgctx (MonoMethod *m)
2733 if (mini_method_get_context (m)->method_inst)
2734 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2736 return mono_class_vtable (mono_domain_get (), m->klass);
2740 * mini_type_is_vtype:
2742 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2743 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2746 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2748 t = mini_get_underlying_type (cfg, t);
2750 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2754 mini_class_is_generic_sharable (MonoClass *klass)
2756 if (klass->generic_class && is_async_state_machine_class (klass))
2759 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2763 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2765 return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2769 mini_is_gsharedvt_gparam (MonoType *t)
2771 /* Matches get_gsharedvt_type () */
2772 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;
2776 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
2778 if (constraint == MONO_TYPE_VALUETYPE) {
2779 return g_strdup_printf ("%s_GSHAREDVT", name);
2780 } else if (constraint == MONO_TYPE_OBJECT) {
2781 return g_strdup_printf ("%s_REF", name);
2782 } else if (constraint == MONO_TYPE_GENERICINST) {
2783 return g_strdup_printf ("%s_INST", name);
2786 char *tname, *tname2, *res;
2788 memset (&t, 0, sizeof (t));
2789 t.type = constraint;
2790 tname = mono_type_full_name (&t);
2791 tname2 = g_utf8_strup (tname, strlen (tname));
2792 res = g_strdup_printf ("%s_%s", name, tname2);
2800 MonoGenericParam *par;
2801 MonoType *constraint;
2805 shared_gparam_hash (gconstpointer data)
2807 SharedGParam *p = (SharedGParam*)data;
2810 hash = mono_metadata_generic_param_hash (p->par);
2811 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->constraint);
2817 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
2819 SharedGParam *p1 = (SharedGParam*)ka;
2820 SharedGParam *p2 = (SharedGParam*)kb;
2824 if (p1->par != p2->par)
2826 if (!mono_metadata_type_equal (p1->constraint, p2->constraint))
2832 * get_shared_gparam:
2834 * Create an anonymous gparam with a type variable with a constraint which encodes which types can match it.
2837 get_shared_gparam (MonoType *t, MonoType *constraint)
2839 MonoGenericParam *par = t->data.generic_param;
2840 MonoGenericParam *copy;
2843 MonoImage *image = NULL;
2846 memset (&key, 0, sizeof (key));
2848 key.constraint = constraint;
2850 g_assert (mono_generic_param_info (par));
2851 /* image might not be set for sre */
2852 if (par->owner && par->owner->image) {
2853 image = par->owner->image;
2855 mono_image_lock (image);
2856 if (!image->gshared_types) {
2857 image->gshared_types_len = MONO_TYPE_INTERNAL;
2858 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
2860 if (!image->gshared_types [constraint->type])
2861 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
2862 res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
2863 mono_image_unlock (image);
2866 copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
2867 memcpy (copy, par, sizeof (MonoGenericParamFull));
2868 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
2869 ((MonoGenericParamFull*)copy)->info.name = mono_image_strdup (image, name);
2872 /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
2873 copy = (MonoGenericParam*)g_new0 (MonoGenericParamFull, 1);
2874 memcpy (copy, par, sizeof (MonoGenericParam));
2878 copy->image = mono_defaults.corlib;
2880 copy->gshared_constraint = constraint;
2881 res = mono_metadata_type_dup (NULL, t);
2882 res->data.generic_param = copy;
2887 dkey = mono_image_alloc0 (image, sizeof (SharedGParam));
2889 dkey->constraint = constraint;
2891 mono_image_lock (image);
2892 /* Duplicates are ok */
2893 g_hash_table_insert (image->gshared_types [constraint->type], dkey, res);
2894 mono_image_unlock (image);
2900 static MonoGenericInst*
2901 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
2904 get_shared_type (MonoType *t, MonoType *type)
2908 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2909 MonoGenericClass *gclass = type->data.generic_class;
2910 MonoGenericContext context;
2913 memset (&context, 0, sizeof (context));
2914 if (gclass->context.class_inst)
2915 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
2916 if (gclass->context.method_inst)
2917 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
2919 k = mono_class_inflate_generic_class (gclass->container_class, &context);
2921 return get_shared_gparam (t, &k->byval_arg);
2922 } else if (MONO_TYPE_ISSTRUCT (type)) {
2926 /* Create a type variable with a constraint which encodes which types can match it */
2928 if (type->type == MONO_TYPE_VALUETYPE) {
2929 ttype = mono_class_enum_basetype (type->data.klass)->type;
2930 } else if (MONO_TYPE_IS_REFERENCE (type)) {
2931 ttype = MONO_TYPE_OBJECT;
2932 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
2933 if (type->data.generic_param->gshared_constraint)
2934 return get_shared_gparam (t, type->data.generic_param->gshared_constraint);
2935 ttype = MONO_TYPE_OBJECT;
2942 memset (&t2, 0, sizeof (t2));
2944 klass = mono_class_from_mono_type (&t2);
2946 return get_shared_gparam (t, &klass->byval_arg);
2951 get_gsharedvt_type (MonoType *t)
2953 /* Use TypeHandle as the constraint type since its a valuetype */
2954 return get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
2957 static MonoGenericInst*
2958 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
2960 MonoGenericInst *res;
2961 MonoType **type_argv;
2964 type_argv = g_new0 (MonoType*, inst->type_argc);
2965 for (i = 0; i < inst->type_argc; ++i) {
2966 if (all_vt || gsharedvt) {
2967 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2969 /* These types match the ones in generic_inst_is_sharable () */
2970 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
2974 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
2980 * mini_get_shared_method_full:
2982 * Return the method which is actually compiled/registered when doing generic sharing.
2983 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
2984 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
2985 * METHOD can be a non-inflated generic method.
2988 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
2991 MonoGenericContext shared_context;
2992 MonoMethod *declaring_method, *res;
2993 gboolean partial = FALSE;
2994 gboolean gsharedvt = FALSE;
2995 MonoGenericContainer *class_container, *method_container = NULL;
2996 MonoGenericContext *context = mono_method_get_context (method);
2997 MonoGenericInst *inst;
2999 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3000 declaring_method = method;
3002 declaring_method = mono_method_get_declaring_generic_method (method);
3005 /* shared_context is the context containing type variables. */
3006 if (declaring_method->is_generic)
3007 shared_context = mono_method_get_generic_container (declaring_method)->context;
3009 shared_context = declaring_method->klass->generic_container->context;
3012 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3014 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3016 class_container = declaring_method->klass->generic_container;
3017 method_container = mono_method_get_generic_container (declaring_method);
3020 * Create the shared context by replacing the ref type arguments with
3021 * type parameters, and keeping the rest.
3024 inst = context->class_inst;
3026 inst = shared_context.class_inst;
3028 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3031 inst = context->method_inst;
3033 inst = shared_context.method_inst;
3035 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3037 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3038 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3040 //printf ("%s\n", mono_method_full_name (res, 1));
3046 mini_get_shared_method (MonoMethod *method)
3048 return mini_get_shared_method_full (method, FALSE, FALSE);
3052 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3056 switch (entry->data->type) {
3057 case MONO_PATCH_INFO_CLASS:
3058 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));
3060 case MONO_PATCH_INFO_METHOD:
3061 case MONO_PATCH_INFO_METHODCONST:
3062 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));
3064 case MONO_PATCH_INFO_FIELD:
3065 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));
3067 case MONO_PATCH_INFO_SIGNATURE:
3068 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));
3070 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3071 MonoJumpInfoGSharedVtCall *call_info = g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3073 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3074 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3077 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3078 MonoGSharedVtMethodInfo *info;
3079 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3082 /* Make a copy into the domain mempool */
3083 info = g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3084 info->method = oinfo->method;
3085 info->num_entries = oinfo->num_entries;
3086 info->entries = g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3087 for (i = 0; i < oinfo->num_entries; ++i) {
3088 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3089 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
3091 memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3093 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3096 case MONO_PATCH_INFO_VIRT_METHOD: {
3097 MonoJumpInfoVirtMethod *info;
3098 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3100 info = g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3101 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3102 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3106 g_assert_not_reached ();
3113 #if defined(ENABLE_GSHAREDVT)
3115 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3120 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
3126 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
3132 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
3138 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
3144 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
3150 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3156 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3161 #endif /* !MONOTOUCH */