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));
667 g_assert_not_reached ();
669 /* Not reached, quiet compiler */
674 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
680 case MONO_RGCTX_INFO_STATIC_DATA:
681 case MONO_RGCTX_INFO_KLASS:
682 case MONO_RGCTX_INFO_ELEMENT_KLASS:
683 case MONO_RGCTX_INFO_VTABLE:
684 case MONO_RGCTX_INFO_TYPE:
685 case MONO_RGCTX_INFO_REFLECTION_TYPE:
686 case MONO_RGCTX_INFO_CAST_CACHE:
687 mono_metadata_free_type (info);
694 static MonoRuntimeGenericContextInfoTemplate
695 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
698 class_uninstantiated (MonoClass *class)
700 if (class->generic_class)
701 return class->generic_class->container_class;
706 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
707 gboolean allow_partial)
711 for (i = 0; i < inst->type_argc; ++i) {
712 MonoType *type = inst->type_argv [i];
714 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
717 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
718 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)))
728 * mono_is_partially_sharable_inst:
730 * Return TRUE if INST has ref and non-ref type arguments.
733 mono_is_partially_sharable_inst (MonoGenericInst *inst)
736 gboolean has_refs = FALSE, has_non_refs = FALSE;
738 for (i = 0; i < inst->type_argc; ++i) {
739 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)
745 return has_refs && has_non_refs;
751 * Return the class used to store information when using generic sharing.
754 get_shared_class (MonoClass *class)
757 * FIXME: This conflicts with normal instances. Also, some code in this file
758 * like class_get_rgctx_template_oti treats these as normal generic instances
759 * instead of generic classes.
761 //g_assert_not_reached ();
764 /* The gsharedvt changes break this */
765 if (ALLOW_PARTIAL_SHARING)
766 g_assert_not_reached ();
770 if (class->is_inflated) {
771 MonoGenericContext *context = &class->generic_class->context;
772 MonoGenericContext *container_context;
773 MonoGenericContext shared_context;
774 MonoGenericInst *inst;
775 MonoType **type_argv;
778 inst = context->class_inst;
779 if (mono_is_partially_sharable_inst (inst)) {
780 container_context = &class->generic_class->container_class->generic_container->context;
781 type_argv = g_new0 (MonoType*, inst->type_argc);
782 for (i = 0; i < inst->type_argc; ++i) {
783 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)
784 type_argv [i] = container_context->class_inst->type_argv [i];
786 type_argv [i] = inst->type_argv [i];
789 memset (&shared_context, 0, sizeof (MonoGenericContext));
790 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
793 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
794 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
795 /* Happens for partially shared methods of nono-sharable generic class */
801 // FIXME: Use this in all cases can be problematic wrt domain/assembly unloading
802 return class_uninstantiated (class);
806 * mono_class_get_runtime_generic_context_template:
809 * Looks up or constructs, if necessary, the runtime generic context template for class.
810 * The template is the same for all instantiations of a class.
812 static MonoRuntimeGenericContextTemplate*
813 mono_class_get_runtime_generic_context_template (MonoClass *class)
815 MonoRuntimeGenericContextTemplate *parent_template, *template;
818 class = get_shared_class (class);
821 template = class_lookup_rgctx_template (class);
822 mono_loader_unlock ();
827 //g_assert (get_shared_class (class) == class);
829 template = alloc_template (class);
835 int max_argc, type_argc;
837 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
838 max_argc = template_get_max_argc (parent_template);
840 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
841 num_entries = rgctx_template_num_infos (parent_template, type_argc);
843 /* FIXME: quadratic! */
844 for (i = 0; i < num_entries; ++i) {
845 MonoRuntimeGenericContextInfoTemplate oti;
847 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
848 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
849 rgctx_template_set_slot (class->image, template, type_argc, i,
850 oti.data, oti.info_type);
856 if (class_lookup_rgctx_template (class)) {
857 /* some other thread already set the template */
858 template = class_lookup_rgctx_template (class);
860 class_set_rgctx_template (class, template);
863 register_generic_subclass (class);
866 mono_loader_unlock ();
872 * class_get_rgctx_template_oti:
874 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
875 * temporary signifies whether the inflated info (oti.data) will be
876 * used temporarily, in which case it might be heap-allocated, or
877 * permanently, in which case it will be mempool-allocated. If
878 * temporary is set then *do_free will return whether the returned
879 * data must be freed.
881 * LOCKING: loader lock
883 static MonoRuntimeGenericContextInfoTemplate
884 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
886 g_assert ((temporary && do_free) || (!temporary && !do_free));
888 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
890 if (class->generic_class && !shared) {
891 MonoRuntimeGenericContextInfoTemplate oti;
892 gboolean tmp_do_free;
894 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
895 type_argc, slot, TRUE, FALSE, &tmp_do_free);
897 gpointer info = oti.data;
898 oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
900 free_inflated_info (oti.info_type, info);
907 MonoRuntimeGenericContextTemplate *template;
908 MonoRuntimeGenericContextInfoTemplate *oti;
910 template = mono_class_get_runtime_generic_context_template (class);
911 oti = rgctx_template_get_other_slot (template, type_argc, slot);
922 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
925 case MONO_RGCTX_INFO_STATIC_DATA: {
926 MonoVTable *vtable = mono_class_vtable (domain, class);
928 mono_raise_exception (mono_class_get_exception_for_failure (class));
929 return mono_vtable_get_static_field_data (vtable);
931 case MONO_RGCTX_INFO_KLASS:
933 case MONO_RGCTX_INFO_ELEMENT_KLASS:
934 return class->element_class;
935 case MONO_RGCTX_INFO_VTABLE: {
936 MonoVTable *vtable = mono_class_vtable (domain, class);
938 mono_raise_exception (mono_class_get_exception_for_failure (class));
941 case MONO_RGCTX_INFO_CAST_CACHE: {
942 /*First slot is the cache itself, the second the vtable.*/
943 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
944 cache_data [1] = (gpointer)class;
947 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
948 return GUINT_TO_POINTER (mono_class_array_element_size (class));
949 case MONO_RGCTX_INFO_VALUE_SIZE:
950 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
951 return GUINT_TO_POINTER (sizeof (gpointer));
953 return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
954 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
955 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
956 return GUINT_TO_POINTER (1);
957 else if (mono_class_is_nullable (class))
958 return GUINT_TO_POINTER (2);
960 return GUINT_TO_POINTER (0);
961 case MONO_RGCTX_INFO_MEMCPY:
962 case MONO_RGCTX_INFO_BZERO: {
963 static MonoMethod *memcpy_method [17];
964 static MonoMethod *bzero_method [17];
965 MonoJitDomainInfo *domain_info;
969 domain_info = domain_jit_info (domain);
971 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg)) {
972 size = sizeof (gpointer);
973 align = sizeof (gpointer);
975 size = mono_class_value_size (class, &align);
978 if (size != 1 && size != 2 && size != 4 && size != 8)
983 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
984 if (!memcpy_method [size]) {
989 sprintf (name, "memcpy");
991 sprintf (name, "memcpy_aligned_%d", size);
992 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
994 mono_memory_barrier ();
995 memcpy_method [size] = m;
997 if (!domain_info->memcpy_addr [size]) {
998 gpointer addr = mono_compile_method (memcpy_method [size]);
999 mono_memory_barrier ();
1000 domain_info->memcpy_addr [size] = addr;
1002 return domain_info->memcpy_addr [size];
1004 if (!bzero_method [size]) {
1009 sprintf (name, "bzero");
1011 sprintf (name, "bzero_aligned_%d", size);
1012 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
1014 mono_memory_barrier ();
1015 bzero_method [size] = m;
1017 if (!domain_info->bzero_addr [size]) {
1018 gpointer addr = mono_compile_method (bzero_method [size]);
1019 mono_memory_barrier ();
1020 domain_info->bzero_addr [size] = addr;
1022 return domain_info->bzero_addr [size];
1025 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1026 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1030 MonoGenericContext *ctx;
1032 if (!mono_class_is_nullable (class))
1033 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1036 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1037 method = mono_class_get_method_from_name (class, "Box", 1);
1039 method = mono_class_get_method_from_name (class, "Unbox", 1);
1041 addr = mono_compile_method (method);
1042 // The caller uses the gsharedvt call signature
1043 ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1045 if (mini_jit_info_is_gsharedvt (ji))
1046 return mono_create_static_rgctx_trampoline (method, addr);
1048 MonoGenericSharingContext gsctx;
1049 MonoMethodSignature *sig, *gsig;
1050 MonoMethod *gmethod;
1052 /* Need to add an out wrapper */
1054 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1055 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1056 sig = mono_method_signature (method);
1057 gsig = mono_method_signature (gmethod);
1058 ctx = mono_method_get_context (gmethod);
1059 mini_init_gsctx (NULL, NULL, ctx, &gsctx);
1061 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, &gsctx, -1, FALSE);
1062 addr = mono_create_static_rgctx_trampoline (method, addr);
1067 g_assert_not_reached ();
1074 ji_is_gsharedvt (MonoJitInfo *ji)
1076 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
1077 mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
1084 * Describes the information used to construct a gsharedvt arg trampoline.
1089 gint32 vcall_offset;
1091 MonoMethodSignature *sig, *gsig;
1092 MonoGenericContext gsctx;
1093 } GSharedVtTrampInfo;
1096 tramp_info_hash (gconstpointer key)
1098 GSharedVtTrampInfo *tramp = (gpointer)key;
1100 return (gsize)tramp->addr;
1104 tramp_info_equal (gconstpointer a, gconstpointer b)
1106 GSharedVtTrampInfo *tramp1 = (gpointer)a;
1107 GSharedVtTrampInfo *tramp2 = (gpointer)b;
1109 /* The signatures should be internalized */
1110 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1111 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
1112 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
1116 * mini_get_gsharedvt_wrapper:
1118 * Return a gsharedvt in/out wrapper for calling ADDR.
1121 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
1122 gint32 vcall_offset, gboolean calli)
1124 static gboolean inited = FALSE;
1125 static int num_trampolines;
1127 MonoDomain *domain = mono_domain_get ();
1128 MonoJitDomainInfo *domain_info;
1129 GSharedVtTrampInfo *tramp_info;
1130 GSharedVtTrampInfo tinfo;
1133 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1137 tinfo.is_in = gsharedvt_in;
1138 tinfo.calli = calli;
1139 tinfo.vcall_offset = vcall_offset;
1141 tinfo.sig = normal_sig;
1142 tinfo.gsig = gsharedvt_sig;
1143 memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
1145 domain_info = domain_jit_info (domain);
1148 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1150 mono_domain_lock (domain);
1151 if (!domain_info->gsharedvt_arg_tramp_hash)
1152 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1153 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1154 mono_domain_unlock (domain);
1158 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1161 static gpointer tramp_addr;
1162 MonoMethod *wrapper;
1165 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1166 addr = mono_compile_method (wrapper);
1167 mono_memory_barrier ();
1172 static gpointer tramp_addr;
1173 MonoMethod *wrapper;
1176 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1177 addr = mono_compile_method (wrapper);
1178 mono_memory_barrier ();
1185 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1187 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1192 tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1193 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1195 mono_domain_lock (domain);
1196 /* Duplicates are not a problem */
1197 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1198 mono_domain_unlock (domain);
1204 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1205 MonoGenericContext *context, MonoClass *class, guint8 *caller)
1213 switch (oti->info_type) {
1214 case MONO_RGCTX_INFO_STATIC_DATA:
1215 case MONO_RGCTX_INFO_KLASS:
1216 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1217 case MONO_RGCTX_INFO_VTABLE:
1218 case MONO_RGCTX_INFO_CAST_CACHE:
1225 data = inflate_info (oti, context, class, temporary);
1227 switch (oti->info_type) {
1228 case MONO_RGCTX_INFO_STATIC_DATA:
1229 case MONO_RGCTX_INFO_KLASS:
1230 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1231 case MONO_RGCTX_INFO_VTABLE:
1232 case MONO_RGCTX_INFO_CAST_CACHE:
1233 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1234 case MONO_RGCTX_INFO_VALUE_SIZE:
1235 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1236 case MONO_RGCTX_INFO_MEMCPY:
1237 case MONO_RGCTX_INFO_BZERO:
1238 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1239 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1240 MonoClass *arg_class = mono_class_from_mono_type (data);
1242 free_inflated_info (oti->info_type, data);
1243 g_assert (arg_class);
1245 /* The class might be used as an argument to
1246 mono_value_copy(), which requires that its GC
1247 descriptor has been computed. */
1248 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1249 mono_class_compute_gc_descriptor (arg_class);
1251 return class_type_info (domain, arg_class, oti->info_type);
1253 case MONO_RGCTX_INFO_TYPE:
1255 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1256 return mono_type_get_object (domain, data);
1257 case MONO_RGCTX_INFO_METHOD:
1259 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1262 addr = mono_compile_method (data);
1263 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1265 #ifndef DISABLE_REMOTING
1266 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1267 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1269 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1270 return mono_domain_alloc0 (domain, sizeof (gpointer));
1271 case MONO_RGCTX_INFO_CLASS_FIELD:
1273 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1274 MonoClassField *field = data;
1276 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1277 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1279 return GUINT_TO_POINTER (field->offset);
1281 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1282 MonoMethodInflated *method = data;
1285 g_assert (method->method.method.is_inflated);
1286 g_assert (method->context.method_inst);
1288 vtable = mono_class_vtable (domain, method->method.method.klass);
1290 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1292 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1294 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1295 MonoMethodInflated *method = data;
1297 g_assert (method->method.method.is_inflated);
1298 g_assert (method->context.method_inst);
1300 return method->context.method_inst;
1302 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1303 MonoMethodSignature *gsig = oti->data;
1304 MonoMethodSignature *sig = data;
1306 MonoJitInfo *caller_ji;
1307 MonoGenericJitInfo *gji;
1310 * This is an indirect call to the address passed by the caller in the rgctx reg.
1312 //printf ("CALLI\n");
1315 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1316 g_assert (caller_ji);
1317 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1320 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1324 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1325 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1326 MonoJumpInfoGSharedVtCall *call_info = data;
1327 MonoMethodSignature *call_sig;
1330 MonoJitInfo *caller_ji, *callee_ji;
1331 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1332 gint32 vcall_offset;
1333 MonoGenericJitInfo *gji, *callee_gji = NULL;
1334 gboolean callee_gsharedvt;
1336 /* This is the original generic signature used by the caller */
1337 call_sig = call_info->sig;
1338 /* This is the instantiated method which is called */
1339 method = call_info->method;
1341 g_assert (method->is_inflated);
1344 addr = mono_compile_method (method);
1349 /* Same as in mono_emit_method_call_full () */
1350 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1351 /* See mono_emit_method_call_full () */
1352 /* The gsharedvt trampoline will recognize this constant */
1353 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1354 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1355 guint32 imt_slot = mono_method_get_imt_slot (method);
1356 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1358 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1359 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1366 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1367 g_assert (caller_ji);
1368 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1371 // FIXME: This loads information in the AOT case
1372 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1373 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1374 if (callee_gsharedvt) {
1375 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1376 g_assert (callee_gji);
1380 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1381 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1382 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1383 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1384 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1385 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1386 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1387 * caller -> out trampoline -> in trampoline -> callee
1388 * This is not very efficient, but it is easy to implement.
1390 if (virtual || !callee_gsharedvt) {
1391 MonoMethodSignature *sig, *gsig;
1393 g_assert (method->is_inflated);
1395 sig = mono_method_signature (method);
1398 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1401 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1403 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1405 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1406 } else if (callee_gsharedvt) {
1407 MonoMethodSignature *sig, *gsig;
1410 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1411 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1414 * public void foo<T1> (T1 t1, T t, object o) {}
1416 * class AClass : Base<long> {
1417 * public void bar<T> (T t, long time, object o) {
1421 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1422 * FIXME: Optimize this.
1425 if (call_sig == mono_method_signature (method)) {
1427 sig = mono_method_signature (method);
1428 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1430 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1432 sig = mono_method_signature (method);
1435 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1437 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1443 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1444 MonoGSharedVtMethodInfo *info = data;
1445 MonoGSharedVtMethodRuntimeInfo *res;
1447 int i, offset, align, size;
1450 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1453 for (i = 0; i < info->num_entries; ++i) {
1454 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1456 switch (template->info_type) {
1457 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1460 size = mono_type_size (t, &align);
1462 if (align < sizeof (gpointer))
1463 align = sizeof (gpointer);
1464 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1465 align = 2 * sizeof (gpointer);
1467 // FIXME: Do the same things as alloc_stack_slots
1468 offset += align - 1;
1469 offset &= ~(align - 1);
1470 res->entries [i] = GINT_TO_POINTER (offset);
1474 res->entries [i] = instantiate_info (domain, template, context, class, NULL);
1478 res->locals_size = offset;
1483 g_assert_not_reached ();
1490 * LOCKING: loader lock
1493 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1495 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1496 MonoClass *subclass;
1498 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1500 /* Recurse for all subclasses */
1501 if (generic_subclass_hash)
1502 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1507 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1508 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1510 g_assert (subclass_template);
1512 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1513 g_assert (subclass_oti.data);
1515 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1517 subclass = subclass_template->next_subclass;
1522 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1525 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1526 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1527 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1528 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1529 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1530 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1531 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1532 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1533 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1534 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1535 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1536 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1537 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1538 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1539 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1540 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1541 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1542 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1543 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1544 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1545 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1546 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1547 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1548 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1549 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1550 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1552 return "<UNKNOWN RGCTX INFO TYPE>";
1556 G_GNUC_UNUSED static char*
1557 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1559 switch (info_type) {
1560 case MONO_RGCTX_INFO_VTABLE:
1561 return mono_type_full_name ((MonoType*)data);
1563 return g_strdup_printf ("<%p>", data);
1568 * LOCKING: loader lock
1571 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1574 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1576 MonoRuntimeGenericContextInfoTemplate *oti;
1578 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1583 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)));
1585 /* Mark the slot as used in all parent classes (until we find
1586 a parent class which already has it marked used). */
1587 parent = class->parent;
1588 while (parent != NULL) {
1589 MonoRuntimeGenericContextTemplate *parent_template;
1590 MonoRuntimeGenericContextInfoTemplate *oti;
1592 if (parent->generic_class)
1593 parent = parent->generic_class->container_class;
1595 parent_template = mono_class_get_runtime_generic_context_template (parent);
1596 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1598 if (oti && oti->data)
1601 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1602 MONO_RGCTX_SLOT_USED_MARKER, 0);
1604 parent = parent->parent;
1607 /* Fill in the slot in this class and in all subclasses
1609 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1615 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1617 switch (info_type) {
1618 case MONO_RGCTX_INFO_STATIC_DATA:
1619 case MONO_RGCTX_INFO_KLASS:
1620 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1621 case MONO_RGCTX_INFO_VTABLE:
1622 case MONO_RGCTX_INFO_TYPE:
1623 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1624 case MONO_RGCTX_INFO_CAST_CACHE:
1625 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1626 case MONO_RGCTX_INFO_VALUE_SIZE:
1627 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1628 case MONO_RGCTX_INFO_MEMCPY:
1629 case MONO_RGCTX_INFO_BZERO:
1630 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1631 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1632 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1633 case MONO_RGCTX_INFO_METHOD:
1634 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1635 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1636 case MONO_RGCTX_INFO_CLASS_FIELD:
1637 case MONO_RGCTX_INFO_FIELD_OFFSET:
1638 case MONO_RGCTX_INFO_METHOD_RGCTX:
1639 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1640 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1641 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1642 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1643 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1644 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1645 return data1 == data2;
1647 g_assert_not_reached ();
1654 * mini_rgctx_info_type_to_patch_info_type:
1656 * Return the type of the runtime object referred to by INFO_TYPE.
1659 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1661 switch (info_type) {
1662 case MONO_RGCTX_INFO_STATIC_DATA:
1663 case MONO_RGCTX_INFO_KLASS:
1664 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1665 case MONO_RGCTX_INFO_VTABLE:
1666 case MONO_RGCTX_INFO_TYPE:
1667 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1668 case MONO_RGCTX_INFO_CAST_CACHE:
1669 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1670 case MONO_RGCTX_INFO_VALUE_SIZE:
1671 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1672 case MONO_RGCTX_INFO_MEMCPY:
1673 case MONO_RGCTX_INFO_BZERO:
1674 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1675 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1676 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1677 return MONO_PATCH_INFO_CLASS;
1678 case MONO_RGCTX_INFO_FIELD_OFFSET:
1679 return MONO_PATCH_INFO_FIELD;
1681 g_assert_not_reached ();
1687 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1688 MonoGenericContext *generic_context)
1690 static gboolean inited = FALSE;
1691 static int max_slot = 0;
1693 MonoRuntimeGenericContextTemplate *rgctx_template =
1694 mono_class_get_runtime_generic_context_template (class);
1695 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1698 class = get_shared_class (class);
1700 mono_loader_lock ();
1702 if (info_has_identity (info_type)) {
1703 oti_list = get_info_templates (rgctx_template, type_argc);
1705 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1706 gpointer inflated_data;
1708 if (oti->info_type != info_type || !oti->data)
1711 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1713 if (info_equal (data, inflated_data, info_type)) {
1714 free_inflated_info (info_type, inflated_data);
1715 mono_loader_unlock ();
1718 free_inflated_info (info_type, inflated_data);
1722 /* We haven't found the info */
1723 i = register_info (class, type_argc, data, info_type);
1725 mono_loader_unlock ();
1728 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1738 * mono_method_lookup_or_register_info:
1740 * @in_mrgctx: whether to put the data into the MRGCTX
1741 * @data: the info data
1742 * @info_type: the type of info to register about data
1743 * @generic_context: a generic context
1745 * Looks up and, if necessary, adds information about data/info_type in
1746 * method's or method's class runtime generic context. Returns the
1747 * encoded slot number.
1750 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1751 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1753 MonoClass *class = method->klass;
1754 int type_argc, index;
1757 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1759 g_assert (method->is_inflated && method_inst);
1760 type_argc = method_inst->type_argc;
1761 g_assert (type_argc > 0);
1766 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1768 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1771 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1773 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1777 * mono_class_rgctx_get_array_size:
1778 * @n: The number of the array
1779 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1781 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1782 * number includes the slot for linking and - for MRGCTXs - the two
1783 * slots in the first array for additional information.
1786 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1788 g_assert (n >= 0 && n < 30);
1797 * LOCKING: domain lock
1800 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1802 static gboolean inited = FALSE;
1803 static int rgctx_num_alloced = 0;
1804 static int rgctx_bytes_alloced = 0;
1805 static int mrgctx_num_alloced = 0;
1806 static int mrgctx_bytes_alloced = 0;
1808 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1809 gpointer array = mono_domain_alloc0 (domain, size);
1812 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1813 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1814 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1815 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1820 mrgctx_num_alloced++;
1821 mrgctx_bytes_alloced += size;
1823 rgctx_num_alloced++;
1824 rgctx_bytes_alloced += size;
1831 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1832 MonoGenericInst *method_inst)
1835 int i, first_slot, size;
1836 MonoDomain *domain = class_vtable->domain;
1837 MonoClass *class = class_vtable->klass;
1838 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1839 MonoRuntimeGenericContextInfoTemplate oti;
1840 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1846 mono_domain_lock (domain);
1848 /* First check whether that slot isn't already instantiated.
1849 This might happen because lookup doesn't lock. Allocate
1850 arrays on the way. */
1852 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1854 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1855 for (i = 0; ; ++i) {
1858 if (method_inst && i == 0)
1859 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1863 if (slot < first_slot + size - 1) {
1864 rgctx_index = slot - first_slot + 1 + offset;
1865 info = rgctx [rgctx_index];
1867 mono_domain_unlock (domain);
1872 if (!rgctx [offset + 0])
1873 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1874 rgctx = rgctx [offset + 0];
1875 first_slot += size - 1;
1876 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1879 g_assert (!rgctx [rgctx_index]);
1881 mono_domain_unlock (domain);
1883 oti = class_get_rgctx_template_oti (get_shared_class (class),
1884 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1885 /* This might take the loader lock */
1886 info = instantiate_info (domain, &oti, &context, class, caller);
1890 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1893 /*FIXME We should use CAS here, no need to take a lock.*/
1894 mono_domain_lock (domain);
1896 /* Check whether the slot hasn't been instantiated in the
1898 if (rgctx [rgctx_index])
1899 info = rgctx [rgctx_index];
1901 rgctx [rgctx_index] = info;
1903 mono_domain_unlock (domain);
1906 free_inflated_info (oti.info_type, oti.data);
1912 * mono_class_fill_runtime_generic_context:
1913 * @class_vtable: a vtable
1914 * @caller: caller method address
1915 * @slot: a slot index to be instantiated
1917 * Instantiates a slot in the RGCTX, returning its value.
1920 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1922 static gboolean inited = FALSE;
1923 static int num_alloced = 0;
1925 MonoDomain *domain = class_vtable->domain;
1926 MonoRuntimeGenericContext *rgctx;
1929 mono_domain_lock (domain);
1932 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1936 rgctx = class_vtable->runtime_generic_context;
1938 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1939 class_vtable->runtime_generic_context = rgctx;
1943 mono_domain_unlock (domain);
1945 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1947 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1953 * mono_method_fill_runtime_generic_context:
1954 * @mrgctx: an MRGCTX
1955 * @caller: caller method address
1956 * @slot: a slot index to be instantiated
1958 * Instantiates a slot in the MRGCTX.
1961 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1965 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1966 mrgctx->method_inst);
1972 mrgctx_hash_func (gconstpointer key)
1974 const MonoMethodRuntimeGenericContext *mrgctx = key;
1976 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1980 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1982 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1983 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1985 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1986 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1990 * mono_method_lookup_rgctx:
1991 * @class_vtable: a vtable
1992 * @method_inst: the method inst of a generic method
1994 * Returns the MRGCTX for the generic method(s) with the given
1995 * method_inst of the given class_vtable.
1997 * LOCKING: Take the domain lock.
1999 MonoMethodRuntimeGenericContext*
2000 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2002 MonoDomain *domain = class_vtable->domain;
2003 MonoMethodRuntimeGenericContext *mrgctx;
2004 MonoMethodRuntimeGenericContext key;
2006 g_assert (!class_vtable->klass->generic_container);
2007 g_assert (!method_inst->is_open);
2009 mono_domain_lock (domain);
2010 if (!domain->method_rgctx_hash)
2011 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2013 key.class_vtable = class_vtable;
2014 key.method_inst = method_inst;
2016 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
2021 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2022 mrgctx->class_vtable = class_vtable;
2023 mrgctx->method_inst = method_inst;
2025 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2028 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2029 for (i = 0; i < method_inst->type_argc; ++i)
2030 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2035 mono_domain_unlock (domain);
2043 * mono_generic_context_is_sharable_full:
2044 * @context: a generic context
2046 * Returns whether the generic context is sharable. A generic context
2047 * is sharable iff all of its type arguments are reference type, or some of them have a
2048 * reference type, and ALLOW_PARTIAL is TRUE.
2051 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2052 gboolean allow_type_vars,
2053 gboolean allow_partial)
2055 g_assert (context->class_inst || context->method_inst);
2057 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2060 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2067 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2069 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2073 * mono_method_is_generic_impl:
2076 * Returns whether the method is either generic or part of a generic
2080 mono_method_is_generic_impl (MonoMethod *method)
2082 if (method->is_inflated)
2084 /* We don't treat wrappers as generic code, i.e., we never
2085 apply generic sharing to them. This is especially
2086 important for static rgctx invoke wrappers, which only work
2087 if not compiled with sharing. */
2088 if (method->wrapper_type != MONO_WRAPPER_NONE)
2090 if (method->klass->generic_container)
2096 has_constraints (MonoGenericContainer *container)
2102 g_assert (container->type_argc > 0);
2103 g_assert (container->type_params);
2105 for (i = 0; i < container->type_argc; ++i)
2106 if (container->type_params [i].constraints)
2113 mini_method_is_open (MonoMethod *method)
2115 if (method->is_inflated) {
2116 MonoGenericContext *ctx = mono_method_get_context (method);
2118 if (ctx->class_inst && ctx->class_inst->is_open)
2120 if (ctx->method_inst && ctx->method_inst->is_open)
2126 static G_GNUC_UNUSED gboolean
2127 is_async_state_machine_class (MonoClass *klass)
2129 static MonoClass *iclass;
2130 static gboolean iclass_set;
2135 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2136 mono_memory_barrier ();
2140 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2145 static G_GNUC_UNUSED gboolean
2146 is_async_method (MonoMethod *method)
2148 MonoCustomAttrInfo *cattr;
2149 MonoMethodSignature *sig;
2150 gboolean res = FALSE;
2151 static MonoClass *attr_class;
2152 static gboolean attr_class_set;
2156 if (!attr_class_set) {
2157 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2158 mono_memory_barrier ();
2159 attr_class_set = TRUE;
2162 /* Do less expensive checks first */
2163 sig = mono_method_signature (method);
2164 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2165 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2166 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2167 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2168 cattr = mono_custom_attrs_from_method (method);
2170 if (mono_custom_attrs_has_attr (cattr, attr_class))
2172 mono_custom_attrs_free (cattr);
2179 * mono_method_is_generic_sharable_full:
2181 * @allow_type_vars: whether to regard type variables as reference types
2182 * @allow_partial: whether to allow partial sharing
2183 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2185 * Returns TRUE iff the method is inflated or part of an inflated
2186 * class, its context is sharable and it has no constraints on its
2187 * type parameters. Otherwise returns FALSE.
2190 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2191 gboolean allow_partial, gboolean allow_gsharedvt)
2193 if (!mono_method_is_generic_impl (method))
2196 if (!partial_sharing_supported ())
2197 allow_partial = FALSE;
2199 if (method->klass->image->dynamic)
2201 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2202 * instance_size is 0.
2204 allow_partial = FALSE;
2207 * Generic async methods have an associated state machine class which is a generic struct. This struct
2208 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2209 * of the async method and the state machine class.
2211 if (is_async_state_machine_class (method->klass))
2214 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2215 if (is_async_method (method))
2220 if (method->is_inflated) {
2221 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2222 MonoGenericContext *context = &inflated->context;
2224 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2227 g_assert (inflated->declaring);
2229 if (inflated->declaring->is_generic) {
2230 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2235 if (method->klass->generic_class) {
2236 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2239 g_assert (method->klass->generic_class->container_class &&
2240 method->klass->generic_class->container_class->generic_container);
2242 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2246 if (method->klass->generic_container && !allow_type_vars)
2249 /* This does potentially expensive cattr checks, so do it at the end */
2250 if (is_async_method (method)) {
2251 if (mini_method_is_open (method))
2252 /* The JIT can't compile these without sharing */
2261 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2263 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2267 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2269 if (!mono_class_generic_sharing_enabled (method->klass))
2272 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2275 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2278 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2279 method->klass->valuetype) &&
2280 (method->klass->generic_class || method->klass->generic_container);
2283 static MonoGenericInst*
2284 get_object_generic_inst (int type_argc)
2286 MonoType **type_argv;
2289 type_argv = alloca (sizeof (MonoType*) * type_argc);
2291 for (i = 0; i < type_argc; ++i)
2292 type_argv [i] = &mono_defaults.object_class->byval_arg;
2294 return mono_metadata_get_generic_inst (type_argc, type_argv);
2298 * mono_method_construct_object_context:
2301 * Returns a generic context for method with all type variables for
2302 * class and method instantiated with Object.
2305 mono_method_construct_object_context (MonoMethod *method)
2307 MonoGenericContext object_context;
2309 g_assert (!method->klass->generic_class);
2310 if (method->klass->generic_container) {
2311 int type_argc = method->klass->generic_container->type_argc;
2313 object_context.class_inst = get_object_generic_inst (type_argc);
2315 object_context.class_inst = NULL;
2318 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2319 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2321 object_context.method_inst = get_object_generic_inst (type_argc);
2323 object_context.method_inst = NULL;
2326 g_assert (object_context.class_inst || object_context.method_inst);
2328 return object_context;
2331 static gboolean gshared_supported;
2332 static gboolean gsharedvt_supported;
2335 mono_set_generic_sharing_supported (gboolean supported)
2337 gshared_supported = supported;
2341 mono_set_generic_sharing_vt_supported (gboolean supported)
2343 gsharedvt_supported = supported;
2347 mono_set_partial_sharing_supported (gboolean supported)
2349 partial_supported = supported;
2353 * mono_class_generic_sharing_enabled:
2356 * Returns whether generic sharing is enabled for class.
2358 * This is a stop-gap measure to slowly introduce generic sharing
2359 * until we have all the issues sorted out, at which time this
2360 * function will disappear and generic sharing will always be enabled.
2363 mono_class_generic_sharing_enabled (MonoClass *class)
2365 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2366 static gboolean inited = FALSE;
2371 if (gshared_supported)
2372 generic_sharing = MONO_GENERIC_SHARING_ALL;
2374 generic_sharing = MONO_GENERIC_SHARING_NONE;
2376 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2377 if (strcmp (option, "corlib") == 0)
2378 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2379 else if (strcmp (option, "collections") == 0)
2380 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2381 else if (strcmp (option, "all") == 0)
2382 generic_sharing = MONO_GENERIC_SHARING_ALL;
2383 else if (strcmp (option, "none") == 0)
2384 generic_sharing = MONO_GENERIC_SHARING_NONE;
2386 g_warning ("Unknown generic sharing option `%s'.", option);
2389 if (!gshared_supported)
2390 generic_sharing = MONO_GENERIC_SHARING_NONE;
2395 switch (generic_sharing) {
2396 case MONO_GENERIC_SHARING_NONE:
2398 case MONO_GENERIC_SHARING_ALL:
2400 case MONO_GENERIC_SHARING_CORLIB :
2401 return class->image == mono_defaults.corlib;
2402 case MONO_GENERIC_SHARING_COLLECTIONS:
2403 if (class->image != mono_defaults.corlib)
2405 while (class->nested_in)
2406 class = class->nested_in;
2407 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2409 g_assert_not_reached ();
2415 * mono_get_generic_context_from_code:
2417 * Return the runtime generic context belonging to the method whose native code
2420 MonoGenericSharingContext*
2421 mono_get_generic_context_from_code (guint8 *code)
2423 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2425 g_assert (jit_info);
2427 return mono_jit_info_get_generic_sharing_context (jit_info);
2431 mini_method_get_context (MonoMethod *method)
2433 return mono_method_get_context_general (method, TRUE);
2437 * mono_method_check_context_used:
2440 * Checks whether the method's generic context uses a type variable.
2441 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2442 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2443 * context's class or method instantiation uses type variables.
2446 mono_method_check_context_used (MonoMethod *method)
2448 MonoGenericContext *method_context = mini_method_get_context (method);
2449 int context_used = 0;
2451 if (!method_context) {
2452 /* It might be a method of an array of an open generic type */
2453 if (method->klass->rank)
2454 context_used = mono_class_check_context_used (method->klass);
2456 context_used = mono_generic_context_check_used (method_context);
2457 context_used |= mono_class_check_context_used (method->klass);
2460 return context_used;
2464 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2475 if (inst1->type_argc != inst2->type_argc)
2478 for (i = 0; i < inst1->type_argc; ++i)
2479 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2486 * mono_generic_context_equal_deep:
2487 * @context1: a generic context
2488 * @context2: a generic context
2490 * Returns whether context1's type arguments are equal to context2's
2494 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2496 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2497 generic_inst_equal (context1->method_inst, context2->method_inst);
2501 * mini_class_get_container_class:
2502 * @class: a generic class
2504 * Returns the class's container class, which is the class itself if
2505 * it doesn't have generic_class set.
2508 mini_class_get_container_class (MonoClass *class)
2510 if (class->generic_class)
2511 return class->generic_class->container_class;
2513 g_assert (class->generic_container);
2518 * mini_class_get_context:
2519 * @class: a generic class
2521 * Returns the class's generic context.
2524 mini_class_get_context (MonoClass *class)
2526 if (class->generic_class)
2527 return &class->generic_class->context;
2529 g_assert (class->generic_container);
2530 return &class->generic_container->context;
2534 * mini_get_basic_type_from_generic:
2535 * @gsctx: a generic sharing context
2538 * Returns a closed type corresponding to the possibly open type
2542 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2544 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2546 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2549 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2551 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2552 MonoTypeEnum constraint = type->data.generic_param->gshared_constraint;
2553 /* The gparam serial encodes the type this gparam can represent */
2554 if (constraint == 0) {
2555 return &mono_defaults.object_class->byval_arg;
2560 g_assert (constraint != MONO_TYPE_VALUETYPE);
2561 memset (&t, 0, sizeof (t));
2562 t.type = constraint;
2563 klass = mono_class_from_mono_type (&t);
2564 return &klass->byval_arg;
2567 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2572 * mini_type_get_underlying_type:
2574 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2578 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2580 type = mini_native_type_replace_type (type);
2583 return &mono_defaults.int_class->byval_arg;
2584 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2586 type = mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2587 switch (type->type) {
2588 case MONO_TYPE_BOOLEAN:
2589 return &mono_defaults.byte_class->byval_arg;
2590 case MONO_TYPE_CHAR:
2591 return &mono_defaults.uint16_class->byval_arg;
2598 * mini_type_stack_size:
2599 * @gsctx: a generic sharing context
2601 * @align: Pointer to an int for returning the alignment
2603 * Returns the type's stack size and the alignment in *align. The
2604 * type is allowed to be open.
2607 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2609 gboolean allow_open = TRUE;
2611 // FIXME: Some callers might not pass in a gsctx
2612 //allow_open = gsctx != NULL;
2613 return mono_type_stack_size_internal (t, align, allow_open);
2617 * mini_type_stack_size_full:
2619 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2622 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2627 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2631 //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2634 size = mono_type_native_stack_size (t, align);
2639 size = mini_type_stack_size (gsctx, t, &ialign);
2642 size = mini_type_stack_size (gsctx, t, NULL);
2650 * mono_generic_sharing_init:
2652 * Register the generic sharing counters.
2655 mono_generic_sharing_init (void)
2657 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2661 mono_generic_sharing_cleanup (void)
2663 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2665 if (generic_subclass_hash)
2666 g_hash_table_destroy (generic_subclass_hash);
2670 * mini_type_var_is_vt:
2672 * Return whenever T is a type variable instantiated with a vtype.
2675 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2677 if (type->type == MONO_TYPE_VAR) {
2678 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2682 } else if (type->type == MONO_TYPE_MVAR) {
2683 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2688 g_assert_not_reached ();
2694 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2696 if (cfg->generic_sharing_context)
2697 type = mini_get_underlying_type (cfg, type);
2698 return mono_type_is_reference (type);
2702 * mini_method_get_rgctx:
2704 * Return the RGCTX which needs to be passed to M when it is called.
2707 mini_method_get_rgctx (MonoMethod *m)
2709 if (mini_method_get_context (m)->method_inst)
2710 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2712 return mono_class_vtable (mono_domain_get (), m->klass);
2716 * mini_type_is_vtype:
2718 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2719 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2722 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2724 t = mini_native_type_replace_type (t);
2726 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2730 mini_class_is_generic_sharable (MonoClass *klass)
2732 if (klass->generic_class && is_async_state_machine_class (klass))
2735 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2740 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2742 return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2746 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
2748 if (constraint == MONO_TYPE_VALUETYPE) {
2749 return g_strdup_printf ("%s_GSHAREDVT", name);
2750 } else if (constraint == MONO_TYPE_OBJECT) {
2751 return g_strdup_printf ("%s_REF", name);
2754 char *tname, *tname2, *res;
2756 memset (&t, 0, sizeof (t));
2757 t.type = constraint;
2758 tname = mono_type_full_name (&t);
2759 tname2 = g_utf8_strup (tname, strlen (tname));
2760 res = g_strdup_printf ("%s_%s", name, tname2);
2768 * get_shared_gparam:
2770 * Create an anonymous gparam with a type variable with a constraint which encodes which types can match it.
2773 get_shared_gparam (MonoType *t, MonoTypeEnum constraint)
2775 MonoGenericParam *par = t->data.generic_param;
2776 MonoGenericParam *copy;
2778 MonoImage *image = NULL;
2781 g_assert (mono_generic_param_info (par));
2782 /* image might not be set for sre */
2783 if (par->owner && par->owner->image) {
2784 image = par->owner->image;
2786 mono_image_lock (image);
2787 if (!image->gshared_types) {
2788 image->gshared_types_len = MONO_TYPE_INTERNAL;
2789 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
2791 if (!image->gshared_types [constraint])
2792 image->gshared_types [constraint] = g_hash_table_new (NULL, NULL);
2793 res = g_hash_table_lookup (image->gshared_types [constraint], par);
2794 mono_image_unlock (image);
2797 copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
2798 memcpy (copy, par, sizeof (MonoGenericParamFull));
2799 name = get_shared_gparam_name (constraint, ((MonoGenericParamFull*)copy)->info.name);
2800 ((MonoGenericParamFull*)copy)->info.name = mono_image_strdup (image, name);
2803 /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
2804 copy = (MonoGenericParam*)g_new0 (MonoGenericParamFull, 1);
2805 memcpy (copy, par, sizeof (MonoGenericParam));
2809 copy->image = mono_defaults.corlib;
2810 copy->gshared_constraint = constraint;
2811 res = mono_metadata_type_dup (NULL, t);
2812 res->data.generic_param = copy;
2815 mono_image_lock (image);
2816 /* Duplicates are ok */
2817 g_hash_table_insert (image->gshared_types [constraint], par, res);
2818 mono_image_unlock (image);
2825 get_shared_type (MonoType *t, MonoType *type)
2829 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)));
2831 /* Create a type variable with a constraint which encodes which types can match it */
2833 if (type->type == MONO_TYPE_VALUETYPE)
2834 ttype = mono_class_enum_basetype (type->data.klass)->type;
2835 return get_shared_gparam (t, ttype);
2839 get_gsharedvt_type (MonoType *t)
2841 return get_shared_gparam (t, MONO_TYPE_VALUETYPE);
2844 static MonoGenericInst*
2845 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
2847 MonoGenericInst *res;
2848 MonoType **type_argv;
2851 type_argv = g_new0 (MonoType*, inst->type_argc);
2852 for (i = 0; i < inst->type_argc; ++i) {
2854 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2855 } 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)) {
2856 g_assert (shared_inst);
2857 type_argv [i] = get_shared_gparam (shared_inst->type_argv [i], MONO_TYPE_OBJECT);
2858 } else if (partial) {
2859 /* These types match the ones in generic_inst_is_sharable () */
2860 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
2861 } else if (gsharedvt) {
2862 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2864 type_argv [i] = inst->type_argv [i];
2868 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
2874 * mini_get_shared_method_full:
2876 * Return the method which is actually compiled/registered when doing generic sharing.
2877 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
2878 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
2879 * METHOD can be a non-inflated generic method.
2882 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
2885 MonoGenericContext shared_context;
2886 MonoMethod *declaring_method, *res;
2887 gboolean partial = FALSE;
2888 gboolean gsharedvt = FALSE;
2889 MonoGenericContainer *class_container, *method_container = NULL;
2890 MonoGenericContext *context = mono_method_get_context (method);
2891 MonoGenericInst *inst;
2893 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
2894 declaring_method = method;
2896 declaring_method = mono_method_get_declaring_generic_method (method);
2899 /* shared_context is the context containing type variables. */
2900 if (declaring_method->is_generic)
2901 shared_context = mono_method_get_generic_container (declaring_method)->context;
2903 shared_context = declaring_method->klass->generic_container->context;
2906 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
2908 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
2910 class_container = declaring_method->klass->generic_container;
2911 method_container = mono_method_get_generic_container (declaring_method);
2914 * Create the shared context by replacing the ref type arguments with
2915 * type parameters, and keeping the rest.
2918 inst = context->class_inst;
2920 inst = shared_context.class_inst;
2922 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
2925 inst = context->method_inst;
2927 inst = shared_context.method_inst;
2929 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
2931 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
2932 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2938 mini_get_shared_method (MonoMethod *method)
2940 return mini_get_shared_method_full (method, FALSE, FALSE);
2943 #if defined(ENABLE_GSHAREDVT)
2945 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2950 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2956 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2962 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2968 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2974 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2980 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2986 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2991 #endif /* !MONOTOUCH */