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)->var_is_vt ||
1006 mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
1013 * Describes the information used to construct a gsharedvt arg trampoline.
1018 gint32 vcall_offset;
1020 MonoMethodSignature *sig, *gsig;
1021 MonoGenericContext gsctx;
1022 } GSharedVtTrampInfo;
1025 tramp_info_hash (gconstpointer key)
1027 GSharedVtTrampInfo *tramp = (gpointer)key;
1029 return (gsize)tramp->addr;
1033 tramp_info_equal (gconstpointer a, gconstpointer b)
1035 GSharedVtTrampInfo *tramp1 = (gpointer)a;
1036 GSharedVtTrampInfo *tramp2 = (gpointer)b;
1038 /* The signatures should be internalized */
1039 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1040 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
1041 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
1045 * mini_get_gsharedvt_wrapper:
1047 * Return a gsharedvt in/out wrapper for calling ADDR.
1050 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
1051 gint32 vcall_offset, gboolean calli)
1053 static gboolean inited = FALSE;
1054 static int num_trampolines;
1056 MonoDomain *domain = mono_domain_get ();
1057 MonoJitDomainInfo *domain_info;
1058 GSharedVtTrampInfo *tramp_info;
1059 GSharedVtTrampInfo tinfo;
1062 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1066 tinfo.is_in = gsharedvt_in;
1067 tinfo.calli = calli;
1068 tinfo.vcall_offset = vcall_offset;
1070 tinfo.sig = normal_sig;
1071 tinfo.gsig = gsharedvt_sig;
1072 memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
1074 domain_info = domain_jit_info (domain);
1077 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1079 mono_domain_lock (domain);
1080 if (!domain_info->gsharedvt_arg_tramp_hash)
1081 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1082 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1083 mono_domain_unlock (domain);
1087 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1090 static gpointer tramp_addr;
1091 MonoMethod *wrapper;
1094 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1095 addr = mono_compile_method (wrapper);
1096 mono_memory_barrier ();
1101 static gpointer tramp_addr;
1102 MonoMethod *wrapper;
1105 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1106 addr = mono_compile_method (wrapper);
1107 mono_memory_barrier ();
1114 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1116 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1121 tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1122 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1124 mono_domain_lock (domain);
1125 /* Duplicates are not a problem */
1126 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1127 mono_domain_unlock (domain);
1133 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1134 MonoGenericContext *context, MonoClass *class, guint8 *caller)
1142 switch (oti->info_type) {
1143 case MONO_RGCTX_INFO_STATIC_DATA:
1144 case MONO_RGCTX_INFO_KLASS:
1145 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1146 case MONO_RGCTX_INFO_VTABLE:
1147 case MONO_RGCTX_INFO_CAST_CACHE:
1154 data = inflate_info (oti, context, class, temporary);
1156 switch (oti->info_type) {
1157 case MONO_RGCTX_INFO_STATIC_DATA:
1158 case MONO_RGCTX_INFO_KLASS:
1159 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1160 case MONO_RGCTX_INFO_VTABLE:
1161 case MONO_RGCTX_INFO_CAST_CACHE:
1162 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1163 case MONO_RGCTX_INFO_VALUE_SIZE:
1164 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1165 case MONO_RGCTX_INFO_MEMCPY:
1166 case MONO_RGCTX_INFO_BZERO:
1167 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1168 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1169 MonoClass *arg_class = mono_class_from_mono_type (data);
1171 free_inflated_info (oti->info_type, data);
1172 g_assert (arg_class);
1174 /* The class might be used as an argument to
1175 mono_value_copy(), which requires that its GC
1176 descriptor has been computed. */
1177 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1178 mono_class_compute_gc_descriptor (arg_class);
1180 return class_type_info (domain, arg_class, oti->info_type);
1182 case MONO_RGCTX_INFO_TYPE:
1184 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1185 return mono_type_get_object (domain, data);
1186 case MONO_RGCTX_INFO_METHOD:
1188 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1191 addr = mono_compile_method (data);
1192 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1194 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1195 MonoJumpInfoVirtMethod *info = data;
1196 MonoClass *iface_class = info->method->klass;
1201 mono_class_setup_vtable (info->klass);
1202 // FIXME: Check type load
1203 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1204 ioffset = mono_class_interface_offset (info->klass, iface_class);
1205 g_assert (ioffset != -1);
1209 slot = mono_method_get_vtable_slot (info->method);
1210 g_assert (slot != -1);
1211 g_assert (info->klass->vtable);
1212 method = info->klass->vtable [ioffset + slot];
1214 addr = mono_compile_method (method);
1215 return mini_add_method_trampoline (NULL, method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1217 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1218 MonoJumpInfoVirtMethod *info = data;
1219 MonoClass *iface_class = info->method->klass;
1221 MonoClass *impl_class;
1224 mono_class_setup_vtable (info->klass);
1225 // FIXME: Check type load
1226 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1227 ioffset = mono_class_interface_offset (info->klass, iface_class);
1228 g_assert (ioffset != -1);
1232 slot = mono_method_get_vtable_slot (info->method);
1233 g_assert (slot != -1);
1234 g_assert (info->klass->vtable);
1235 method = info->klass->vtable [ioffset + slot];
1237 impl_class = method->klass;
1238 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1239 return GUINT_TO_POINTER (1);
1240 else if (mono_class_is_nullable (impl_class))
1241 return GUINT_TO_POINTER (2);
1243 return GUINT_TO_POINTER (0);
1245 #ifndef DISABLE_REMOTING
1246 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1247 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1249 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1250 return mono_domain_alloc0 (domain, sizeof (gpointer));
1251 case MONO_RGCTX_INFO_CLASS_FIELD:
1253 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1254 MonoClassField *field = data;
1256 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1257 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1259 return GUINT_TO_POINTER (field->offset);
1261 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1262 MonoMethodInflated *method = data;
1265 g_assert (method->method.method.is_inflated);
1266 g_assert (method->context.method_inst);
1268 vtable = mono_class_vtable (domain, method->method.method.klass);
1270 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1272 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1274 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1275 MonoMethodInflated *method = data;
1277 g_assert (method->method.method.is_inflated);
1278 g_assert (method->context.method_inst);
1280 return method->context.method_inst;
1282 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1283 MonoMethodSignature *gsig = oti->data;
1284 MonoMethodSignature *sig = data;
1286 MonoJitInfo *caller_ji;
1287 MonoGenericJitInfo *gji;
1290 * This is an indirect call to the address passed by the caller in the rgctx reg.
1292 //printf ("CALLI\n");
1295 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1296 g_assert (caller_ji);
1297 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1300 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1304 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1305 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1306 MonoJumpInfoGSharedVtCall *call_info = data;
1307 MonoMethodSignature *call_sig;
1310 MonoJitInfo *caller_ji, *callee_ji;
1311 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1312 gint32 vcall_offset;
1313 MonoGenericJitInfo *gji, *callee_gji = NULL;
1314 gboolean callee_gsharedvt;
1316 /* This is the original generic signature used by the caller */
1317 call_sig = call_info->sig;
1318 /* This is the instantiated method which is called */
1319 method = call_info->method;
1321 g_assert (method->is_inflated);
1324 addr = mono_compile_method (method);
1329 /* Same as in mono_emit_method_call_full () */
1330 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1331 /* See mono_emit_method_call_full () */
1332 /* The gsharedvt trampoline will recognize this constant */
1333 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1334 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1335 guint32 imt_slot = mono_method_get_imt_slot (method);
1336 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1338 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1339 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1346 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1347 g_assert (caller_ji);
1348 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1351 // FIXME: This loads information in the AOT case
1352 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1353 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1354 if (callee_gsharedvt) {
1355 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1356 g_assert (callee_gji);
1360 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1361 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1362 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1363 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1364 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1365 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1366 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1367 * caller -> out trampoline -> in trampoline -> callee
1368 * This is not very efficient, but it is easy to implement.
1370 if (virtual || !callee_gsharedvt) {
1371 MonoMethodSignature *sig, *gsig;
1373 g_assert (method->is_inflated);
1375 sig = mono_method_signature (method);
1378 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1381 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1383 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1385 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1386 } else if (callee_gsharedvt) {
1387 MonoMethodSignature *sig, *gsig;
1390 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1391 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1394 * public void foo<T1> (T1 t1, T t, object o) {}
1396 * class AClass : Base<long> {
1397 * public void bar<T> (T t, long time, object o) {
1401 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1402 * FIXME: Optimize this.
1405 if (call_sig == mono_method_signature (method)) {
1407 sig = mono_method_signature (method);
1408 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1410 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1412 sig = mono_method_signature (method);
1415 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1417 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1423 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1424 MonoGSharedVtMethodInfo *info = data;
1425 MonoGSharedVtMethodRuntimeInfo *res;
1427 int i, offset, align, size;
1430 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1433 for (i = 0; i < info->num_entries; ++i) {
1434 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1436 switch (template->info_type) {
1437 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1440 size = mono_type_size (t, &align);
1442 if (align < sizeof (gpointer))
1443 align = sizeof (gpointer);
1444 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1445 align = 2 * sizeof (gpointer);
1447 // FIXME: Do the same things as alloc_stack_slots
1448 offset += align - 1;
1449 offset &= ~(align - 1);
1450 res->entries [i] = GINT_TO_POINTER (offset);
1454 res->entries [i] = instantiate_info (domain, template, context, class, NULL);
1458 res->locals_size = offset;
1463 g_assert_not_reached ();
1470 * LOCKING: loader lock
1473 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1475 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1476 MonoClass *subclass;
1478 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1480 /* Recurse for all subclasses */
1481 if (generic_subclass_hash)
1482 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1487 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1488 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1490 g_assert (subclass_template);
1492 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1493 g_assert (subclass_oti.data);
1495 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1497 subclass = subclass_template->next_subclass;
1502 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1505 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1506 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1507 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1508 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1509 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1510 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1511 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1512 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1513 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1514 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1515 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1516 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1517 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1518 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1519 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1520 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1521 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1522 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1523 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1524 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1525 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1526 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1527 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1528 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1529 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1530 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1531 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1532 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1534 return "<UNKNOWN RGCTX INFO TYPE>";
1538 G_GNUC_UNUSED static char*
1539 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1541 switch (info_type) {
1542 case MONO_RGCTX_INFO_VTABLE:
1543 return mono_type_full_name ((MonoType*)data);
1545 return g_strdup_printf ("<%p>", data);
1550 * LOCKING: loader lock
1553 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1556 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1558 MonoRuntimeGenericContextInfoTemplate *oti;
1560 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1565 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)));
1567 /* Mark the slot as used in all parent classes (until we find
1568 a parent class which already has it marked used). */
1569 parent = class->parent;
1570 while (parent != NULL) {
1571 MonoRuntimeGenericContextTemplate *parent_template;
1572 MonoRuntimeGenericContextInfoTemplate *oti;
1574 if (parent->generic_class)
1575 parent = parent->generic_class->container_class;
1577 parent_template = mono_class_get_runtime_generic_context_template (parent);
1578 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1580 if (oti && oti->data)
1583 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1584 MONO_RGCTX_SLOT_USED_MARKER, 0);
1586 parent = parent->parent;
1589 /* Fill in the slot in this class and in all subclasses
1591 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1597 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1599 switch (info_type) {
1600 case MONO_RGCTX_INFO_STATIC_DATA:
1601 case MONO_RGCTX_INFO_KLASS:
1602 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1603 case MONO_RGCTX_INFO_VTABLE:
1604 case MONO_RGCTX_INFO_TYPE:
1605 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1606 case MONO_RGCTX_INFO_CAST_CACHE:
1607 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1608 case MONO_RGCTX_INFO_VALUE_SIZE:
1609 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1610 case MONO_RGCTX_INFO_MEMCPY:
1611 case MONO_RGCTX_INFO_BZERO:
1612 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1613 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1614 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1615 case MONO_RGCTX_INFO_METHOD:
1616 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1617 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1618 case MONO_RGCTX_INFO_CLASS_FIELD:
1619 case MONO_RGCTX_INFO_FIELD_OFFSET:
1620 case MONO_RGCTX_INFO_METHOD_RGCTX:
1621 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1622 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1623 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1624 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1625 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1626 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1627 return data1 == data2;
1628 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
1629 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1630 MonoJumpInfoVirtMethod *info1 = data1;
1631 MonoJumpInfoVirtMethod *info2 = data2;
1633 return info1->klass == info2->klass && info1->method == info2->method;
1636 g_assert_not_reached ();
1643 * mini_rgctx_info_type_to_patch_info_type:
1645 * Return the type of the runtime object referred to by INFO_TYPE.
1648 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1650 switch (info_type) {
1651 case MONO_RGCTX_INFO_STATIC_DATA:
1652 case MONO_RGCTX_INFO_KLASS:
1653 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1654 case MONO_RGCTX_INFO_VTABLE:
1655 case MONO_RGCTX_INFO_TYPE:
1656 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1657 case MONO_RGCTX_INFO_CAST_CACHE:
1658 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1659 case MONO_RGCTX_INFO_VALUE_SIZE:
1660 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1661 case MONO_RGCTX_INFO_MEMCPY:
1662 case MONO_RGCTX_INFO_BZERO:
1663 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1664 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1665 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1666 return MONO_PATCH_INFO_CLASS;
1667 case MONO_RGCTX_INFO_FIELD_OFFSET:
1668 return MONO_PATCH_INFO_FIELD;
1670 g_assert_not_reached ();
1676 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1677 MonoGenericContext *generic_context)
1679 static gboolean inited = FALSE;
1680 static int max_slot = 0;
1682 MonoRuntimeGenericContextTemplate *rgctx_template =
1683 mono_class_get_runtime_generic_context_template (class);
1684 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1687 class = get_shared_class (class);
1689 mono_loader_lock ();
1691 if (info_has_identity (info_type)) {
1692 oti_list = get_info_templates (rgctx_template, type_argc);
1694 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1695 gpointer inflated_data;
1697 if (oti->info_type != info_type || !oti->data)
1700 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1702 if (info_equal (data, inflated_data, info_type)) {
1703 free_inflated_info (info_type, inflated_data);
1704 mono_loader_unlock ();
1707 free_inflated_info (info_type, inflated_data);
1711 /* We haven't found the info */
1712 i = register_info (class, type_argc, data, info_type);
1714 mono_loader_unlock ();
1717 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1727 * mono_method_lookup_or_register_info:
1729 * @in_mrgctx: whether to put the data into the MRGCTX
1730 * @data: the info data
1731 * @info_type: the type of info to register about data
1732 * @generic_context: a generic context
1734 * Looks up and, if necessary, adds information about data/info_type in
1735 * method's or method's class runtime generic context. Returns the
1736 * encoded slot number.
1739 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1740 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1742 MonoClass *class = method->klass;
1743 int type_argc, index;
1746 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1748 g_assert (method->is_inflated && method_inst);
1749 type_argc = method_inst->type_argc;
1750 g_assert (type_argc > 0);
1755 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1757 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1760 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1762 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1766 * mono_class_rgctx_get_array_size:
1767 * @n: The number of the array
1768 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1770 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1771 * number includes the slot for linking and - for MRGCTXs - the two
1772 * slots in the first array for additional information.
1775 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1777 g_assert (n >= 0 && n < 30);
1786 * LOCKING: domain lock
1789 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1791 static gboolean inited = FALSE;
1792 static int rgctx_num_alloced = 0;
1793 static int rgctx_bytes_alloced = 0;
1794 static int mrgctx_num_alloced = 0;
1795 static int mrgctx_bytes_alloced = 0;
1797 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1798 gpointer array = mono_domain_alloc0 (domain, size);
1801 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1802 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1803 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1804 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1809 mrgctx_num_alloced++;
1810 mrgctx_bytes_alloced += size;
1812 rgctx_num_alloced++;
1813 rgctx_bytes_alloced += size;
1820 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1821 MonoGenericInst *method_inst)
1824 int i, first_slot, size;
1825 MonoDomain *domain = class_vtable->domain;
1826 MonoClass *class = class_vtable->klass;
1827 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1828 MonoRuntimeGenericContextInfoTemplate oti;
1829 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1835 mono_domain_lock (domain);
1837 /* First check whether that slot isn't already instantiated.
1838 This might happen because lookup doesn't lock. Allocate
1839 arrays on the way. */
1841 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1843 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1844 for (i = 0; ; ++i) {
1847 if (method_inst && i == 0)
1848 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1852 if (slot < first_slot + size - 1) {
1853 rgctx_index = slot - first_slot + 1 + offset;
1854 info = rgctx [rgctx_index];
1856 mono_domain_unlock (domain);
1861 if (!rgctx [offset + 0])
1862 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1863 rgctx = rgctx [offset + 0];
1864 first_slot += size - 1;
1865 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1868 g_assert (!rgctx [rgctx_index]);
1870 mono_domain_unlock (domain);
1872 oti = class_get_rgctx_template_oti (get_shared_class (class),
1873 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1874 /* This might take the loader lock */
1875 info = instantiate_info (domain, &oti, &context, class, caller);
1879 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1882 /*FIXME We should use CAS here, no need to take a lock.*/
1883 mono_domain_lock (domain);
1885 /* Check whether the slot hasn't been instantiated in the
1887 if (rgctx [rgctx_index])
1888 info = rgctx [rgctx_index];
1890 rgctx [rgctx_index] = info;
1892 mono_domain_unlock (domain);
1895 free_inflated_info (oti.info_type, oti.data);
1901 * mono_class_fill_runtime_generic_context:
1902 * @class_vtable: a vtable
1903 * @caller: caller method address
1904 * @slot: a slot index to be instantiated
1906 * Instantiates a slot in the RGCTX, returning its value.
1909 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1911 static gboolean inited = FALSE;
1912 static int num_alloced = 0;
1914 MonoDomain *domain = class_vtable->domain;
1915 MonoRuntimeGenericContext *rgctx;
1918 mono_domain_lock (domain);
1921 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1925 rgctx = class_vtable->runtime_generic_context;
1927 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1928 class_vtable->runtime_generic_context = rgctx;
1932 mono_domain_unlock (domain);
1934 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1936 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1942 * mono_method_fill_runtime_generic_context:
1943 * @mrgctx: an MRGCTX
1944 * @caller: caller method address
1945 * @slot: a slot index to be instantiated
1947 * Instantiates a slot in the MRGCTX.
1950 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1954 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1955 mrgctx->method_inst);
1961 mrgctx_hash_func (gconstpointer key)
1963 const MonoMethodRuntimeGenericContext *mrgctx = key;
1965 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1969 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1971 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1972 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1974 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1975 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1979 * mono_method_lookup_rgctx:
1980 * @class_vtable: a vtable
1981 * @method_inst: the method inst of a generic method
1983 * Returns the MRGCTX for the generic method(s) with the given
1984 * method_inst of the given class_vtable.
1986 * LOCKING: Take the domain lock.
1988 MonoMethodRuntimeGenericContext*
1989 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1991 MonoDomain *domain = class_vtable->domain;
1992 MonoMethodRuntimeGenericContext *mrgctx;
1993 MonoMethodRuntimeGenericContext key;
1995 g_assert (!class_vtable->klass->generic_container);
1996 g_assert (!method_inst->is_open);
1998 mono_domain_lock (domain);
1999 if (!domain->method_rgctx_hash)
2000 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2002 key.class_vtable = class_vtable;
2003 key.method_inst = method_inst;
2005 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
2010 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2011 mrgctx->class_vtable = class_vtable;
2012 mrgctx->method_inst = method_inst;
2014 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2017 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2018 for (i = 0; i < method_inst->type_argc; ++i)
2019 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2024 mono_domain_unlock (domain);
2033 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2034 gboolean allow_partial);
2037 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2039 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
2042 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2043 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)))
2046 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2047 MonoGenericClass *gclass = type->data.generic_class;
2049 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2051 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2053 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2062 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2063 gboolean allow_partial)
2067 for (i = 0; i < inst->type_argc; ++i) {
2068 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2076 * mono_is_partially_sharable_inst:
2078 * Return TRUE if INST has ref and non-ref type arguments.
2081 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2084 gboolean has_refs = FALSE, has_non_refs = FALSE;
2086 for (i = 0; i < inst->type_argc; ++i) {
2087 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)
2090 has_non_refs = TRUE;
2093 return has_refs && has_non_refs;
2097 * mono_generic_context_is_sharable_full:
2098 * @context: a generic context
2100 * Returns whether the generic context is sharable. A generic context
2101 * is sharable iff all of its type arguments are reference type, or some of them have a
2102 * reference type, and ALLOW_PARTIAL is TRUE.
2105 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2106 gboolean allow_type_vars,
2107 gboolean allow_partial)
2109 g_assert (context->class_inst || context->method_inst);
2111 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2114 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2121 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2123 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2127 * mono_method_is_generic_impl:
2130 * Returns whether the method is either generic or part of a generic
2134 mono_method_is_generic_impl (MonoMethod *method)
2136 if (method->is_inflated)
2138 /* We don't treat wrappers as generic code, i.e., we never
2139 apply generic sharing to them. This is especially
2140 important for static rgctx invoke wrappers, which only work
2141 if not compiled with sharing. */
2142 if (method->wrapper_type != MONO_WRAPPER_NONE)
2144 if (method->klass->generic_container)
2150 has_constraints (MonoGenericContainer *container)
2156 g_assert (container->type_argc > 0);
2157 g_assert (container->type_params);
2159 for (i = 0; i < container->type_argc; ++i)
2160 if (container->type_params [i].constraints)
2167 mini_method_is_open (MonoMethod *method)
2169 if (method->is_inflated) {
2170 MonoGenericContext *ctx = mono_method_get_context (method);
2172 if (ctx->class_inst && ctx->class_inst->is_open)
2174 if (ctx->method_inst && ctx->method_inst->is_open)
2180 static G_GNUC_UNUSED gboolean
2181 is_async_state_machine_class (MonoClass *klass)
2183 static MonoClass *iclass;
2184 static gboolean iclass_set;
2189 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2190 mono_memory_barrier ();
2194 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2199 static G_GNUC_UNUSED gboolean
2200 is_async_method (MonoMethod *method)
2202 MonoCustomAttrInfo *cattr;
2203 MonoMethodSignature *sig;
2204 gboolean res = FALSE;
2205 static MonoClass *attr_class;
2206 static gboolean attr_class_set;
2210 if (!attr_class_set) {
2211 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2212 mono_memory_barrier ();
2213 attr_class_set = TRUE;
2216 /* Do less expensive checks first */
2217 sig = mono_method_signature (method);
2218 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2219 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2220 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2221 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2222 cattr = mono_custom_attrs_from_method (method);
2224 if (mono_custom_attrs_has_attr (cattr, attr_class))
2226 mono_custom_attrs_free (cattr);
2233 * mono_method_is_generic_sharable_full:
2235 * @allow_type_vars: whether to regard type variables as reference types
2236 * @allow_partial: whether to allow partial sharing
2237 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2239 * Returns TRUE iff the method is inflated or part of an inflated
2240 * class, its context is sharable and it has no constraints on its
2241 * type parameters. Otherwise returns FALSE.
2244 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2245 gboolean allow_partial, gboolean allow_gsharedvt)
2247 if (!mono_method_is_generic_impl (method))
2250 if (!partial_sharing_supported ())
2251 allow_partial = FALSE;
2253 if (mono_class_is_nullable (method->klass))
2255 allow_partial = FALSE;
2257 if (method->klass->image->dynamic)
2259 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2260 * instance_size is 0.
2262 allow_partial = FALSE;
2265 * Generic async methods have an associated state machine class which is a generic struct. This struct
2266 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2267 * of the async method and the state machine class.
2269 if (is_async_state_machine_class (method->klass))
2272 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2273 if (is_async_method (method))
2278 if (method->is_inflated) {
2279 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2280 MonoGenericContext *context = &inflated->context;
2282 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2285 g_assert (inflated->declaring);
2287 if (inflated->declaring->is_generic) {
2288 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2293 if (method->klass->generic_class) {
2294 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2297 g_assert (method->klass->generic_class->container_class &&
2298 method->klass->generic_class->container_class->generic_container);
2300 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2304 if (method->klass->generic_container && !allow_type_vars)
2307 /* This does potentially expensive cattr checks, so do it at the end */
2308 if (is_async_method (method)) {
2309 if (mini_method_is_open (method))
2310 /* The JIT can't compile these without sharing */
2319 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2321 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2325 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2327 if (!mono_class_generic_sharing_enabled (method->klass))
2330 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2333 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2336 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2337 method->klass->valuetype) &&
2338 (method->klass->generic_class || method->klass->generic_container);
2341 static MonoGenericInst*
2342 get_object_generic_inst (int type_argc)
2344 MonoType **type_argv;
2347 type_argv = alloca (sizeof (MonoType*) * type_argc);
2349 for (i = 0; i < type_argc; ++i)
2350 type_argv [i] = &mono_defaults.object_class->byval_arg;
2352 return mono_metadata_get_generic_inst (type_argc, type_argv);
2356 * mono_method_construct_object_context:
2359 * Returns a generic context for method with all type variables for
2360 * class and method instantiated with Object.
2363 mono_method_construct_object_context (MonoMethod *method)
2365 MonoGenericContext object_context;
2367 g_assert (!method->klass->generic_class);
2368 if (method->klass->generic_container) {
2369 int type_argc = method->klass->generic_container->type_argc;
2371 object_context.class_inst = get_object_generic_inst (type_argc);
2373 object_context.class_inst = NULL;
2376 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2377 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2379 object_context.method_inst = get_object_generic_inst (type_argc);
2381 object_context.method_inst = NULL;
2384 g_assert (object_context.class_inst || object_context.method_inst);
2386 return object_context;
2389 static gboolean gshared_supported;
2390 static gboolean gsharedvt_supported;
2393 mono_set_generic_sharing_supported (gboolean supported)
2395 gshared_supported = supported;
2399 mono_set_generic_sharing_vt_supported (gboolean supported)
2401 gsharedvt_supported = supported;
2405 mono_set_partial_sharing_supported (gboolean supported)
2407 partial_supported = supported;
2411 * mono_class_generic_sharing_enabled:
2414 * Returns whether generic sharing is enabled for class.
2416 * This is a stop-gap measure to slowly introduce generic sharing
2417 * until we have all the issues sorted out, at which time this
2418 * function will disappear and generic sharing will always be enabled.
2421 mono_class_generic_sharing_enabled (MonoClass *class)
2423 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2424 static gboolean inited = FALSE;
2429 if (gshared_supported)
2430 generic_sharing = MONO_GENERIC_SHARING_ALL;
2432 generic_sharing = MONO_GENERIC_SHARING_NONE;
2434 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2435 if (strcmp (option, "corlib") == 0)
2436 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2437 else if (strcmp (option, "collections") == 0)
2438 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2439 else if (strcmp (option, "all") == 0)
2440 generic_sharing = MONO_GENERIC_SHARING_ALL;
2441 else if (strcmp (option, "none") == 0)
2442 generic_sharing = MONO_GENERIC_SHARING_NONE;
2444 g_warning ("Unknown generic sharing option `%s'.", option);
2447 if (!gshared_supported)
2448 generic_sharing = MONO_GENERIC_SHARING_NONE;
2453 switch (generic_sharing) {
2454 case MONO_GENERIC_SHARING_NONE:
2456 case MONO_GENERIC_SHARING_ALL:
2458 case MONO_GENERIC_SHARING_CORLIB :
2459 return class->image == mono_defaults.corlib;
2460 case MONO_GENERIC_SHARING_COLLECTIONS:
2461 if (class->image != mono_defaults.corlib)
2463 while (class->nested_in)
2464 class = class->nested_in;
2465 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2467 g_assert_not_reached ();
2473 * mono_get_generic_context_from_code:
2475 * Return the runtime generic context belonging to the method whose native code
2478 MonoGenericSharingContext*
2479 mono_get_generic_context_from_code (guint8 *code)
2481 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2483 g_assert (jit_info);
2485 return mono_jit_info_get_generic_sharing_context (jit_info);
2489 mini_method_get_context (MonoMethod *method)
2491 return mono_method_get_context_general (method, TRUE);
2495 * mono_method_check_context_used:
2498 * Checks whether the method's generic context uses a type variable.
2499 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2500 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2501 * context's class or method instantiation uses type variables.
2504 mono_method_check_context_used (MonoMethod *method)
2506 MonoGenericContext *method_context = mini_method_get_context (method);
2507 int context_used = 0;
2509 if (!method_context) {
2510 /* It might be a method of an array of an open generic type */
2511 if (method->klass->rank)
2512 context_used = mono_class_check_context_used (method->klass);
2514 context_used = mono_generic_context_check_used (method_context);
2515 context_used |= mono_class_check_context_used (method->klass);
2518 return context_used;
2522 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2533 if (inst1->type_argc != inst2->type_argc)
2536 for (i = 0; i < inst1->type_argc; ++i)
2537 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2544 * mono_generic_context_equal_deep:
2545 * @context1: a generic context
2546 * @context2: a generic context
2548 * Returns whether context1's type arguments are equal to context2's
2552 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2554 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2555 generic_inst_equal (context1->method_inst, context2->method_inst);
2559 * mini_class_get_container_class:
2560 * @class: a generic class
2562 * Returns the class's container class, which is the class itself if
2563 * it doesn't have generic_class set.
2566 mini_class_get_container_class (MonoClass *class)
2568 if (class->generic_class)
2569 return class->generic_class->container_class;
2571 g_assert (class->generic_container);
2576 * mini_class_get_context:
2577 * @class: a generic class
2579 * Returns the class's generic context.
2582 mini_class_get_context (MonoClass *class)
2584 if (class->generic_class)
2585 return &class->generic_class->context;
2587 g_assert (class->generic_container);
2588 return &class->generic_container->context;
2592 * mini_get_basic_type_from_generic:
2593 * @gsctx: a generic sharing context
2596 * Returns a closed type corresponding to the possibly open type
2600 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2602 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2604 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2607 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2609 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2610 MonoType *constraint = type->data.generic_param->gshared_constraint;
2611 /* The gparam serial encodes the type this gparam can represent */
2613 return &mono_defaults.object_class->byval_arg;
2617 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2618 klass = mono_class_from_mono_type (constraint);
2619 return &klass->byval_arg;
2622 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2627 * mini_type_get_underlying_type:
2629 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2633 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2635 type = mini_native_type_replace_type (type);
2638 return &mono_defaults.int_class->byval_arg;
2639 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2641 type = mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2642 switch (type->type) {
2643 case MONO_TYPE_BOOLEAN:
2644 return &mono_defaults.byte_class->byval_arg;
2645 case MONO_TYPE_CHAR:
2646 return &mono_defaults.uint16_class->byval_arg;
2653 * mini_type_stack_size:
2654 * @gsctx: a generic sharing context
2656 * @align: Pointer to an int for returning the alignment
2658 * Returns the type's stack size and the alignment in *align. The
2659 * type is allowed to be open.
2662 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2664 gboolean allow_open = TRUE;
2666 // FIXME: Some callers might not pass in a gsctx
2667 //allow_open = gsctx != NULL;
2668 return mono_type_stack_size_internal (t, align, allow_open);
2672 * mini_type_stack_size_full:
2674 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2677 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2682 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2686 //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2689 size = mono_type_native_stack_size (t, align);
2694 size = mini_type_stack_size (gsctx, t, &ialign);
2697 size = mini_type_stack_size (gsctx, t, NULL);
2705 * mono_generic_sharing_init:
2707 * Register the generic sharing counters.
2710 mono_generic_sharing_init (void)
2712 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2716 mono_generic_sharing_cleanup (void)
2718 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2720 if (generic_subclass_hash)
2721 g_hash_table_destroy (generic_subclass_hash);
2725 * mini_type_var_is_vt:
2727 * Return whenever T is a type variable instantiated with a vtype.
2730 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2732 if (type->type == MONO_TYPE_VAR) {
2733 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2737 } else if (type->type == MONO_TYPE_MVAR) {
2738 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2743 g_assert_not_reached ();
2749 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2751 if (cfg->generic_sharing_context)
2752 type = mini_get_underlying_type (cfg, type);
2753 return mono_type_is_reference (type);
2757 * mini_method_get_rgctx:
2759 * Return the RGCTX which needs to be passed to M when it is called.
2762 mini_method_get_rgctx (MonoMethod *m)
2764 if (mini_method_get_context (m)->method_inst)
2765 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2767 return mono_class_vtable (mono_domain_get (), m->klass);
2771 * mini_type_is_vtype:
2773 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2774 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2777 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2779 t = mini_native_type_replace_type (t);
2781 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2785 mini_class_is_generic_sharable (MonoClass *klass)
2787 if (klass->generic_class && is_async_state_machine_class (klass))
2790 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2794 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2796 return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2800 mini_is_gsharedvt_gparam (MonoType *t)
2802 /* Matches get_gsharedvt_type () */
2803 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;
2807 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
2809 if (constraint == MONO_TYPE_VALUETYPE) {
2810 return g_strdup_printf ("%s_GSHAREDVT", name);
2811 } else if (constraint == MONO_TYPE_OBJECT) {
2812 return g_strdup_printf ("%s_REF", name);
2813 } else if (constraint == MONO_TYPE_GENERICINST) {
2814 return g_strdup_printf ("%s_INST", name);
2817 char *tname, *tname2, *res;
2819 memset (&t, 0, sizeof (t));
2820 t.type = constraint;
2821 tname = mono_type_full_name (&t);
2822 tname2 = g_utf8_strup (tname, strlen (tname));
2823 res = g_strdup_printf ("%s_%s", name, tname2);
2831 MonoGenericParam *par;
2832 MonoType *constraint;
2836 shared_gparam_hash (gconstpointer data)
2838 SharedGParam *p = (SharedGParam*)data;
2841 hash = mono_metadata_generic_param_hash (p->par);
2842 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->constraint);
2848 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
2850 SharedGParam *p1 = (SharedGParam*)ka;
2851 SharedGParam *p2 = (SharedGParam*)kb;
2855 if (p1->par != p2->par)
2857 if (!mono_metadata_type_equal (p1->constraint, p2->constraint))
2863 * get_shared_gparam:
2865 * Create an anonymous gparam with a type variable with a constraint which encodes which types can match it.
2868 get_shared_gparam (MonoType *t, MonoType *constraint)
2870 MonoGenericParam *par = t->data.generic_param;
2871 MonoGenericParam *copy;
2874 MonoImage *image = NULL;
2877 memset (&key, 0, sizeof (key));
2879 key.constraint = constraint;
2881 g_assert (mono_generic_param_info (par));
2882 /* image might not be set for sre */
2883 if (par->owner && par->owner->image) {
2884 image = par->owner->image;
2886 mono_image_lock (image);
2887 if (!image->gshared_types) {
2888 image->gshared_types_len = MONO_TYPE_INTERNAL;
2889 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
2891 if (!image->gshared_types [constraint->type])
2892 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
2893 res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
2894 mono_image_unlock (image);
2897 copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
2898 memcpy (copy, par, sizeof (MonoGenericParamFull));
2899 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
2900 ((MonoGenericParamFull*)copy)->info.name = mono_image_strdup (image, name);
2903 /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
2904 copy = (MonoGenericParam*)g_new0 (MonoGenericParamFull, 1);
2905 memcpy (copy, par, sizeof (MonoGenericParam));
2909 copy->image = mono_defaults.corlib;
2911 copy->gshared_constraint = constraint;
2912 res = mono_metadata_type_dup (NULL, t);
2913 res->data.generic_param = copy;
2918 dkey = mono_image_alloc0 (image, sizeof (SharedGParam));
2920 dkey->constraint = constraint;
2922 mono_image_lock (image);
2923 /* Duplicates are ok */
2924 g_hash_table_insert (image->gshared_types [constraint->type], dkey, res);
2925 mono_image_unlock (image);
2931 static MonoGenericInst*
2932 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
2935 get_shared_type (MonoType *t, MonoType *type)
2939 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2940 MonoGenericClass *gclass = type->data.generic_class;
2941 MonoGenericContext context;
2944 memset (&context, 0, sizeof (context));
2945 if (gclass->context.class_inst)
2946 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
2947 if (gclass->context.method_inst)
2948 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
2950 k = mono_class_inflate_generic_class (gclass->container_class, &context);
2952 return get_shared_gparam (t, &k->byval_arg);
2955 g_assert (!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)));
2957 /* Create a type variable with a constraint which encodes which types can match it */
2959 if (type->type == MONO_TYPE_VALUETYPE)
2960 ttype = mono_class_enum_basetype (type->data.klass)->type;
2966 memset (&t2, 0, sizeof (t2));
2968 klass = mono_class_from_mono_type (&t2);
2970 return get_shared_gparam (t, &klass->byval_arg);
2975 get_gsharedvt_type (MonoType *t)
2977 /* Use TypeHandle as the constraint type since its a valuetype */
2978 return get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
2981 static MonoGenericInst*
2982 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
2984 MonoGenericInst *res;
2985 MonoType **type_argv;
2988 type_argv = g_new0 (MonoType*, inst->type_argc);
2989 for (i = 0; i < inst->type_argc; ++i) {
2991 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2992 } else 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)) {
2993 g_assert (shared_inst);
2994 type_argv [i] = get_shared_gparam (shared_inst->type_argv [i], &mono_defaults.object_class->byval_arg);
2995 } else if (partial) {
2996 /* These types match the ones in generic_inst_is_sharable () */
2997 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
2998 } else if (gsharedvt) {
2999 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3001 type_argv [i] = inst->type_argv [i];
3005 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3011 * mini_get_shared_method_full:
3013 * Return the method which is actually compiled/registered when doing generic sharing.
3014 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3015 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3016 * METHOD can be a non-inflated generic method.
3019 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3022 MonoGenericContext shared_context;
3023 MonoMethod *declaring_method, *res;
3024 gboolean partial = FALSE;
3025 gboolean gsharedvt = FALSE;
3026 MonoGenericContainer *class_container, *method_container = NULL;
3027 MonoGenericContext *context = mono_method_get_context (method);
3028 MonoGenericInst *inst;
3030 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3031 declaring_method = method;
3033 declaring_method = mono_method_get_declaring_generic_method (method);
3036 /* shared_context is the context containing type variables. */
3037 if (declaring_method->is_generic)
3038 shared_context = mono_method_get_generic_container (declaring_method)->context;
3040 shared_context = declaring_method->klass->generic_container->context;
3043 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3045 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3047 class_container = declaring_method->klass->generic_container;
3048 method_container = mono_method_get_generic_container (declaring_method);
3051 * Create the shared context by replacing the ref type arguments with
3052 * type parameters, and keeping the rest.
3055 inst = context->class_inst;
3057 inst = shared_context.class_inst;
3059 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3062 inst = context->method_inst;
3064 inst = shared_context.method_inst;
3066 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3068 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3069 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3075 mini_get_shared_method (MonoMethod *method)
3077 return mini_get_shared_method_full (method, FALSE, FALSE);
3080 #if defined(ENABLE_GSHAREDVT)
3082 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3087 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
3093 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
3099 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
3105 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
3111 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
3117 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3123 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3128 #endif /* !MONOTOUCH */