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 (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 (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 (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 (MonoMethod *method, gboolean allow_type_vars)
2311 if (!mono_class_generic_sharing_enabled (method->klass))
2314 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2317 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2320 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2321 method->klass->valuetype) &&
2322 (method->klass->generic_class || method->klass->generic_container);
2325 static MonoGenericInst*
2326 get_object_generic_inst (int type_argc)
2328 MonoType **type_argv;
2331 type_argv = alloca (sizeof (MonoType*) * type_argc);
2333 for (i = 0; i < type_argc; ++i)
2334 type_argv [i] = &mono_defaults.object_class->byval_arg;
2336 return mono_metadata_get_generic_inst (type_argc, type_argv);
2340 * mono_method_construct_object_context:
2343 * Returns a generic context for method with all type variables for
2344 * class and method instantiated with Object.
2347 mono_method_construct_object_context (MonoMethod *method)
2349 MonoGenericContext object_context;
2351 g_assert (!method->klass->generic_class);
2352 if (method->klass->generic_container) {
2353 int type_argc = method->klass->generic_container->type_argc;
2355 object_context.class_inst = get_object_generic_inst (type_argc);
2357 object_context.class_inst = NULL;
2360 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2361 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2363 object_context.method_inst = get_object_generic_inst (type_argc);
2365 object_context.method_inst = NULL;
2368 g_assert (object_context.class_inst || object_context.method_inst);
2370 return object_context;
2373 static gboolean gshared_supported;
2374 static gboolean gsharedvt_supported;
2377 mono_set_generic_sharing_supported (gboolean supported)
2379 gshared_supported = supported;
2383 mono_set_generic_sharing_vt_supported (gboolean supported)
2385 gsharedvt_supported = supported;
2389 mono_set_partial_sharing_supported (gboolean supported)
2391 partial_supported = supported;
2395 * mono_class_generic_sharing_enabled:
2398 * Returns whether generic sharing is enabled for class.
2400 * This is a stop-gap measure to slowly introduce generic sharing
2401 * until we have all the issues sorted out, at which time this
2402 * function will disappear and generic sharing will always be enabled.
2405 mono_class_generic_sharing_enabled (MonoClass *class)
2407 if (gshared_supported)
2414 * mono_get_generic_context_from_code:
2416 * Return the runtime generic context belonging to the method whose native code
2419 MonoGenericSharingContext*
2420 mono_get_generic_context_from_code (guint8 *code)
2422 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2424 g_assert (jit_info);
2426 return mono_jit_info_get_generic_sharing_context (jit_info);
2430 mini_method_get_context (MonoMethod *method)
2432 return mono_method_get_context_general (method, TRUE);
2436 * mono_method_check_context_used:
2439 * Checks whether the method's generic context uses a type variable.
2440 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2441 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2442 * context's class or method instantiation uses type variables.
2445 mono_method_check_context_used (MonoMethod *method)
2447 MonoGenericContext *method_context = mini_method_get_context (method);
2448 int context_used = 0;
2450 if (!method_context) {
2451 /* It might be a method of an array of an open generic type */
2452 if (method->klass->rank)
2453 context_used = mono_class_check_context_used (method->klass);
2455 context_used = mono_generic_context_check_used (method_context);
2456 context_used |= mono_class_check_context_used (method->klass);
2459 return context_used;
2463 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2474 if (inst1->type_argc != inst2->type_argc)
2477 for (i = 0; i < inst1->type_argc; ++i)
2478 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2485 * mono_generic_context_equal_deep:
2486 * @context1: a generic context
2487 * @context2: a generic context
2489 * Returns whether context1's type arguments are equal to context2's
2493 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2495 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2496 generic_inst_equal (context1->method_inst, context2->method_inst);
2500 * mini_class_get_container_class:
2501 * @class: a generic class
2503 * Returns the class's container class, which is the class itself if
2504 * it doesn't have generic_class set.
2507 mini_class_get_container_class (MonoClass *class)
2509 if (class->generic_class)
2510 return class->generic_class->container_class;
2512 g_assert (class->generic_container);
2517 * mini_class_get_context:
2518 * @class: a generic class
2520 * Returns the class's generic context.
2523 mini_class_get_context (MonoClass *class)
2525 if (class->generic_class)
2526 return &class->generic_class->context;
2528 g_assert (class->generic_container);
2529 return &class->generic_container->context;
2533 * mini_get_basic_type_from_generic:
2534 * @gsctx: a generic sharing context
2537 * Returns a closed type corresponding to the possibly open type
2541 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2543 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2545 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2548 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2550 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2551 MonoType *constraint = type->data.generic_param->gshared_constraint;
2552 /* The gparam serial encodes the type this gparam can represent */
2554 return &mono_defaults.object_class->byval_arg;
2558 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2559 klass = mono_class_from_mono_type (constraint);
2560 return &klass->byval_arg;
2563 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2568 * mini_type_get_underlying_type:
2570 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2574 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2576 type = mini_native_type_replace_type (type);
2579 return &mono_defaults.int_class->byval_arg;
2580 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2582 type = mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2583 switch (type->type) {
2584 case MONO_TYPE_BOOLEAN:
2585 return &mono_defaults.byte_class->byval_arg;
2586 case MONO_TYPE_CHAR:
2587 return &mono_defaults.uint16_class->byval_arg;
2594 * mini_type_stack_size:
2595 * @gsctx: a generic sharing context
2597 * @align: Pointer to an int for returning the alignment
2599 * Returns the type's stack size and the alignment in *align. The
2600 * type is allowed to be open.
2603 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2605 gboolean allow_open = TRUE;
2607 // FIXME: Some callers might not pass in a gsctx
2608 //allow_open = gsctx != NULL;
2609 return mono_type_stack_size_internal (t, align, allow_open);
2613 * mini_type_stack_size_full:
2615 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2618 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2623 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2627 //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2630 size = mono_type_native_stack_size (t, align);
2635 size = mini_type_stack_size (gsctx, t, &ialign);
2638 size = mini_type_stack_size (gsctx, t, NULL);
2646 * mono_generic_sharing_init:
2648 * Register the generic sharing counters.
2651 mono_generic_sharing_init (void)
2653 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2657 mono_generic_sharing_cleanup (void)
2659 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2661 if (generic_subclass_hash)
2662 g_hash_table_destroy (generic_subclass_hash);
2666 * mini_type_var_is_vt:
2668 * Return whenever T is a type variable instantiated with a vtype.
2671 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2673 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
2674 return type->data.generic_param->gshared_constraint && type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
2676 g_assert_not_reached ();
2682 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2684 if (cfg->generic_sharing_context)
2685 type = mini_get_underlying_type (cfg, type);
2686 return mono_type_is_reference (type);
2690 * mini_method_get_rgctx:
2692 * Return the RGCTX which needs to be passed to M when it is called.
2695 mini_method_get_rgctx (MonoMethod *m)
2697 if (mini_method_get_context (m)->method_inst)
2698 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2700 return mono_class_vtable (mono_domain_get (), m->klass);
2704 * mini_type_is_vtype:
2706 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2707 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2710 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2712 t = mini_get_underlying_type (cfg, t);
2714 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2718 mini_class_is_generic_sharable (MonoClass *klass)
2720 if (klass->generic_class && is_async_state_machine_class (klass))
2723 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2727 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2729 return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2733 mini_is_gsharedvt_gparam (MonoType *t)
2735 /* Matches get_gsharedvt_type () */
2736 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;
2740 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
2742 if (constraint == MONO_TYPE_VALUETYPE) {
2743 return g_strdup_printf ("%s_GSHAREDVT", name);
2744 } else if (constraint == MONO_TYPE_OBJECT) {
2745 return g_strdup_printf ("%s_REF", name);
2746 } else if (constraint == MONO_TYPE_GENERICINST) {
2747 return g_strdup_printf ("%s_INST", name);
2750 char *tname, *tname2, *res;
2752 memset (&t, 0, sizeof (t));
2753 t.type = constraint;
2754 tname = mono_type_full_name (&t);
2755 tname2 = g_utf8_strup (tname, strlen (tname));
2756 res = g_strdup_printf ("%s_%s", name, tname2);
2764 MonoGenericParam *par;
2765 MonoType *constraint;
2769 shared_gparam_hash (gconstpointer data)
2771 SharedGParam *p = (SharedGParam*)data;
2774 hash = mono_metadata_generic_param_hash (p->par);
2775 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->constraint);
2781 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
2783 SharedGParam *p1 = (SharedGParam*)ka;
2784 SharedGParam *p2 = (SharedGParam*)kb;
2788 if (p1->par != p2->par)
2790 if (!mono_metadata_type_equal (p1->constraint, p2->constraint))
2796 * get_shared_gparam:
2798 * Create an anonymous gparam with a type variable with a constraint which encodes which types can match it.
2801 get_shared_gparam (MonoType *t, MonoType *constraint)
2803 MonoGenericParam *par = t->data.generic_param;
2804 MonoGenericParam *copy;
2807 MonoImage *image = NULL;
2810 memset (&key, 0, sizeof (key));
2812 key.constraint = constraint;
2814 g_assert (mono_generic_param_info (par));
2815 /* image might not be set for sre */
2816 if (par->owner && par->owner->image) {
2817 image = par->owner->image;
2819 mono_image_lock (image);
2820 if (!image->gshared_types) {
2821 image->gshared_types_len = MONO_TYPE_INTERNAL;
2822 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
2824 if (!image->gshared_types [constraint->type])
2825 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
2826 res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
2827 mono_image_unlock (image);
2830 copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
2831 memcpy (copy, par, sizeof (MonoGenericParamFull));
2832 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
2833 ((MonoGenericParamFull*)copy)->info.name = mono_image_strdup (image, name);
2836 /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
2837 copy = (MonoGenericParam*)g_new0 (MonoGenericParamFull, 1);
2838 memcpy (copy, par, sizeof (MonoGenericParam));
2842 copy->image = mono_defaults.corlib;
2844 copy->gshared_constraint = constraint;
2845 res = mono_metadata_type_dup (NULL, t);
2846 res->data.generic_param = copy;
2851 dkey = mono_image_alloc0 (image, sizeof (SharedGParam));
2853 dkey->constraint = constraint;
2855 mono_image_lock (image);
2856 /* Duplicates are ok */
2857 g_hash_table_insert (image->gshared_types [constraint->type], dkey, res);
2858 mono_image_unlock (image);
2864 static MonoGenericInst*
2865 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
2868 get_shared_type (MonoType *t, MonoType *type)
2872 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2873 MonoGenericClass *gclass = type->data.generic_class;
2874 MonoGenericContext context;
2877 memset (&context, 0, sizeof (context));
2878 if (gclass->context.class_inst)
2879 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
2880 if (gclass->context.method_inst)
2881 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
2883 k = mono_class_inflate_generic_class (gclass->container_class, &context);
2885 return get_shared_gparam (t, &k->byval_arg);
2886 } else if (MONO_TYPE_ISSTRUCT (type)) {
2890 /* Create a type variable with a constraint which encodes which types can match it */
2892 if (type->type == MONO_TYPE_VALUETYPE) {
2893 ttype = mono_class_enum_basetype (type->data.klass)->type;
2894 } else if (MONO_TYPE_IS_REFERENCE (type)) {
2895 ttype = MONO_TYPE_OBJECT;
2896 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
2897 if (type->data.generic_param->gshared_constraint)
2898 return get_shared_gparam (t, type->data.generic_param->gshared_constraint);
2899 ttype = MONO_TYPE_OBJECT;
2906 memset (&t2, 0, sizeof (t2));
2908 klass = mono_class_from_mono_type (&t2);
2910 return get_shared_gparam (t, &klass->byval_arg);
2915 get_gsharedvt_type (MonoType *t)
2917 /* Use TypeHandle as the constraint type since its a valuetype */
2918 return get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
2921 static MonoGenericInst*
2922 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
2924 MonoGenericInst *res;
2925 MonoType **type_argv;
2928 type_argv = g_new0 (MonoType*, inst->type_argc);
2929 for (i = 0; i < inst->type_argc; ++i) {
2930 if (all_vt || gsharedvt) {
2931 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2933 /* These types match the ones in generic_inst_is_sharable () */
2934 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
2938 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
2944 * mini_get_shared_method_full:
2946 * Return the method which is actually compiled/registered when doing generic sharing.
2947 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
2948 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
2949 * METHOD can be a non-inflated generic method.
2952 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
2955 MonoGenericContext shared_context;
2956 MonoMethod *declaring_method, *res;
2957 gboolean partial = FALSE;
2958 gboolean gsharedvt = FALSE;
2959 MonoGenericContainer *class_container, *method_container = NULL;
2960 MonoGenericContext *context = mono_method_get_context (method);
2961 MonoGenericInst *inst;
2963 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
2964 declaring_method = method;
2966 declaring_method = mono_method_get_declaring_generic_method (method);
2969 /* shared_context is the context containing type variables. */
2970 if (declaring_method->is_generic)
2971 shared_context = mono_method_get_generic_container (declaring_method)->context;
2973 shared_context = declaring_method->klass->generic_container->context;
2976 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
2978 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
2980 class_container = declaring_method->klass->generic_container;
2981 method_container = mono_method_get_generic_container (declaring_method);
2984 * Create the shared context by replacing the ref type arguments with
2985 * type parameters, and keeping the rest.
2988 inst = context->class_inst;
2990 inst = shared_context.class_inst;
2992 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
2995 inst = context->method_inst;
2997 inst = shared_context.method_inst;
2999 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3001 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3002 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3004 //printf ("%s\n", mono_method_full_name (res, 1));
3010 mini_get_shared_method (MonoMethod *method)
3012 return mini_get_shared_method_full (method, FALSE, FALSE);
3016 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3020 switch (entry->data->type) {
3021 case MONO_PATCH_INFO_CLASS:
3022 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));
3024 case MONO_PATCH_INFO_METHOD:
3025 case MONO_PATCH_INFO_METHODCONST:
3026 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));
3028 case MONO_PATCH_INFO_FIELD:
3029 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));
3031 case MONO_PATCH_INFO_SIGNATURE:
3032 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));
3034 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3035 MonoJumpInfoGSharedVtCall *call_info = g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3037 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3038 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3041 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3042 MonoGSharedVtMethodInfo *info;
3043 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3046 /* Make a copy into the domain mempool */
3047 info = g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3048 info->method = oinfo->method;
3049 info->num_entries = oinfo->num_entries;
3050 info->entries = g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3051 for (i = 0; i < oinfo->num_entries; ++i) {
3052 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3053 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
3055 memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3057 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3060 case MONO_PATCH_INFO_VIRT_METHOD: {
3061 MonoJumpInfoVirtMethod *info;
3062 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3064 info = g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3065 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3066 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3070 g_assert_not_reached ();
3077 #if defined(ENABLE_GSHAREDVT)
3079 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3084 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
3090 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
3096 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
3102 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
3108 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
3114 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3120 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3125 #endif /* !MONOTOUCH */