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)
732 * FIXME: This conflicts with normal instances. Also, some code in this file
733 * like class_get_rgctx_template_oti treats these as normal generic instances
734 * instead of generic classes.
736 //g_assert_not_reached ();
739 /* The gsharedvt changes break this */
740 if (ALLOW_PARTIAL_SHARING)
741 g_assert_not_reached ();
745 if (class->is_inflated) {
746 MonoGenericContext *context = &class->generic_class->context;
747 MonoGenericContext *container_context;
748 MonoGenericContext shared_context;
749 MonoGenericInst *inst;
750 MonoType **type_argv;
753 inst = context->class_inst;
754 if (mono_is_partially_sharable_inst (inst)) {
755 container_context = &class->generic_class->container_class->generic_container->context;
756 type_argv = g_new0 (MonoType*, inst->type_argc);
757 for (i = 0; i < inst->type_argc; ++i) {
758 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)
759 type_argv [i] = container_context->class_inst->type_argv [i];
761 type_argv [i] = inst->type_argv [i];
764 memset (&shared_context, 0, sizeof (MonoGenericContext));
765 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
768 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
769 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
770 /* Happens for partially shared methods of nono-sharable generic class */
776 // FIXME: Use this in all cases can be problematic wrt domain/assembly unloading
777 return class_uninstantiated (class);
781 * mono_class_get_runtime_generic_context_template:
784 * Looks up or constructs, if necessary, the runtime generic context template for class.
785 * The template is the same for all instantiations of a class.
787 static MonoRuntimeGenericContextTemplate*
788 mono_class_get_runtime_generic_context_template (MonoClass *class)
790 MonoRuntimeGenericContextTemplate *parent_template, *template;
793 class = get_shared_class (class);
796 template = class_lookup_rgctx_template (class);
797 mono_loader_unlock ();
802 //g_assert (get_shared_class (class) == class);
804 template = alloc_template (class);
810 int max_argc, type_argc;
812 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
813 max_argc = template_get_max_argc (parent_template);
815 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
816 num_entries = rgctx_template_num_infos (parent_template, type_argc);
818 /* FIXME: quadratic! */
819 for (i = 0; i < num_entries; ++i) {
820 MonoRuntimeGenericContextInfoTemplate oti;
822 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
823 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
824 rgctx_template_set_slot (class->image, template, type_argc, i,
825 oti.data, oti.info_type);
831 if (class_lookup_rgctx_template (class)) {
832 /* some other thread already set the template */
833 template = class_lookup_rgctx_template (class);
835 class_set_rgctx_template (class, template);
838 register_generic_subclass (class);
841 mono_loader_unlock ();
847 * class_get_rgctx_template_oti:
849 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
850 * temporary signifies whether the inflated info (oti.data) will be
851 * used temporarily, in which case it might be heap-allocated, or
852 * permanently, in which case it will be mempool-allocated. If
853 * temporary is set then *do_free will return whether the returned
854 * data must be freed.
856 * LOCKING: loader lock
858 static MonoRuntimeGenericContextInfoTemplate
859 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
861 g_assert ((temporary && do_free) || (!temporary && !do_free));
863 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
865 if (class->generic_class && !shared) {
866 MonoRuntimeGenericContextInfoTemplate oti;
867 gboolean tmp_do_free;
869 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
870 type_argc, slot, TRUE, FALSE, &tmp_do_free);
872 gpointer info = oti.data;
873 oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
875 free_inflated_info (oti.info_type, info);
882 MonoRuntimeGenericContextTemplate *template;
883 MonoRuntimeGenericContextInfoTemplate *oti;
885 template = mono_class_get_runtime_generic_context_template (class);
886 oti = rgctx_template_get_other_slot (template, type_argc, slot);
897 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
900 case MONO_RGCTX_INFO_STATIC_DATA: {
901 MonoVTable *vtable = mono_class_vtable (domain, class);
903 mono_raise_exception (mono_class_get_exception_for_failure (class));
904 return mono_vtable_get_static_field_data (vtable);
906 case MONO_RGCTX_INFO_KLASS:
908 case MONO_RGCTX_INFO_ELEMENT_KLASS:
909 return class->element_class;
910 case MONO_RGCTX_INFO_VTABLE: {
911 MonoVTable *vtable = mono_class_vtable (domain, class);
913 mono_raise_exception (mono_class_get_exception_for_failure (class));
916 case MONO_RGCTX_INFO_CAST_CACHE: {
917 /*First slot is the cache itself, the second the vtable.*/
918 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
919 cache_data [1] = (gpointer)class;
922 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
923 return GUINT_TO_POINTER (mono_class_array_element_size (class));
924 case MONO_RGCTX_INFO_VALUE_SIZE:
925 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
926 return GUINT_TO_POINTER (sizeof (gpointer));
928 return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
929 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
930 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
931 return GUINT_TO_POINTER (1);
932 else if (mono_class_is_nullable (class))
933 return GUINT_TO_POINTER (2);
935 return GUINT_TO_POINTER (0);
936 case MONO_RGCTX_INFO_MEMCPY:
937 case MONO_RGCTX_INFO_BZERO: {
938 static MonoMethod *memcpy_method [17];
939 static MonoMethod *bzero_method [17];
940 MonoJitDomainInfo *domain_info;
944 domain_info = domain_jit_info (domain);
946 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg)) {
947 size = sizeof (gpointer);
948 align = sizeof (gpointer);
950 size = mono_class_value_size (class, &align);
953 if (size != 1 && size != 2 && size != 4 && size != 8)
958 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
959 if (!memcpy_method [size]) {
964 sprintf (name, "memcpy");
966 sprintf (name, "memcpy_aligned_%d", size);
967 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
969 mono_memory_barrier ();
970 memcpy_method [size] = m;
972 if (!domain_info->memcpy_addr [size]) {
973 gpointer addr = mono_compile_method (memcpy_method [size]);
974 mono_memory_barrier ();
975 domain_info->memcpy_addr [size] = addr;
977 return domain_info->memcpy_addr [size];
979 if (!bzero_method [size]) {
984 sprintf (name, "bzero");
986 sprintf (name, "bzero_aligned_%d", size);
987 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
989 mono_memory_barrier ();
990 bzero_method [size] = m;
992 if (!domain_info->bzero_addr [size]) {
993 gpointer addr = mono_compile_method (bzero_method [size]);
994 mono_memory_barrier ();
995 domain_info->bzero_addr [size] = addr;
997 return domain_info->bzero_addr [size];
1000 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1001 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1005 MonoGenericContext *ctx;
1007 if (!mono_class_is_nullable (class))
1008 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1011 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1012 method = mono_class_get_method_from_name (class, "Box", 1);
1014 method = mono_class_get_method_from_name (class, "Unbox", 1);
1016 addr = mono_compile_method (method);
1017 // The caller uses the gsharedvt call signature
1018 ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1020 if (mini_jit_info_is_gsharedvt (ji))
1021 return mono_create_static_rgctx_trampoline (method, addr);
1023 MonoGenericSharingContext gsctx;
1024 MonoMethodSignature *sig, *gsig;
1025 MonoMethod *gmethod;
1027 /* Need to add an out wrapper */
1029 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1030 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1031 sig = mono_method_signature (method);
1032 gsig = mono_method_signature (gmethod);
1033 ctx = mono_method_get_context (gmethod);
1034 mini_init_gsctx (NULL, NULL, ctx, &gsctx);
1036 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, &gsctx, -1, FALSE);
1037 addr = mono_create_static_rgctx_trampoline (method, addr);
1042 g_assert_not_reached ();
1049 ji_is_gsharedvt (MonoJitInfo *ji)
1051 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
1052 mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
1059 * Describes the information used to construct a gsharedvt arg trampoline.
1064 gint32 vcall_offset;
1066 MonoMethodSignature *sig, *gsig;
1067 MonoGenericContext gsctx;
1068 } GSharedVtTrampInfo;
1071 tramp_info_hash (gconstpointer key)
1073 GSharedVtTrampInfo *tramp = (gpointer)key;
1075 return (gsize)tramp->addr;
1079 tramp_info_equal (gconstpointer a, gconstpointer b)
1081 GSharedVtTrampInfo *tramp1 = (gpointer)a;
1082 GSharedVtTrampInfo *tramp2 = (gpointer)b;
1084 /* The signatures should be internalized */
1085 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1086 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
1087 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
1091 * mini_get_gsharedvt_wrapper:
1093 * Return a gsharedvt in/out wrapper for calling ADDR.
1096 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
1097 gint32 vcall_offset, gboolean calli)
1099 static gboolean inited = FALSE;
1100 static int num_trampolines;
1102 MonoDomain *domain = mono_domain_get ();
1103 MonoJitDomainInfo *domain_info;
1104 GSharedVtTrampInfo *tramp_info;
1105 GSharedVtTrampInfo tinfo;
1108 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1112 tinfo.is_in = gsharedvt_in;
1113 tinfo.calli = calli;
1114 tinfo.vcall_offset = vcall_offset;
1116 tinfo.sig = normal_sig;
1117 tinfo.gsig = gsharedvt_sig;
1118 memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
1120 domain_info = domain_jit_info (domain);
1123 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1125 mono_domain_lock (domain);
1126 if (!domain_info->gsharedvt_arg_tramp_hash)
1127 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1128 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1129 mono_domain_unlock (domain);
1133 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1136 static gpointer tramp_addr;
1137 MonoMethod *wrapper;
1140 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1141 addr = mono_compile_method (wrapper);
1142 mono_memory_barrier ();
1147 static gpointer tramp_addr;
1148 MonoMethod *wrapper;
1151 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1152 addr = mono_compile_method (wrapper);
1153 mono_memory_barrier ();
1160 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1162 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1167 tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1168 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1170 mono_domain_lock (domain);
1171 /* Duplicates are not a problem */
1172 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1173 mono_domain_unlock (domain);
1179 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1180 MonoGenericContext *context, MonoClass *class, guint8 *caller)
1188 switch (oti->info_type) {
1189 case MONO_RGCTX_INFO_STATIC_DATA:
1190 case MONO_RGCTX_INFO_KLASS:
1191 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1192 case MONO_RGCTX_INFO_VTABLE:
1193 case MONO_RGCTX_INFO_CAST_CACHE:
1200 data = inflate_info (oti, context, class, temporary);
1202 switch (oti->info_type) {
1203 case MONO_RGCTX_INFO_STATIC_DATA:
1204 case MONO_RGCTX_INFO_KLASS:
1205 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1206 case MONO_RGCTX_INFO_VTABLE:
1207 case MONO_RGCTX_INFO_CAST_CACHE:
1208 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1209 case MONO_RGCTX_INFO_VALUE_SIZE:
1210 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1211 case MONO_RGCTX_INFO_MEMCPY:
1212 case MONO_RGCTX_INFO_BZERO:
1213 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1214 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1215 MonoClass *arg_class = mono_class_from_mono_type (data);
1217 free_inflated_info (oti->info_type, data);
1218 g_assert (arg_class);
1220 /* The class might be used as an argument to
1221 mono_value_copy(), which requires that its GC
1222 descriptor has been computed. */
1223 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1224 mono_class_compute_gc_descriptor (arg_class);
1226 return class_type_info (domain, arg_class, oti->info_type);
1228 case MONO_RGCTX_INFO_TYPE:
1230 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1231 return mono_type_get_object (domain, data);
1232 case MONO_RGCTX_INFO_METHOD:
1234 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1237 addr = mono_compile_method (data);
1238 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1240 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1241 MonoJumpInfoVirtMethod *info = data;
1242 MonoClass *iface_class = info->method->klass;
1247 mono_class_setup_vtable (info->klass);
1248 // FIXME: Check type load
1249 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1250 ioffset = mono_class_interface_offset (info->klass, iface_class);
1251 g_assert (ioffset != -1);
1255 slot = mono_method_get_vtable_slot (info->method);
1256 g_assert (slot != -1);
1257 g_assert (info->klass->vtable);
1258 method = info->klass->vtable [ioffset + slot];
1260 addr = mono_compile_method (method);
1261 return mini_add_method_trampoline (NULL, method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1263 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1264 MonoJumpInfoVirtMethod *info = data;
1265 MonoClass *iface_class = info->method->klass;
1267 MonoClass *impl_class;
1270 mono_class_setup_vtable (info->klass);
1271 // FIXME: Check type load
1272 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1273 ioffset = mono_class_interface_offset (info->klass, iface_class);
1274 g_assert (ioffset != -1);
1278 slot = mono_method_get_vtable_slot (info->method);
1279 g_assert (slot != -1);
1280 g_assert (info->klass->vtable);
1281 method = info->klass->vtable [ioffset + slot];
1283 impl_class = method->klass;
1284 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1285 return GUINT_TO_POINTER (1);
1286 else if (mono_class_is_nullable (impl_class))
1287 return GUINT_TO_POINTER (2);
1289 return GUINT_TO_POINTER (0);
1291 #ifndef DISABLE_REMOTING
1292 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1293 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1295 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1296 return mono_domain_alloc0 (domain, sizeof (gpointer));
1297 case MONO_RGCTX_INFO_CLASS_FIELD:
1299 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1300 MonoClassField *field = data;
1302 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1303 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1305 return GUINT_TO_POINTER (field->offset);
1307 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1308 MonoMethodInflated *method = data;
1311 g_assert (method->method.method.is_inflated);
1312 g_assert (method->context.method_inst);
1314 vtable = mono_class_vtable (domain, method->method.method.klass);
1316 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1318 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1320 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1321 MonoMethodInflated *method = data;
1323 g_assert (method->method.method.is_inflated);
1324 g_assert (method->context.method_inst);
1326 return method->context.method_inst;
1328 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1329 MonoMethodSignature *gsig = oti->data;
1330 MonoMethodSignature *sig = data;
1332 MonoJitInfo *caller_ji;
1333 MonoGenericJitInfo *gji;
1336 * This is an indirect call to the address passed by the caller in the rgctx reg.
1338 //printf ("CALLI\n");
1341 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1342 g_assert (caller_ji);
1343 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1346 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1350 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1351 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1352 MonoJumpInfoGSharedVtCall *call_info = data;
1353 MonoMethodSignature *call_sig;
1356 MonoJitInfo *caller_ji, *callee_ji;
1357 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1358 gint32 vcall_offset;
1359 MonoGenericJitInfo *gji, *callee_gji = NULL;
1360 gboolean callee_gsharedvt;
1362 /* This is the original generic signature used by the caller */
1363 call_sig = call_info->sig;
1364 /* This is the instantiated method which is called */
1365 method = call_info->method;
1367 g_assert (method->is_inflated);
1370 addr = mono_compile_method (method);
1375 /* Same as in mono_emit_method_call_full () */
1376 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1377 /* See mono_emit_method_call_full () */
1378 /* The gsharedvt trampoline will recognize this constant */
1379 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1380 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1381 guint32 imt_slot = mono_method_get_imt_slot (method);
1382 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1384 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1385 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1392 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1393 g_assert (caller_ji);
1394 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1397 // FIXME: This loads information in the AOT case
1398 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1399 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1400 if (callee_gsharedvt) {
1401 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1402 g_assert (callee_gji);
1406 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1407 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1408 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1409 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1410 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1411 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1412 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1413 * caller -> out trampoline -> in trampoline -> callee
1414 * This is not very efficient, but it is easy to implement.
1416 if (virtual || !callee_gsharedvt) {
1417 MonoMethodSignature *sig, *gsig;
1419 g_assert (method->is_inflated);
1421 sig = mono_method_signature (method);
1424 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1427 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1429 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1431 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1432 } else if (callee_gsharedvt) {
1433 MonoMethodSignature *sig, *gsig;
1436 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1437 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1440 * public void foo<T1> (T1 t1, T t, object o) {}
1442 * class AClass : Base<long> {
1443 * public void bar<T> (T t, long time, object o) {
1447 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1448 * FIXME: Optimize this.
1451 if (call_sig == mono_method_signature (method)) {
1453 sig = mono_method_signature (method);
1454 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1456 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1458 sig = mono_method_signature (method);
1461 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1463 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1469 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1470 MonoGSharedVtMethodInfo *info = data;
1471 MonoGSharedVtMethodRuntimeInfo *res;
1473 int i, offset, align, size;
1476 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1479 for (i = 0; i < info->num_entries; ++i) {
1480 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1482 switch (template->info_type) {
1483 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1486 size = mono_type_size (t, &align);
1488 if (align < sizeof (gpointer))
1489 align = sizeof (gpointer);
1490 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1491 align = 2 * sizeof (gpointer);
1493 // FIXME: Do the same things as alloc_stack_slots
1494 offset += align - 1;
1495 offset &= ~(align - 1);
1496 res->entries [i] = GINT_TO_POINTER (offset);
1500 res->entries [i] = instantiate_info (domain, template, context, class, NULL);
1504 res->locals_size = offset;
1509 g_assert_not_reached ();
1516 * LOCKING: loader lock
1519 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1521 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1522 MonoClass *subclass;
1524 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1526 /* Recurse for all subclasses */
1527 if (generic_subclass_hash)
1528 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1533 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1534 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1536 g_assert (subclass_template);
1538 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1539 g_assert (subclass_oti.data);
1541 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1543 subclass = subclass_template->next_subclass;
1548 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1551 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1552 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1553 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1554 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1555 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1556 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1557 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1558 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1559 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1560 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1561 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1562 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1563 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1564 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1565 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1566 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1567 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1568 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1569 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1570 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1571 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1572 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1573 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1574 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1575 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1576 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1577 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1578 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1580 return "<UNKNOWN RGCTX INFO TYPE>";
1584 G_GNUC_UNUSED static char*
1585 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1587 switch (info_type) {
1588 case MONO_RGCTX_INFO_VTABLE:
1589 return mono_type_full_name ((MonoType*)data);
1591 return g_strdup_printf ("<%p>", data);
1596 * LOCKING: loader lock
1599 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1602 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1604 MonoRuntimeGenericContextInfoTemplate *oti;
1606 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1611 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)));
1613 /* Mark the slot as used in all parent classes (until we find
1614 a parent class which already has it marked used). */
1615 parent = class->parent;
1616 while (parent != NULL) {
1617 MonoRuntimeGenericContextTemplate *parent_template;
1618 MonoRuntimeGenericContextInfoTemplate *oti;
1620 if (parent->generic_class)
1621 parent = parent->generic_class->container_class;
1623 parent_template = mono_class_get_runtime_generic_context_template (parent);
1624 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1626 if (oti && oti->data)
1629 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1630 MONO_RGCTX_SLOT_USED_MARKER, 0);
1632 parent = parent->parent;
1635 /* Fill in the slot in this class and in all subclasses
1637 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1643 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1645 switch (info_type) {
1646 case MONO_RGCTX_INFO_STATIC_DATA:
1647 case MONO_RGCTX_INFO_KLASS:
1648 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1649 case MONO_RGCTX_INFO_VTABLE:
1650 case MONO_RGCTX_INFO_TYPE:
1651 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1652 case MONO_RGCTX_INFO_CAST_CACHE:
1653 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1654 case MONO_RGCTX_INFO_VALUE_SIZE:
1655 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1656 case MONO_RGCTX_INFO_MEMCPY:
1657 case MONO_RGCTX_INFO_BZERO:
1658 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1659 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1660 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1661 case MONO_RGCTX_INFO_METHOD:
1662 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1663 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1664 case MONO_RGCTX_INFO_CLASS_FIELD:
1665 case MONO_RGCTX_INFO_FIELD_OFFSET:
1666 case MONO_RGCTX_INFO_METHOD_RGCTX:
1667 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1668 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1669 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1670 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1671 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1672 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1673 return data1 == data2;
1674 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
1675 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1676 MonoJumpInfoVirtMethod *info1 = data1;
1677 MonoJumpInfoVirtMethod *info2 = data2;
1679 return info1->klass == info2->klass && info1->method == info2->method;
1682 g_assert_not_reached ();
1689 * mini_rgctx_info_type_to_patch_info_type:
1691 * Return the type of the runtime object referred to by INFO_TYPE.
1694 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1696 switch (info_type) {
1697 case MONO_RGCTX_INFO_STATIC_DATA:
1698 case MONO_RGCTX_INFO_KLASS:
1699 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1700 case MONO_RGCTX_INFO_VTABLE:
1701 case MONO_RGCTX_INFO_TYPE:
1702 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1703 case MONO_RGCTX_INFO_CAST_CACHE:
1704 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1705 case MONO_RGCTX_INFO_VALUE_SIZE:
1706 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1707 case MONO_RGCTX_INFO_MEMCPY:
1708 case MONO_RGCTX_INFO_BZERO:
1709 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1710 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1711 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1712 return MONO_PATCH_INFO_CLASS;
1713 case MONO_RGCTX_INFO_FIELD_OFFSET:
1714 return MONO_PATCH_INFO_FIELD;
1716 g_assert_not_reached ();
1722 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1723 MonoGenericContext *generic_context)
1725 static gboolean inited = FALSE;
1726 static int max_slot = 0;
1728 MonoRuntimeGenericContextTemplate *rgctx_template =
1729 mono_class_get_runtime_generic_context_template (class);
1730 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1733 class = get_shared_class (class);
1735 mono_loader_lock ();
1737 if (info_has_identity (info_type)) {
1738 oti_list = get_info_templates (rgctx_template, type_argc);
1740 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1741 gpointer inflated_data;
1743 if (oti->info_type != info_type || !oti->data)
1746 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1748 if (info_equal (data, inflated_data, info_type)) {
1749 free_inflated_info (info_type, inflated_data);
1750 mono_loader_unlock ();
1753 free_inflated_info (info_type, inflated_data);
1757 /* We haven't found the info */
1758 i = register_info (class, type_argc, data, info_type);
1760 mono_loader_unlock ();
1763 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1773 * mono_method_lookup_or_register_info:
1775 * @in_mrgctx: whether to put the data into the MRGCTX
1776 * @data: the info data
1777 * @info_type: the type of info to register about data
1778 * @generic_context: a generic context
1780 * Looks up and, if necessary, adds information about data/info_type in
1781 * method's or method's class runtime generic context. Returns the
1782 * encoded slot number.
1785 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1786 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1788 MonoClass *class = method->klass;
1789 int type_argc, index;
1792 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1794 g_assert (method->is_inflated && method_inst);
1795 type_argc = method_inst->type_argc;
1796 g_assert (type_argc > 0);
1801 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1803 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1806 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1808 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1812 * mono_class_rgctx_get_array_size:
1813 * @n: The number of the array
1814 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1816 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1817 * number includes the slot for linking and - for MRGCTXs - the two
1818 * slots in the first array for additional information.
1821 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1823 g_assert (n >= 0 && n < 30);
1832 * LOCKING: domain lock
1835 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1837 static gboolean inited = FALSE;
1838 static int rgctx_num_alloced = 0;
1839 static int rgctx_bytes_alloced = 0;
1840 static int mrgctx_num_alloced = 0;
1841 static int mrgctx_bytes_alloced = 0;
1843 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1844 gpointer array = mono_domain_alloc0 (domain, size);
1847 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1848 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1849 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1850 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1855 mrgctx_num_alloced++;
1856 mrgctx_bytes_alloced += size;
1858 rgctx_num_alloced++;
1859 rgctx_bytes_alloced += size;
1866 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1867 MonoGenericInst *method_inst)
1870 int i, first_slot, size;
1871 MonoDomain *domain = class_vtable->domain;
1872 MonoClass *class = class_vtable->klass;
1873 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1874 MonoRuntimeGenericContextInfoTemplate oti;
1875 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1881 mono_domain_lock (domain);
1883 /* First check whether that slot isn't already instantiated.
1884 This might happen because lookup doesn't lock. Allocate
1885 arrays on the way. */
1887 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1889 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1890 for (i = 0; ; ++i) {
1893 if (method_inst && i == 0)
1894 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1898 if (slot < first_slot + size - 1) {
1899 rgctx_index = slot - first_slot + 1 + offset;
1900 info = rgctx [rgctx_index];
1902 mono_domain_unlock (domain);
1907 if (!rgctx [offset + 0])
1908 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1909 rgctx = rgctx [offset + 0];
1910 first_slot += size - 1;
1911 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1914 g_assert (!rgctx [rgctx_index]);
1916 mono_domain_unlock (domain);
1918 oti = class_get_rgctx_template_oti (get_shared_class (class),
1919 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1920 /* This might take the loader lock */
1921 info = instantiate_info (domain, &oti, &context, class, caller);
1925 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1928 /*FIXME We should use CAS here, no need to take a lock.*/
1929 mono_domain_lock (domain);
1931 /* Check whether the slot hasn't been instantiated in the
1933 if (rgctx [rgctx_index])
1934 info = rgctx [rgctx_index];
1936 rgctx [rgctx_index] = info;
1938 mono_domain_unlock (domain);
1941 free_inflated_info (oti.info_type, oti.data);
1947 * mono_class_fill_runtime_generic_context:
1948 * @class_vtable: a vtable
1949 * @caller: caller method address
1950 * @slot: a slot index to be instantiated
1952 * Instantiates a slot in the RGCTX, returning its value.
1955 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1957 static gboolean inited = FALSE;
1958 static int num_alloced = 0;
1960 MonoDomain *domain = class_vtable->domain;
1961 MonoRuntimeGenericContext *rgctx;
1964 mono_domain_lock (domain);
1967 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1971 rgctx = class_vtable->runtime_generic_context;
1973 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1974 class_vtable->runtime_generic_context = rgctx;
1978 mono_domain_unlock (domain);
1980 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1982 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1988 * mono_method_fill_runtime_generic_context:
1989 * @mrgctx: an MRGCTX
1990 * @caller: caller method address
1991 * @slot: a slot index to be instantiated
1993 * Instantiates a slot in the MRGCTX.
1996 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
2000 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
2001 mrgctx->method_inst);
2007 mrgctx_hash_func (gconstpointer key)
2009 const MonoMethodRuntimeGenericContext *mrgctx = key;
2011 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2015 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2017 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
2018 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
2020 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2021 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2025 * mono_method_lookup_rgctx:
2026 * @class_vtable: a vtable
2027 * @method_inst: the method inst of a generic method
2029 * Returns the MRGCTX for the generic method(s) with the given
2030 * method_inst of the given class_vtable.
2032 * LOCKING: Take the domain lock.
2034 MonoMethodRuntimeGenericContext*
2035 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2037 MonoDomain *domain = class_vtable->domain;
2038 MonoMethodRuntimeGenericContext *mrgctx;
2039 MonoMethodRuntimeGenericContext key;
2041 g_assert (!class_vtable->klass->generic_container);
2042 g_assert (!method_inst->is_open);
2044 mono_domain_lock (domain);
2045 if (!domain->method_rgctx_hash)
2046 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2048 key.class_vtable = class_vtable;
2049 key.method_inst = method_inst;
2051 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
2056 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2057 mrgctx->class_vtable = class_vtable;
2058 mrgctx->method_inst = method_inst;
2060 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2063 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2064 for (i = 0; i < method_inst->type_argc; ++i)
2065 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2070 mono_domain_unlock (domain);
2079 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2080 gboolean allow_partial);
2083 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2085 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
2088 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2089 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)))
2092 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2093 MonoGenericClass *gclass = type->data.generic_class;
2095 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2097 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2099 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2108 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2109 gboolean allow_partial)
2113 for (i = 0; i < inst->type_argc; ++i) {
2114 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2122 * mono_is_partially_sharable_inst:
2124 * Return TRUE if INST has ref and non-ref type arguments.
2127 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2130 gboolean has_refs = FALSE, has_non_refs = FALSE;
2132 for (i = 0; i < inst->type_argc; ++i) {
2133 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)
2136 has_non_refs = TRUE;
2139 return has_refs && has_non_refs;
2143 * mono_generic_context_is_sharable_full:
2144 * @context: a generic context
2146 * Returns whether the generic context is sharable. A generic context
2147 * is sharable iff all of its type arguments are reference type, or some of them have a
2148 * reference type, and ALLOW_PARTIAL is TRUE.
2151 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2152 gboolean allow_type_vars,
2153 gboolean allow_partial)
2155 g_assert (context->class_inst || context->method_inst);
2157 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2160 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2167 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2169 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2173 * mono_method_is_generic_impl:
2176 * Returns whether the method is either generic or part of a generic
2180 mono_method_is_generic_impl (MonoMethod *method)
2182 if (method->is_inflated)
2184 /* We don't treat wrappers as generic code, i.e., we never
2185 apply generic sharing to them. This is especially
2186 important for static rgctx invoke wrappers, which only work
2187 if not compiled with sharing. */
2188 if (method->wrapper_type != MONO_WRAPPER_NONE)
2190 if (method->klass->generic_container)
2196 has_constraints (MonoGenericContainer *container)
2202 g_assert (container->type_argc > 0);
2203 g_assert (container->type_params);
2205 for (i = 0; i < container->type_argc; ++i)
2206 if (container->type_params [i].constraints)
2213 mini_method_is_open (MonoMethod *method)
2215 if (method->is_inflated) {
2216 MonoGenericContext *ctx = mono_method_get_context (method);
2218 if (ctx->class_inst && ctx->class_inst->is_open)
2220 if (ctx->method_inst && ctx->method_inst->is_open)
2226 static G_GNUC_UNUSED gboolean
2227 is_async_state_machine_class (MonoClass *klass)
2229 static MonoClass *iclass;
2230 static gboolean iclass_set;
2235 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2236 mono_memory_barrier ();
2240 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2245 static G_GNUC_UNUSED gboolean
2246 is_async_method (MonoMethod *method)
2248 MonoCustomAttrInfo *cattr;
2249 MonoMethodSignature *sig;
2250 gboolean res = FALSE;
2251 static MonoClass *attr_class;
2252 static gboolean attr_class_set;
2256 if (!attr_class_set) {
2257 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2258 mono_memory_barrier ();
2259 attr_class_set = TRUE;
2262 /* Do less expensive checks first */
2263 sig = mono_method_signature (method);
2264 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2265 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2266 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2267 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2268 cattr = mono_custom_attrs_from_method (method);
2270 if (mono_custom_attrs_has_attr (cattr, attr_class))
2272 mono_custom_attrs_free (cattr);
2279 * mono_method_is_generic_sharable_full:
2281 * @allow_type_vars: whether to regard type variables as reference types
2282 * @allow_partial: whether to allow partial sharing
2283 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2285 * Returns TRUE iff the method is inflated or part of an inflated
2286 * class, its context is sharable and it has no constraints on its
2287 * type parameters. Otherwise returns FALSE.
2290 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2291 gboolean allow_partial, gboolean allow_gsharedvt)
2293 if (!mono_method_is_generic_impl (method))
2296 if (!partial_sharing_supported ())
2297 allow_partial = FALSE;
2299 if (mono_class_is_nullable (method->klass))
2301 allow_partial = FALSE;
2303 if (method->klass->image->dynamic)
2305 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2306 * instance_size is 0.
2308 allow_partial = FALSE;
2311 * Generic async methods have an associated state machine class which is a generic struct. This struct
2312 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2313 * of the async method and the state machine class.
2315 if (is_async_state_machine_class (method->klass))
2318 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2319 if (is_async_method (method))
2324 if (method->is_inflated) {
2325 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2326 MonoGenericContext *context = &inflated->context;
2328 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2331 g_assert (inflated->declaring);
2333 if (inflated->declaring->is_generic) {
2334 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2339 if (method->klass->generic_class) {
2340 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2343 g_assert (method->klass->generic_class->container_class &&
2344 method->klass->generic_class->container_class->generic_container);
2346 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2350 if (method->klass->generic_container && !allow_type_vars)
2353 /* This does potentially expensive cattr checks, so do it at the end */
2354 if (is_async_method (method)) {
2355 if (mini_method_is_open (method))
2356 /* The JIT can't compile these without sharing */
2365 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2367 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2371 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2373 if (!mono_class_generic_sharing_enabled (method->klass))
2376 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2379 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2382 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2383 method->klass->valuetype) &&
2384 (method->klass->generic_class || method->klass->generic_container);
2387 static MonoGenericInst*
2388 get_object_generic_inst (int type_argc)
2390 MonoType **type_argv;
2393 type_argv = alloca (sizeof (MonoType*) * type_argc);
2395 for (i = 0; i < type_argc; ++i)
2396 type_argv [i] = &mono_defaults.object_class->byval_arg;
2398 return mono_metadata_get_generic_inst (type_argc, type_argv);
2402 * mono_method_construct_object_context:
2405 * Returns a generic context for method with all type variables for
2406 * class and method instantiated with Object.
2409 mono_method_construct_object_context (MonoMethod *method)
2411 MonoGenericContext object_context;
2413 g_assert (!method->klass->generic_class);
2414 if (method->klass->generic_container) {
2415 int type_argc = method->klass->generic_container->type_argc;
2417 object_context.class_inst = get_object_generic_inst (type_argc);
2419 object_context.class_inst = NULL;
2422 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2423 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2425 object_context.method_inst = get_object_generic_inst (type_argc);
2427 object_context.method_inst = NULL;
2430 g_assert (object_context.class_inst || object_context.method_inst);
2432 return object_context;
2435 static gboolean gshared_supported;
2436 static gboolean gsharedvt_supported;
2439 mono_set_generic_sharing_supported (gboolean supported)
2441 gshared_supported = supported;
2445 mono_set_generic_sharing_vt_supported (gboolean supported)
2447 gsharedvt_supported = supported;
2451 mono_set_partial_sharing_supported (gboolean supported)
2453 partial_supported = supported;
2457 * mono_class_generic_sharing_enabled:
2460 * Returns whether generic sharing is enabled for class.
2462 * This is a stop-gap measure to slowly introduce generic sharing
2463 * until we have all the issues sorted out, at which time this
2464 * function will disappear and generic sharing will always be enabled.
2467 mono_class_generic_sharing_enabled (MonoClass *class)
2469 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2470 static gboolean inited = FALSE;
2475 if (gshared_supported)
2476 generic_sharing = MONO_GENERIC_SHARING_ALL;
2478 generic_sharing = MONO_GENERIC_SHARING_NONE;
2480 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2481 if (strcmp (option, "corlib") == 0)
2482 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2483 else if (strcmp (option, "collections") == 0)
2484 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2485 else if (strcmp (option, "all") == 0)
2486 generic_sharing = MONO_GENERIC_SHARING_ALL;
2487 else if (strcmp (option, "none") == 0)
2488 generic_sharing = MONO_GENERIC_SHARING_NONE;
2490 g_warning ("Unknown generic sharing option `%s'.", option);
2493 if (!gshared_supported)
2494 generic_sharing = MONO_GENERIC_SHARING_NONE;
2499 switch (generic_sharing) {
2500 case MONO_GENERIC_SHARING_NONE:
2502 case MONO_GENERIC_SHARING_ALL:
2504 case MONO_GENERIC_SHARING_CORLIB :
2505 return class->image == mono_defaults.corlib;
2506 case MONO_GENERIC_SHARING_COLLECTIONS:
2507 if (class->image != mono_defaults.corlib)
2509 while (class->nested_in)
2510 class = class->nested_in;
2511 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2513 g_assert_not_reached ();
2519 * mono_get_generic_context_from_code:
2521 * Return the runtime generic context belonging to the method whose native code
2524 MonoGenericSharingContext*
2525 mono_get_generic_context_from_code (guint8 *code)
2527 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2529 g_assert (jit_info);
2531 return mono_jit_info_get_generic_sharing_context (jit_info);
2535 mini_method_get_context (MonoMethod *method)
2537 return mono_method_get_context_general (method, TRUE);
2541 * mono_method_check_context_used:
2544 * Checks whether the method's generic context uses a type variable.
2545 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2546 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2547 * context's class or method instantiation uses type variables.
2550 mono_method_check_context_used (MonoMethod *method)
2552 MonoGenericContext *method_context = mini_method_get_context (method);
2553 int context_used = 0;
2555 if (!method_context) {
2556 /* It might be a method of an array of an open generic type */
2557 if (method->klass->rank)
2558 context_used = mono_class_check_context_used (method->klass);
2560 context_used = mono_generic_context_check_used (method_context);
2561 context_used |= mono_class_check_context_used (method->klass);
2564 return context_used;
2568 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2579 if (inst1->type_argc != inst2->type_argc)
2582 for (i = 0; i < inst1->type_argc; ++i)
2583 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2590 * mono_generic_context_equal_deep:
2591 * @context1: a generic context
2592 * @context2: a generic context
2594 * Returns whether context1's type arguments are equal to context2's
2598 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2600 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2601 generic_inst_equal (context1->method_inst, context2->method_inst);
2605 * mini_class_get_container_class:
2606 * @class: a generic class
2608 * Returns the class's container class, which is the class itself if
2609 * it doesn't have generic_class set.
2612 mini_class_get_container_class (MonoClass *class)
2614 if (class->generic_class)
2615 return class->generic_class->container_class;
2617 g_assert (class->generic_container);
2622 * mini_class_get_context:
2623 * @class: a generic class
2625 * Returns the class's generic context.
2628 mini_class_get_context (MonoClass *class)
2630 if (class->generic_class)
2631 return &class->generic_class->context;
2633 g_assert (class->generic_container);
2634 return &class->generic_container->context;
2638 * mini_get_basic_type_from_generic:
2639 * @gsctx: a generic sharing context
2642 * Returns a closed type corresponding to the possibly open type
2646 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2648 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2650 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2653 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2655 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2656 MonoType *constraint = type->data.generic_param->gshared_constraint;
2657 /* The gparam serial encodes the type this gparam can represent */
2659 return &mono_defaults.object_class->byval_arg;
2663 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2664 klass = mono_class_from_mono_type (constraint);
2665 return &klass->byval_arg;
2668 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2673 * mini_type_get_underlying_type:
2675 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2679 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2681 type = mini_native_type_replace_type (type);
2684 return &mono_defaults.int_class->byval_arg;
2685 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2687 type = mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2688 switch (type->type) {
2689 case MONO_TYPE_BOOLEAN:
2690 return &mono_defaults.byte_class->byval_arg;
2691 case MONO_TYPE_CHAR:
2692 return &mono_defaults.uint16_class->byval_arg;
2699 * mini_type_stack_size:
2700 * @gsctx: a generic sharing context
2702 * @align: Pointer to an int for returning the alignment
2704 * Returns the type's stack size and the alignment in *align. The
2705 * type is allowed to be open.
2708 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2710 gboolean allow_open = TRUE;
2712 // FIXME: Some callers might not pass in a gsctx
2713 //allow_open = gsctx != NULL;
2714 return mono_type_stack_size_internal (t, align, allow_open);
2718 * mini_type_stack_size_full:
2720 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2723 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2728 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2732 //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2735 size = mono_type_native_stack_size (t, align);
2740 size = mini_type_stack_size (gsctx, t, &ialign);
2743 size = mini_type_stack_size (gsctx, t, NULL);
2751 * mono_generic_sharing_init:
2753 * Register the generic sharing counters.
2756 mono_generic_sharing_init (void)
2758 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2762 mono_generic_sharing_cleanup (void)
2764 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2766 if (generic_subclass_hash)
2767 g_hash_table_destroy (generic_subclass_hash);
2771 * mini_type_var_is_vt:
2773 * Return whenever T is a type variable instantiated with a vtype.
2776 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2778 if (type->type == MONO_TYPE_VAR) {
2779 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2783 } else if (type->type == MONO_TYPE_MVAR) {
2784 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2789 g_assert_not_reached ();
2795 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2797 if (cfg->generic_sharing_context)
2798 type = mini_get_underlying_type (cfg, type);
2799 return mono_type_is_reference (type);
2803 * mini_method_get_rgctx:
2805 * Return the RGCTX which needs to be passed to M when it is called.
2808 mini_method_get_rgctx (MonoMethod *m)
2810 if (mini_method_get_context (m)->method_inst)
2811 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2813 return mono_class_vtable (mono_domain_get (), m->klass);
2817 * mini_type_is_vtype:
2819 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2820 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2823 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2825 t = mini_native_type_replace_type (t);
2827 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2831 mini_class_is_generic_sharable (MonoClass *klass)
2833 if (klass->generic_class && is_async_state_machine_class (klass))
2836 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2840 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2842 return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2846 mini_is_gsharedvt_gparam (MonoType *t)
2848 /* Matches get_gsharedvt_type () */
2849 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;
2853 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
2855 if (constraint == MONO_TYPE_VALUETYPE) {
2856 return g_strdup_printf ("%s_GSHAREDVT", name);
2857 } else if (constraint == MONO_TYPE_OBJECT) {
2858 return g_strdup_printf ("%s_REF", name);
2859 } else if (constraint == MONO_TYPE_GENERICINST) {
2860 return g_strdup_printf ("%s_INST", name);
2863 char *tname, *tname2, *res;
2865 memset (&t, 0, sizeof (t));
2866 t.type = constraint;
2867 tname = mono_type_full_name (&t);
2868 tname2 = g_utf8_strup (tname, strlen (tname));
2869 res = g_strdup_printf ("%s_%s", name, tname2);
2877 MonoGenericParam *par;
2878 MonoType *constraint;
2882 shared_gparam_hash (gconstpointer data)
2884 SharedGParam *p = (SharedGParam*)data;
2887 hash = mono_metadata_generic_param_hash (p->par);
2888 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->constraint);
2894 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
2896 SharedGParam *p1 = (SharedGParam*)ka;
2897 SharedGParam *p2 = (SharedGParam*)kb;
2901 if (p1->par != p2->par)
2903 if (!mono_metadata_type_equal (p1->constraint, p2->constraint))
2909 * get_shared_gparam:
2911 * Create an anonymous gparam with a type variable with a constraint which encodes which types can match it.
2914 get_shared_gparam (MonoType *t, MonoType *constraint)
2916 MonoGenericParam *par = t->data.generic_param;
2917 MonoGenericParam *copy;
2920 MonoImage *image = NULL;
2923 memset (&key, 0, sizeof (key));
2925 key.constraint = constraint;
2927 g_assert (mono_generic_param_info (par));
2928 /* image might not be set for sre */
2929 if (par->owner && par->owner->image) {
2930 image = par->owner->image;
2932 mono_image_lock (image);
2933 if (!image->gshared_types) {
2934 image->gshared_types_len = MONO_TYPE_INTERNAL;
2935 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
2937 if (!image->gshared_types [constraint->type])
2938 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
2939 res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
2940 mono_image_unlock (image);
2943 copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
2944 memcpy (copy, par, sizeof (MonoGenericParamFull));
2945 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
2946 ((MonoGenericParamFull*)copy)->info.name = mono_image_strdup (image, name);
2949 /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
2950 copy = (MonoGenericParam*)g_new0 (MonoGenericParamFull, 1);
2951 memcpy (copy, par, sizeof (MonoGenericParam));
2955 copy->image = mono_defaults.corlib;
2957 copy->gshared_constraint = constraint;
2958 res = mono_metadata_type_dup (NULL, t);
2959 res->data.generic_param = copy;
2964 dkey = mono_image_alloc0 (image, sizeof (SharedGParam));
2966 dkey->constraint = constraint;
2968 mono_image_lock (image);
2969 /* Duplicates are ok */
2970 g_hash_table_insert (image->gshared_types [constraint->type], dkey, res);
2971 mono_image_unlock (image);
2977 static MonoGenericInst*
2978 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
2981 get_shared_type (MonoType *t, MonoType *type)
2985 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2986 MonoGenericClass *gclass = type->data.generic_class;
2987 MonoGenericContext context;
2990 memset (&context, 0, sizeof (context));
2991 if (gclass->context.class_inst)
2992 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
2993 if (gclass->context.method_inst)
2994 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
2996 k = mono_class_inflate_generic_class (gclass->container_class, &context);
2998 return get_shared_gparam (t, &k->byval_arg);
3001 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)));
3003 /* Create a type variable with a constraint which encodes which types can match it */
3005 if (type->type == MONO_TYPE_VALUETYPE)
3006 ttype = mono_class_enum_basetype (type->data.klass)->type;
3012 memset (&t2, 0, sizeof (t2));
3014 klass = mono_class_from_mono_type (&t2);
3016 return get_shared_gparam (t, &klass->byval_arg);
3021 get_gsharedvt_type (MonoType *t)
3023 /* Use TypeHandle as the constraint type since its a valuetype */
3024 return get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3027 static MonoGenericInst*
3028 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3030 MonoGenericInst *res;
3031 MonoType **type_argv;
3034 type_argv = g_new0 (MonoType*, inst->type_argc);
3035 for (i = 0; i < inst->type_argc; ++i) {
3037 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3038 } 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)) {
3039 g_assert (shared_inst);
3040 type_argv [i] = get_shared_gparam (shared_inst->type_argv [i], &mono_defaults.object_class->byval_arg);
3041 } else if (partial) {
3042 /* These types match the ones in generic_inst_is_sharable () */
3043 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3044 } else if (gsharedvt) {
3045 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3047 type_argv [i] = inst->type_argv [i];
3051 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3057 * mini_get_shared_method_full:
3059 * Return the method which is actually compiled/registered when doing generic sharing.
3060 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3061 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3062 * METHOD can be a non-inflated generic method.
3065 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3068 MonoGenericContext shared_context;
3069 MonoMethod *declaring_method, *res;
3070 gboolean partial = FALSE;
3071 gboolean gsharedvt = FALSE;
3072 MonoGenericContainer *class_container, *method_container = NULL;
3073 MonoGenericContext *context = mono_method_get_context (method);
3074 MonoGenericInst *inst;
3076 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3077 declaring_method = method;
3079 declaring_method = mono_method_get_declaring_generic_method (method);
3082 /* shared_context is the context containing type variables. */
3083 if (declaring_method->is_generic)
3084 shared_context = mono_method_get_generic_container (declaring_method)->context;
3086 shared_context = declaring_method->klass->generic_container->context;
3089 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3091 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3093 class_container = declaring_method->klass->generic_container;
3094 method_container = mono_method_get_generic_container (declaring_method);
3097 * Create the shared context by replacing the ref type arguments with
3098 * type parameters, and keeping the rest.
3101 inst = context->class_inst;
3103 inst = shared_context.class_inst;
3105 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3108 inst = context->method_inst;
3110 inst = shared_context.method_inst;
3112 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3114 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3115 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3121 mini_get_shared_method (MonoMethod *method)
3123 return mini_get_shared_method_full (method, FALSE, FALSE);
3126 #if defined(ENABLE_GSHAREDVT)
3128 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3133 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
3139 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
3145 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
3151 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
3157 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
3163 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3169 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3174 #endif /* !MONOTOUCH */