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;
32 static inline gboolean
33 partial_sharing_supported (void)
35 if (!ALLOW_PARTIAL_SHARING)
37 /* Enable this only when AOT compiling or running in full-aot mode */
38 if (partial_supported || mono_aot_only)
44 type_check_context_used (MonoType *type, gboolean recursive)
46 switch (mono_type_get_type (type)) {
48 return MONO_GENERIC_CONTEXT_USED_CLASS;
50 return MONO_GENERIC_CONTEXT_USED_METHOD;
51 case MONO_TYPE_SZARRAY:
52 return mono_class_check_context_used (mono_type_get_class (type));
54 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
57 return mono_class_check_context_used (mono_type_get_class (type));
60 case MONO_TYPE_GENERICINST:
62 MonoGenericClass *gclass = type->data.generic_class;
64 g_assert (gclass->container_class->generic_container);
65 return mono_generic_context_check_used (&gclass->context);
75 inst_check_context_used (MonoGenericInst *inst)
83 for (i = 0; i < inst->type_argc; ++i)
84 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
90 * mono_generic_context_check_used:
91 * @context: a generic context
93 * Checks whether the context uses a type variable. Returns an int
94 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
95 * the context's class instantiation uses type variables.
98 mono_generic_context_check_used (MonoGenericContext *context)
100 int context_used = 0;
102 context_used |= inst_check_context_used (context->class_inst);
103 context_used |= inst_check_context_used (context->method_inst);
109 * mono_class_check_context_used:
112 * Checks whether the class's generic context uses a type variable.
113 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
114 * reflect whether the context's class instantiation uses type
118 mono_class_check_context_used (MonoClass *class)
120 int context_used = 0;
122 context_used |= type_check_context_used (&class->this_arg, FALSE);
123 context_used |= type_check_context_used (&class->byval_arg, FALSE);
125 if (class->generic_class)
126 context_used |= mono_generic_context_check_used (&class->generic_class->context);
127 else if (class->generic_container)
128 context_used |= mono_generic_context_check_used (&class->generic_container->context);
134 * LOCKING: loader lock
136 static MonoRuntimeGenericContextInfoTemplate*
137 get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
139 g_assert (type_argc >= 0);
141 return template->infos;
142 return g_slist_nth_data (template->method_templates, type_argc - 1);
146 * LOCKING: loader lock
149 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
150 MonoRuntimeGenericContextInfoTemplate *oti)
152 g_assert (type_argc >= 0);
154 template->infos = oti;
156 int length = g_slist_length (template->method_templates);
159 /* FIXME: quadratic! */
160 while (length < type_argc) {
161 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
165 list = g_slist_nth (template->method_templates, type_argc - 1);
172 * LOCKING: loader lock
175 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
177 return g_slist_length (template->method_templates);
181 * LOCKING: loader lock
183 static MonoRuntimeGenericContextInfoTemplate*
184 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
187 MonoRuntimeGenericContextInfoTemplate *oti;
189 g_assert (slot >= 0);
191 for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
200 * LOCKING: loader lock
203 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
205 MonoRuntimeGenericContextInfoTemplate *oti;
208 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
214 /* Maps from uninstantiated generic classes to GList's of
215 * uninstantiated generic classes whose parent is the key class or an
216 * instance of the key class.
218 * LOCKING: loader lock
220 static GHashTable *generic_subclass_hash;
223 * LOCKING: templates lock
226 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
228 if (!class->image->rgctx_template_hash)
229 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
231 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
235 * LOCKING: loader lock
237 static MonoRuntimeGenericContextTemplate*
238 class_lookup_rgctx_template (MonoClass *class)
240 MonoRuntimeGenericContextTemplate *template;
242 if (!class->image->rgctx_template_hash)
245 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
251 * LOCKING: loader lock
254 register_generic_subclass (MonoClass *class)
256 MonoClass *parent = class->parent;
258 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
260 g_assert (rgctx_template);
262 if (parent->generic_class)
263 parent = parent->generic_class->container_class;
265 if (!generic_subclass_hash)
266 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
268 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
269 rgctx_template->next_subclass = subclass;
270 g_hash_table_insert (generic_subclass_hash, parent, class);
274 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
278 if (class->image == image) {
279 /* The parent class itself is in the image, so all the
280 subclasses must be in the image, too. If not,
281 we're removing an image containing a class which
282 still has a subclass in another image. */
285 g_assert (subclass->image == image);
286 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
294 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
295 MonoClass *next = subclass_template->next_subclass;
297 if (subclass->image != image) {
298 subclass_template->next_subclass = new_list;
306 g_hash_table_insert (generic_subclass_hash, class, new_list);
310 * mono_class_unregister_image_generic_subclasses:
313 * Removes all classes of the image from the generic subclass hash.
314 * Must be called when an image is unloaded.
317 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
319 GHashTable *old_hash;
321 //g_print ("unregistering image %s\n", image->name);
323 if (!generic_subclass_hash)
328 old_hash = generic_subclass_hash;
329 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
331 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
333 mono_loader_unlock ();
335 g_hash_table_destroy (old_hash);
338 static MonoRuntimeGenericContextTemplate*
339 alloc_template (MonoClass *class)
341 static gboolean inited = FALSE;
342 static int num_allocted = 0;
343 static int num_bytes = 0;
345 int size = sizeof (MonoRuntimeGenericContextTemplate);
348 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
349 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
356 return mono_image_alloc0 (class->image, size);
359 static MonoRuntimeGenericContextInfoTemplate*
360 alloc_oti (MonoImage *image)
362 static gboolean inited = FALSE;
363 static int num_allocted = 0;
364 static int num_bytes = 0;
366 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
369 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
370 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
377 return mono_image_alloc0 (image, size);
380 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
383 * Return true if this info type has the notion of identify.
385 * Some info types expect that each insert results in a new slot been assigned.
388 info_has_identity (MonoRgctxInfoType info_type)
390 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
394 * LOCKING: loader lock
397 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
398 int slot, gpointer data, MonoRgctxInfoType info_type)
400 static gboolean inited = FALSE;
401 static int num_markers = 0;
402 static int num_data = 0;
405 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
406 MonoRuntimeGenericContextInfoTemplate **oti = &list;
409 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
410 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
414 g_assert (slot >= 0);
422 *oti = alloc_oti (image);
426 g_assert (!(*oti)->data);
428 (*oti)->info_type = info_type;
430 set_info_templates (image, template, type_argc, list);
432 if (data == MONO_RGCTX_SLOT_USED_MARKER)
439 * mono_method_get_declaring_generic_method:
440 * @method: an inflated method
442 * Returns an inflated method's declaring method.
445 mono_method_get_declaring_generic_method (MonoMethod *method)
447 MonoMethodInflated *inflated;
449 g_assert (method->is_inflated);
451 inflated = (MonoMethodInflated*)method;
453 return inflated->declaring;
457 * mono_class_get_method_generic:
461 * Given a class and a generic method, which has to be of an
462 * instantiation of the same class that klass is an instantiation of,
463 * returns the corresponding method in klass. Example:
465 * klass is Gen<string>
466 * method is Gen<object>.work<int>
468 * returns: Gen<string>.work<int>
471 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
473 MonoMethod *declaring, *m;
476 if (method->is_inflated)
477 declaring = mono_method_get_declaring_generic_method (method);
482 if (klass->generic_class)
483 m = mono_class_get_inflated_method (klass, declaring);
486 mono_class_setup_methods (klass);
487 if (klass->exception_type)
489 for (i = 0; i < klass->method.count; ++i) {
490 m = klass->methods [i];
493 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
496 if (i >= klass->method.count)
500 if (method != declaring) {
501 MonoGenericContext context;
503 context.class_inst = NULL;
504 context.method_inst = mono_method_get_context (method)->method_inst;
506 m = mono_class_inflate_generic_method (m, &context);
513 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
515 gpointer data = oti->data;
516 MonoRgctxInfoType info_type = oti->info_type;
521 if (data == MONO_RGCTX_SLOT_USED_MARKER)
522 return MONO_RGCTX_SLOT_USED_MARKER;
526 case MONO_RGCTX_INFO_STATIC_DATA:
527 case MONO_RGCTX_INFO_KLASS:
528 case MONO_RGCTX_INFO_VTABLE:
529 case MONO_RGCTX_INFO_TYPE:
530 case MONO_RGCTX_INFO_REFLECTION_TYPE:
531 case MONO_RGCTX_INFO_CAST_CACHE:
532 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
533 case MONO_RGCTX_INFO_VALUE_SIZE:
534 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
535 case MONO_RGCTX_INFO_MEMCPY:
536 case MONO_RGCTX_INFO_BZERO:
537 case MONO_RGCTX_INFO_LOCAL_OFFSET:
538 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
539 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
540 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
541 data, context, &error);
542 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
546 case MONO_RGCTX_INFO_METHOD:
547 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
548 case MONO_RGCTX_INFO_METHOD_RGCTX:
549 case MONO_RGCTX_INFO_METHOD_CONTEXT:
550 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
551 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
552 MonoMethod *method = data;
553 MonoMethod *inflated_method;
554 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
555 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
557 mono_metadata_free_type (inflated_type);
559 mono_class_init (inflated_class);
561 g_assert (!method->wrapper_type);
563 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
564 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
565 inflated_method = mono_method_search_in_array_class (inflated_class,
566 method->name, method->signature);
568 inflated_method = mono_class_inflate_generic_method (method, context);
570 mono_class_init (inflated_method->klass);
571 g_assert (inflated_method->klass == inflated_class);
572 return inflated_method;
574 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
575 MonoGSharedVtMethodInfo *oinfo = data;
576 MonoGSharedVtMethodInfo *res;
577 MonoDomain *domain = mono_domain_get ();
580 res = mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
582 res->nlocals = info->nlocals;
583 res->locals_types = g_new0 (MonoType*, info->nlocals);
584 for (i = 0; i < info->nlocals; ++i)
585 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
587 res->num_entries = oinfo->num_entries;
588 res->entries = mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
589 for (i = 0; i < oinfo->num_entries; ++i) {
590 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
591 MonoRuntimeGenericContextInfoTemplate *template = &res->entries [i];
593 memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
594 template->data = inflate_info (template, context, class, FALSE);
598 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
599 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
600 MonoJumpInfoGSharedVtCall *info = data;
601 MonoMethod *method = info->method;
602 MonoMethod *inflated_method;
603 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
604 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
605 MonoJumpInfoGSharedVtCall *res;
606 MonoDomain *domain = mono_domain_get ();
608 res = mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
609 /* Keep the original signature */
610 res->sig = info->sig;
612 mono_metadata_free_type (inflated_type);
614 mono_class_init (inflated_class);
616 g_assert (!method->wrapper_type);
618 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
619 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
620 inflated_method = mono_method_search_in_array_class (inflated_class,
621 method->name, method->signature);
623 inflated_method = mono_class_inflate_generic_method (method, context);
625 mono_class_init (inflated_method->klass);
626 g_assert (inflated_method->klass == inflated_class);
627 res->method = inflated_method;
632 case MONO_RGCTX_INFO_CLASS_FIELD:
633 case MONO_RGCTX_INFO_FIELD_OFFSET: {
634 MonoClassField *field = data;
635 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
636 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
637 int i = field - field->parent->fields;
638 gpointer dummy = NULL;
640 mono_metadata_free_type (inflated_type);
642 mono_class_get_fields (inflated_class, &dummy);
643 g_assert (inflated_class->fields);
645 return &inflated_class->fields [i];
647 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
648 MonoMethodSignature *sig = data;
649 MonoMethodSignature *isig;
652 isig = mono_inflate_generic_signature (sig, context, &error);
653 g_assert (mono_error_ok (&error));
658 g_assert_not_reached ();
660 /* Not reached, quiet compiler */
665 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
671 case MONO_RGCTX_INFO_STATIC_DATA:
672 case MONO_RGCTX_INFO_KLASS:
673 case MONO_RGCTX_INFO_VTABLE:
674 case MONO_RGCTX_INFO_TYPE:
675 case MONO_RGCTX_INFO_REFLECTION_TYPE:
676 case MONO_RGCTX_INFO_CAST_CACHE:
677 mono_metadata_free_type (info);
684 static MonoRuntimeGenericContextInfoTemplate
685 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
688 class_uninstantiated (MonoClass *class)
690 if (class->generic_class)
691 return class->generic_class->container_class;
696 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
697 gboolean allow_partial)
700 gboolean has_ref = FALSE;
702 for (i = 0; i < inst->type_argc; ++i) {
703 MonoType *type = inst->type_argv [i];
705 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) {
711 * Allow non ref arguments, if there is at least one ref argument
713 * FIXME: Allow more types
715 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)))
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_VTABLE: {
934 MonoVTable *vtable = mono_class_vtable (domain, class);
936 mono_raise_exception (mono_class_get_exception_for_failure (class));
939 case MONO_RGCTX_INFO_CAST_CACHE: {
940 /*First slot is the cache itself, the second the vtable.*/
941 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
942 cache_data [1] = (gpointer)class;
945 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
946 return GUINT_TO_POINTER (mono_class_array_element_size (class));
947 case MONO_RGCTX_INFO_VALUE_SIZE:
948 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
949 return GUINT_TO_POINTER (sizeof (gpointer));
951 return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
952 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
953 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
954 return GUINT_TO_POINTER (1);
955 else if (mono_class_is_nullable (class))
956 return GUINT_TO_POINTER (2);
958 return GUINT_TO_POINTER (0);
959 case MONO_RGCTX_INFO_MEMCPY:
960 case MONO_RGCTX_INFO_BZERO: {
961 static MonoMethod *memcpy_method [17];
962 static MonoMethod *bzero_method [17];
963 MonoJitDomainInfo *domain_info;
967 domain_info = domain_jit_info (domain);
969 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg)) {
970 size = sizeof (gpointer);
971 align = sizeof (gpointer);
973 size = mono_class_value_size (class, &align);
976 if (size != 1 && size != 2 && size != 4 && size != 8)
981 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
982 if (!memcpy_method [size]) {
987 sprintf (name, "memcpy");
989 sprintf (name, "memcpy_aligned_%d", size);
990 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
992 mono_memory_barrier ();
993 memcpy_method [size] = m;
995 if (!domain_info->memcpy_addr [size]) {
996 gpointer addr = mono_compile_method (memcpy_method [size]);
997 mono_memory_barrier ();
998 domain_info->memcpy_addr [size] = addr;
1000 return domain_info->memcpy_addr [size];
1002 if (!bzero_method [size]) {
1007 sprintf (name, "bzero");
1009 sprintf (name, "bzero_aligned_%d", size);
1010 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
1012 mono_memory_barrier ();
1013 bzero_method [size] = m;
1015 if (!domain_info->bzero_addr [size]) {
1016 gpointer addr = mono_compile_method (bzero_method [size]);
1017 mono_memory_barrier ();
1018 domain_info->bzero_addr [size] = addr;
1020 return domain_info->bzero_addr [size];
1023 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1024 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1028 MonoGenericContext *ctx;
1030 if (!mono_class_is_nullable (class))
1031 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1034 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1035 method = mono_class_get_method_from_name (class, "Box", 1);
1037 method = mono_class_get_method_from_name (class, "Unbox", 1);
1039 addr = mono_compile_method (method);
1040 // The caller uses the gsharedvt call signature
1041 ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1043 if (mini_jit_info_is_gsharedvt (ji))
1044 return mono_create_static_rgctx_trampoline (method, addr);
1046 MonoGenericSharingContext gsctx;
1047 MonoMethodSignature *sig, *gsig;
1048 MonoMethod *gmethod;
1050 /* Need to add an out wrapper */
1052 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1053 gmethod = mini_get_shared_method (method);
1054 sig = mono_method_signature (method);
1055 gsig = mono_method_signature (gmethod);
1056 ctx = mono_method_get_context (gmethod);
1057 mini_init_gsctx (NULL, NULL, ctx, &gsctx);
1059 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, &gsctx, -1, FALSE);
1060 addr = mono_create_static_rgctx_trampoline (method, addr);
1065 g_assert_not_reached ();
1072 ji_is_gsharedvt (MonoJitInfo *ji)
1074 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
1075 mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
1082 * Describes the information used to construct a gsharedvt arg trampoline.
1087 gint32 vcall_offset;
1089 MonoMethodSignature *sig, *gsig;
1090 MonoGenericContext gsctx;
1091 } GSharedVtTrampInfo;
1094 tramp_info_hash (gconstpointer key)
1096 GSharedVtTrampInfo *tramp = (gpointer)key;
1098 return (gsize)tramp->addr;
1102 tramp_info_equal (gconstpointer a, gconstpointer b)
1104 GSharedVtTrampInfo *tramp1 = (gpointer)a;
1105 GSharedVtTrampInfo *tramp2 = (gpointer)b;
1107 /* The signatures should be internalized */
1108 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1109 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
1110 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
1114 * mini_get_gsharedvt_wrapper:
1116 * Return a gsharedvt in/out wrapper for calling ADDR.
1119 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
1120 gint32 vcall_offset, gboolean calli)
1122 static gboolean inited = FALSE;
1123 static int num_trampolines;
1125 MonoDomain *domain = mono_domain_get ();
1126 MonoJitDomainInfo *domain_info;
1127 GSharedVtTrampInfo *tramp_info;
1128 GSharedVtTrampInfo tinfo;
1131 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1135 tinfo.is_in = gsharedvt_in;
1136 tinfo.calli = calli;
1137 tinfo.vcall_offset = vcall_offset;
1139 tinfo.sig = normal_sig;
1140 tinfo.gsig = gsharedvt_sig;
1141 memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
1143 domain_info = domain_jit_info (domain);
1146 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1148 mono_domain_lock (domain);
1149 if (!domain_info->gsharedvt_arg_tramp_hash)
1150 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1151 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1152 mono_domain_unlock (domain);
1156 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1159 static gpointer tramp_addr;
1160 MonoMethod *wrapper;
1163 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1164 addr = mono_compile_method (wrapper);
1165 mono_memory_barrier ();
1170 static gpointer tramp_addr;
1171 MonoMethod *wrapper;
1174 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1175 addr = mono_compile_method (wrapper);
1176 mono_memory_barrier ();
1183 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1185 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1190 tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1191 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1193 mono_domain_lock (domain);
1194 /* Duplicates are not a problem */
1195 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1196 mono_domain_unlock (domain);
1202 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1203 MonoGenericContext *context, MonoClass *class, guint8 *caller)
1211 switch (oti->info_type) {
1212 case MONO_RGCTX_INFO_STATIC_DATA:
1213 case MONO_RGCTX_INFO_KLASS:
1214 case MONO_RGCTX_INFO_VTABLE:
1215 case MONO_RGCTX_INFO_CAST_CACHE:
1222 data = inflate_info (oti, context, class, temporary);
1224 switch (oti->info_type) {
1225 case MONO_RGCTX_INFO_STATIC_DATA:
1226 case MONO_RGCTX_INFO_KLASS:
1227 case MONO_RGCTX_INFO_VTABLE:
1228 case MONO_RGCTX_INFO_CAST_CACHE:
1229 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1230 case MONO_RGCTX_INFO_VALUE_SIZE:
1231 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1232 case MONO_RGCTX_INFO_MEMCPY:
1233 case MONO_RGCTX_INFO_BZERO:
1234 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1235 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1236 MonoClass *arg_class = mono_class_from_mono_type (data);
1238 free_inflated_info (oti->info_type, data);
1239 g_assert (arg_class);
1241 /* The class might be used as an argument to
1242 mono_value_copy(), which requires that its GC
1243 descriptor has been computed. */
1244 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1245 mono_class_compute_gc_descriptor (arg_class);
1247 return class_type_info (domain, arg_class, oti->info_type);
1249 case MONO_RGCTX_INFO_TYPE:
1251 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1252 return mono_type_get_object (domain, data);
1253 case MONO_RGCTX_INFO_METHOD:
1255 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1258 addr = mono_compile_method (data);
1259 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1261 #ifndef DISABLE_REMOTING
1262 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1263 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1265 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1266 return mono_domain_alloc0 (domain, sizeof (gpointer));
1267 case MONO_RGCTX_INFO_CLASS_FIELD:
1269 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1270 MonoClassField *field = data;
1272 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1273 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1275 return GUINT_TO_POINTER (field->offset);
1277 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1278 MonoMethodInflated *method = data;
1281 g_assert (method->method.method.is_inflated);
1282 g_assert (method->context.method_inst);
1284 vtable = mono_class_vtable (domain, method->method.method.klass);
1286 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1288 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1290 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1291 MonoMethodInflated *method = data;
1293 g_assert (method->method.method.is_inflated);
1294 g_assert (method->context.method_inst);
1296 return method->context.method_inst;
1298 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1299 MonoMethodSignature *gsig = oti->data;
1300 MonoMethodSignature *sig = data;
1302 MonoJitInfo *caller_ji;
1303 MonoGenericJitInfo *gji;
1306 * This is an indirect call to the address passed by the caller in the rgctx reg.
1308 //printf ("CALLI\n");
1311 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1312 g_assert (caller_ji);
1313 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1316 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1320 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1321 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1322 MonoJumpInfoGSharedVtCall *call_info = data;
1323 MonoMethodSignature *call_sig;
1326 MonoJitInfo *caller_ji, *callee_ji;
1327 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1328 gint32 vcall_offset;
1329 MonoGenericJitInfo *gji, *callee_gji = NULL;
1330 gboolean callee_gsharedvt;
1332 /* This is the original generic signature used by the caller */
1333 call_sig = call_info->sig;
1334 /* This is the instantiated method which is called */
1335 method = call_info->method;
1337 g_assert (method->is_inflated);
1340 addr = mono_compile_method (method);
1345 /* Same as in mono_emit_method_call_full () */
1346 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1347 /* See mono_emit_method_call_full () */
1348 /* The gsharedvt trampoline will recognize this constant */
1349 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1350 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1351 guint32 imt_slot = mono_method_get_imt_slot (method);
1352 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1354 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1355 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1362 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1363 g_assert (caller_ji);
1364 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1367 // FIXME: This loads information in the AOT case
1368 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1369 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1370 if (callee_gsharedvt) {
1371 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1372 g_assert (callee_gji);
1376 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1377 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1378 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1379 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1380 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1381 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1382 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1383 * caller -> out trampoline -> in trampoline -> callee
1384 * This is not very efficient, but it is easy to implement.
1386 if (virtual || !callee_gsharedvt) {
1387 MonoMethodSignature *sig, *gsig;
1389 g_assert (method->is_inflated);
1391 sig = mono_method_signature (method);
1394 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1397 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1399 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1401 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1402 } else if (callee_gsharedvt) {
1403 MonoMethodSignature *sig, *gsig;
1406 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1407 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1410 * public void foo<T1> (T1 t1, T t, object o) {}
1412 * class AClass : Base<long> {
1413 * public void bar<T> (T t, long time, object o) {
1417 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1418 * FIXME: Optimize this.
1421 if (call_sig == mono_method_signature (method)) {
1423 sig = mono_method_signature (method);
1424 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1426 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1428 sig = mono_method_signature (method);
1431 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1433 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1439 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1440 MonoGSharedVtMethodInfo *info = data;
1441 MonoGSharedVtMethodRuntimeInfo *res;
1443 int i, offset, align, size;
1446 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1449 for (i = 0; i < info->num_entries; ++i) {
1450 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1452 switch (template->info_type) {
1453 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1456 size = mono_type_size (t, &align);
1458 if (align < sizeof (gpointer))
1459 align = sizeof (gpointer);
1460 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1461 align = 2 * sizeof (gpointer);
1463 // FIXME: Do the same things as alloc_stack_slots
1464 offset += align - 1;
1465 offset &= ~(align - 1);
1466 res->entries [i] = GINT_TO_POINTER (offset);
1470 res->entries [i] = instantiate_info (domain, template, context, class, NULL);
1474 res->locals_size = offset;
1479 g_assert_not_reached ();
1486 * LOCKING: loader lock
1489 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1491 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1492 MonoClass *subclass;
1494 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1496 /* Recurse for all subclasses */
1497 if (generic_subclass_hash)
1498 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1503 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1504 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1506 g_assert (subclass_template);
1508 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1509 g_assert (subclass_oti.data);
1511 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1513 subclass = subclass_template->next_subclass;
1518 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1521 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1522 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1523 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1524 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1525 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1526 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1527 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1528 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1529 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1530 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1531 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1532 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1533 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1534 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1535 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1536 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1537 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1538 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1539 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1540 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1541 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1542 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1543 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1544 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1545 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1547 return "<UNKNOWN RGCTX INFO TYPE>";
1551 G_GNUC_UNUSED static char*
1552 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1554 switch (info_type) {
1555 case MONO_RGCTX_INFO_VTABLE:
1556 return mono_type_full_name ((MonoType*)data);
1558 return g_strdup_printf ("<%p>", data);
1563 * LOCKING: loader lock
1566 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1569 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1571 MonoRuntimeGenericContextInfoTemplate *oti;
1573 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1578 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)));
1580 /* Mark the slot as used in all parent classes (until we find
1581 a parent class which already has it marked used). */
1582 parent = class->parent;
1583 while (parent != NULL) {
1584 MonoRuntimeGenericContextTemplate *parent_template;
1585 MonoRuntimeGenericContextInfoTemplate *oti;
1587 if (parent->generic_class)
1588 parent = parent->generic_class->container_class;
1590 parent_template = mono_class_get_runtime_generic_context_template (parent);
1591 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1593 if (oti && oti->data)
1596 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1597 MONO_RGCTX_SLOT_USED_MARKER, 0);
1599 parent = parent->parent;
1602 /* Fill in the slot in this class and in all subclasses
1604 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1610 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1612 switch (info_type) {
1613 case MONO_RGCTX_INFO_STATIC_DATA:
1614 case MONO_RGCTX_INFO_KLASS:
1615 case MONO_RGCTX_INFO_VTABLE:
1616 case MONO_RGCTX_INFO_TYPE:
1617 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1618 case MONO_RGCTX_INFO_CAST_CACHE:
1619 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1620 case MONO_RGCTX_INFO_VALUE_SIZE:
1621 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1622 case MONO_RGCTX_INFO_MEMCPY:
1623 case MONO_RGCTX_INFO_BZERO:
1624 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1625 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1626 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1627 case MONO_RGCTX_INFO_METHOD:
1628 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1629 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1630 case MONO_RGCTX_INFO_CLASS_FIELD:
1631 case MONO_RGCTX_INFO_FIELD_OFFSET:
1632 case MONO_RGCTX_INFO_METHOD_RGCTX:
1633 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1634 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1635 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1636 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1637 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1638 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1639 return data1 == data2;
1641 g_assert_not_reached ();
1648 * mini_rgctx_info_type_to_patch_info_type:
1650 * Return the type of the runtime object referred to by INFO_TYPE.
1653 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1655 switch (info_type) {
1656 case MONO_RGCTX_INFO_STATIC_DATA:
1657 case MONO_RGCTX_INFO_KLASS:
1658 case MONO_RGCTX_INFO_VTABLE:
1659 case MONO_RGCTX_INFO_TYPE:
1660 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1661 case MONO_RGCTX_INFO_CAST_CACHE:
1662 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1663 case MONO_RGCTX_INFO_VALUE_SIZE:
1664 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1665 case MONO_RGCTX_INFO_MEMCPY:
1666 case MONO_RGCTX_INFO_BZERO:
1667 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1668 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1669 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1670 return MONO_PATCH_INFO_CLASS;
1671 case MONO_RGCTX_INFO_FIELD_OFFSET:
1672 return MONO_PATCH_INFO_FIELD;
1674 g_assert_not_reached ();
1680 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1681 MonoGenericContext *generic_context)
1683 static gboolean inited = FALSE;
1684 static int max_slot = 0;
1686 MonoRuntimeGenericContextTemplate *rgctx_template =
1687 mono_class_get_runtime_generic_context_template (class);
1688 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1691 class = get_shared_class (class);
1693 mono_loader_lock ();
1695 if (info_has_identity (info_type)) {
1696 oti_list = get_info_templates (rgctx_template, type_argc);
1698 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1699 gpointer inflated_data;
1701 if (oti->info_type != info_type || !oti->data)
1704 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1706 if (info_equal (data, inflated_data, info_type)) {
1707 free_inflated_info (info_type, inflated_data);
1708 mono_loader_unlock ();
1711 free_inflated_info (info_type, inflated_data);
1715 /* We haven't found the info */
1716 i = register_info (class, type_argc, data, info_type);
1718 mono_loader_unlock ();
1721 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1731 * mono_method_lookup_or_register_info:
1733 * @in_mrgctx: whether to put the data into the MRGCTX
1734 * @data: the info data
1735 * @info_type: the type of info to register about data
1736 * @generic_context: a generic context
1738 * Looks up and, if necessary, adds information about data/info_type in
1739 * method's or method's class runtime generic context. Returns the
1740 * encoded slot number.
1743 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1744 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1746 MonoClass *class = method->klass;
1747 int type_argc, index;
1750 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1752 g_assert (method->is_inflated && method_inst);
1753 type_argc = method_inst->type_argc;
1754 g_assert (type_argc > 0);
1759 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1761 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1764 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1766 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1770 * mono_class_rgctx_get_array_size:
1771 * @n: The number of the array
1772 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1774 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1775 * number includes the slot for linking and - for MRGCTXs - the two
1776 * slots in the first array for additional information.
1779 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1781 g_assert (n >= 0 && n < 30);
1790 * LOCKING: domain lock
1793 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1795 static gboolean inited = FALSE;
1796 static int rgctx_num_alloced = 0;
1797 static int rgctx_bytes_alloced = 0;
1798 static int mrgctx_num_alloced = 0;
1799 static int mrgctx_bytes_alloced = 0;
1801 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1802 gpointer array = mono_domain_alloc0 (domain, size);
1805 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1806 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1807 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1808 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1813 mrgctx_num_alloced++;
1814 mrgctx_bytes_alloced += size;
1816 rgctx_num_alloced++;
1817 rgctx_bytes_alloced += size;
1824 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1825 MonoGenericInst *method_inst)
1828 int i, first_slot, size;
1829 MonoDomain *domain = class_vtable->domain;
1830 MonoClass *class = class_vtable->klass;
1831 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1832 MonoRuntimeGenericContextInfoTemplate oti;
1833 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1839 mono_domain_lock (domain);
1841 /* First check whether that slot isn't already instantiated.
1842 This might happen because lookup doesn't lock. Allocate
1843 arrays on the way. */
1845 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1847 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1848 for (i = 0; ; ++i) {
1851 if (method_inst && i == 0)
1852 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1856 if (slot < first_slot + size - 1) {
1857 rgctx_index = slot - first_slot + 1 + offset;
1858 info = rgctx [rgctx_index];
1860 mono_domain_unlock (domain);
1865 if (!rgctx [offset + 0])
1866 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1867 rgctx = rgctx [offset + 0];
1868 first_slot += size - 1;
1869 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1872 g_assert (!rgctx [rgctx_index]);
1874 mono_domain_unlock (domain);
1876 oti = class_get_rgctx_template_oti (get_shared_class (class),
1877 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1878 /* This might take the loader lock */
1879 info = instantiate_info (domain, &oti, &context, class, caller);
1883 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1886 /*FIXME We should use CAS here, no need to take a lock.*/
1887 mono_domain_lock (domain);
1889 /* Check whether the slot hasn't been instantiated in the
1891 if (rgctx [rgctx_index])
1892 info = rgctx [rgctx_index];
1894 rgctx [rgctx_index] = info;
1896 mono_domain_unlock (domain);
1899 free_inflated_info (oti.info_type, oti.data);
1905 * mono_class_fill_runtime_generic_context:
1906 * @class_vtable: a vtable
1907 * @caller: caller method address
1908 * @slot: a slot index to be instantiated
1910 * Instantiates a slot in the RGCTX, returning its value.
1913 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1915 static gboolean inited = FALSE;
1916 static int num_alloced = 0;
1918 MonoDomain *domain = class_vtable->domain;
1919 MonoRuntimeGenericContext *rgctx;
1922 mono_domain_lock (domain);
1925 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1929 rgctx = class_vtable->runtime_generic_context;
1931 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1932 class_vtable->runtime_generic_context = rgctx;
1936 mono_domain_unlock (domain);
1938 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1940 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1946 * mono_method_fill_runtime_generic_context:
1947 * @mrgctx: an MRGCTX
1948 * @caller: caller method address
1949 * @slot: a slot index to be instantiated
1951 * Instantiates a slot in the MRGCTX.
1954 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1958 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1959 mrgctx->method_inst);
1965 mrgctx_hash_func (gconstpointer key)
1967 const MonoMethodRuntimeGenericContext *mrgctx = key;
1969 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1973 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1975 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1976 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1978 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1979 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1983 * mono_method_lookup_rgctx:
1984 * @class_vtable: a vtable
1985 * @method_inst: the method inst of a generic method
1987 * Returns the MRGCTX for the generic method(s) with the given
1988 * method_inst of the given class_vtable.
1990 * LOCKING: Take the domain lock.
1992 MonoMethodRuntimeGenericContext*
1993 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1995 MonoDomain *domain = class_vtable->domain;
1996 MonoMethodRuntimeGenericContext *mrgctx;
1997 MonoMethodRuntimeGenericContext key;
1999 g_assert (!class_vtable->klass->generic_container);
2000 g_assert (!method_inst->is_open);
2002 mono_domain_lock (domain);
2003 if (!domain->method_rgctx_hash)
2004 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2006 key.class_vtable = class_vtable;
2007 key.method_inst = method_inst;
2009 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
2014 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2015 mrgctx->class_vtable = class_vtable;
2016 mrgctx->method_inst = method_inst;
2018 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2021 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2022 for (i = 0; i < method_inst->type_argc; ++i)
2023 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2028 mono_domain_unlock (domain);
2036 * mono_generic_context_is_sharable_full:
2037 * @context: a generic context
2039 * Returns whether the generic context is sharable. A generic context
2040 * is sharable iff all of its type arguments are reference type, or some of them have a
2041 * reference type, and ALLOW_PARTIAL is TRUE.
2044 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2045 gboolean allow_type_vars,
2046 gboolean allow_partial)
2048 g_assert (context->class_inst || context->method_inst);
2050 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2053 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2060 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2062 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2066 * mono_method_is_generic_impl:
2069 * Returns whether the method is either generic or part of a generic
2073 mono_method_is_generic_impl (MonoMethod *method)
2075 if (method->is_inflated)
2077 /* We don't treat wrappers as generic code, i.e., we never
2078 apply generic sharing to them. This is especially
2079 important for static rgctx invoke wrappers, which only work
2080 if not compiled with sharing. */
2081 if (method->wrapper_type != MONO_WRAPPER_NONE)
2083 if (method->klass->generic_container)
2089 has_constraints (MonoGenericContainer *container)
2095 g_assert (container->type_argc > 0);
2096 g_assert (container->type_params);
2098 for (i = 0; i < container->type_argc; ++i)
2099 if (container->type_params [i].constraints)
2106 mini_method_is_open (MonoMethod *method)
2108 if (method->is_inflated) {
2109 MonoGenericContext *ctx = mono_method_get_context (method);
2111 if (ctx->class_inst && ctx->class_inst->is_open)
2113 if (ctx->method_inst && ctx->method_inst->is_open)
2119 static G_GNUC_UNUSED gboolean
2120 is_async_state_machine_class (MonoClass *klass)
2122 static MonoClass *iclass;
2123 static gboolean iclass_set;
2128 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2129 mono_memory_barrier ();
2133 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2138 static G_GNUC_UNUSED gboolean
2139 is_async_method (MonoMethod *method)
2141 MonoCustomAttrInfo *cattr;
2142 MonoMethodSignature *sig;
2143 gboolean res = FALSE;
2144 static MonoClass *attr_class;
2145 static gboolean attr_class_set;
2149 if (!attr_class_set) {
2150 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2151 mono_memory_barrier ();
2152 attr_class_set = TRUE;
2155 /* Do less expensive checks first */
2156 sig = mono_method_signature (method);
2157 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2158 (sig->ret->type == MONO_TYPE_CLASS && (sig->ret->data.generic_class->container_class->name, "Task")) ||
2159 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2160 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2161 cattr = mono_custom_attrs_from_method (method);
2163 if (mono_custom_attrs_has_attr (cattr, attr_class))
2165 mono_custom_attrs_free (cattr);
2172 * mono_method_is_generic_sharable_full:
2174 * @allow_type_vars: whether to regard type variables as reference types
2175 * @allow_partial: whether to allow partial sharing
2176 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2178 * Returns TRUE iff the method is inflated or part of an inflated
2179 * class, its context is sharable and it has no constraints on its
2180 * type parameters. Otherwise returns FALSE.
2183 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2184 gboolean allow_partial, gboolean allow_gsharedvt)
2186 if (!mono_method_is_generic_impl (method))
2189 if (!partial_sharing_supported ())
2190 allow_partial = FALSE;
2193 * Generic async methods have an associated state machine class which is a generic struct. This struct
2194 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2195 * of the async method and the state machine class.
2197 if (is_async_state_machine_class (method->klass))
2200 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2201 if (is_async_method (method))
2206 if (method->is_inflated) {
2207 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2208 MonoGenericContext *context = &inflated->context;
2210 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2213 g_assert (inflated->declaring);
2215 if (inflated->declaring->is_generic) {
2216 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2221 if (method->klass->generic_class) {
2222 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2225 g_assert (method->klass->generic_class->container_class &&
2226 method->klass->generic_class->container_class->generic_container);
2228 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2232 if (method->klass->generic_container && !allow_type_vars)
2235 /* This does potentially expensive cattr checks, so do it at the end */
2236 if (is_async_method (method)) {
2237 if (mini_method_is_open (method))
2238 /* The JIT can't compile these without sharing */
2247 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2249 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2253 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2255 if (!mono_class_generic_sharing_enabled (method->klass))
2258 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2261 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2264 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2265 method->klass->valuetype) &&
2266 (method->klass->generic_class || method->klass->generic_container);
2269 static MonoGenericInst*
2270 get_object_generic_inst (int type_argc)
2272 MonoType **type_argv;
2275 type_argv = alloca (sizeof (MonoType*) * type_argc);
2277 for (i = 0; i < type_argc; ++i)
2278 type_argv [i] = &mono_defaults.object_class->byval_arg;
2280 return mono_metadata_get_generic_inst (type_argc, type_argv);
2284 * mono_method_construct_object_context:
2287 * Returns a generic context for method with all type variables for
2288 * class and method instantiated with Object.
2291 mono_method_construct_object_context (MonoMethod *method)
2293 MonoGenericContext object_context;
2295 g_assert (!method->klass->generic_class);
2296 if (method->klass->generic_container) {
2297 int type_argc = method->klass->generic_container->type_argc;
2299 object_context.class_inst = get_object_generic_inst (type_argc);
2301 object_context.class_inst = NULL;
2304 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2305 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2307 object_context.method_inst = get_object_generic_inst (type_argc);
2309 object_context.method_inst = NULL;
2312 g_assert (object_context.class_inst || object_context.method_inst);
2314 return object_context;
2317 static gboolean gshared_supported;
2318 static gboolean gsharedvt_supported;
2321 mono_set_generic_sharing_supported (gboolean supported)
2323 gshared_supported = supported;
2327 mono_set_generic_sharing_vt_supported (gboolean supported)
2329 gsharedvt_supported = supported;
2333 mono_set_partial_sharing_supported (gboolean supported)
2335 partial_supported = supported;
2339 * mono_class_generic_sharing_enabled:
2342 * Returns whether generic sharing is enabled for class.
2344 * This is a stop-gap measure to slowly introduce generic sharing
2345 * until we have all the issues sorted out, at which time this
2346 * function will disappear and generic sharing will always be enabled.
2349 mono_class_generic_sharing_enabled (MonoClass *class)
2351 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2352 static gboolean inited = FALSE;
2357 if (gshared_supported)
2358 generic_sharing = MONO_GENERIC_SHARING_ALL;
2360 generic_sharing = MONO_GENERIC_SHARING_NONE;
2362 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2363 if (strcmp (option, "corlib") == 0)
2364 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2365 else if (strcmp (option, "collections") == 0)
2366 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2367 else if (strcmp (option, "all") == 0)
2368 generic_sharing = MONO_GENERIC_SHARING_ALL;
2369 else if (strcmp (option, "none") == 0)
2370 generic_sharing = MONO_GENERIC_SHARING_NONE;
2372 g_warning ("Unknown generic sharing option `%s'.", option);
2375 if (!gshared_supported)
2376 generic_sharing = MONO_GENERIC_SHARING_NONE;
2381 switch (generic_sharing) {
2382 case MONO_GENERIC_SHARING_NONE:
2384 case MONO_GENERIC_SHARING_ALL:
2386 case MONO_GENERIC_SHARING_CORLIB :
2387 return class->image == mono_defaults.corlib;
2388 case MONO_GENERIC_SHARING_COLLECTIONS:
2389 if (class->image != mono_defaults.corlib)
2391 while (class->nested_in)
2392 class = class->nested_in;
2393 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2395 g_assert_not_reached ();
2401 * mono_get_generic_context_from_code:
2403 * Return the runtime generic context belonging to the method whose native code
2406 MonoGenericSharingContext*
2407 mono_get_generic_context_from_code (guint8 *code)
2409 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2411 g_assert (jit_info);
2413 return mono_jit_info_get_generic_sharing_context (jit_info);
2417 mini_method_get_context (MonoMethod *method)
2419 return mono_method_get_context_general (method, TRUE);
2423 * mono_method_check_context_used:
2426 * Checks whether the method's generic context uses a type variable.
2427 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2428 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2429 * context's class or method instantiation uses type variables.
2432 mono_method_check_context_used (MonoMethod *method)
2434 MonoGenericContext *method_context = mini_method_get_context (method);
2435 int context_used = 0;
2437 if (!method_context) {
2438 /* It might be a method of an array of an open generic type */
2439 if (method->klass->rank)
2440 context_used = mono_class_check_context_used (method->klass);
2442 context_used = mono_generic_context_check_used (method_context);
2443 context_used |= mono_class_check_context_used (method->klass);
2446 return context_used;
2450 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2461 if (inst1->type_argc != inst2->type_argc)
2464 for (i = 0; i < inst1->type_argc; ++i)
2465 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2472 * mono_generic_context_equal_deep:
2473 * @context1: a generic context
2474 * @context2: a generic context
2476 * Returns whether context1's type arguments are equal to context2's
2480 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2482 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2483 generic_inst_equal (context1->method_inst, context2->method_inst);
2487 * mini_class_get_container_class:
2488 * @class: a generic class
2490 * Returns the class's container class, which is the class itself if
2491 * it doesn't have generic_class set.
2494 mini_class_get_container_class (MonoClass *class)
2496 if (class->generic_class)
2497 return class->generic_class->container_class;
2499 g_assert (class->generic_container);
2504 * mini_class_get_context:
2505 * @class: a generic class
2507 * Returns the class's generic context.
2510 mini_class_get_context (MonoClass *class)
2512 if (class->generic_class)
2513 return &class->generic_class->context;
2515 g_assert (class->generic_container);
2516 return &class->generic_container->context;
2520 * mini_get_basic_type_from_generic:
2521 * @gsctx: a generic sharing context
2524 * Returns a closed type corresponding to the possibly open type
2528 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2530 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2532 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2535 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2538 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2542 * mini_type_get_underlying_type:
2544 * Return the underlying type of TYPE, taking into account enums, byref and generic
2548 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2550 type = mini_native_type_replace_type (type);
2553 return &mono_defaults.int_class->byval_arg;
2554 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2556 return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2560 * mini_type_stack_size:
2561 * @gsctx: a generic sharing context
2563 * @align: Pointer to an int for returning the alignment
2565 * Returns the type's stack size and the alignment in *align. The
2566 * type is allowed to be open.
2569 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2571 gboolean allow_open = TRUE;
2573 // FIXME: Some callers might not pass in a gsctx
2574 //allow_open = gsctx != NULL;
2575 return mono_type_stack_size_internal (t, align, allow_open);
2579 * mini_type_stack_size_full:
2581 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2584 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2589 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2593 //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2596 size = mono_type_native_stack_size (t, align);
2601 size = mini_type_stack_size (gsctx, t, &ialign);
2604 size = mini_type_stack_size (gsctx, t, NULL);
2612 * mono_generic_sharing_init:
2614 * Register the generic sharing counters.
2617 mono_generic_sharing_init (void)
2619 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2623 mono_generic_sharing_cleanup (void)
2625 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2627 if (generic_subclass_hash)
2628 g_hash_table_destroy (generic_subclass_hash);
2632 * mini_type_var_is_vt:
2634 * Return whenever T is a type variable instantiated with a vtype.
2637 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2639 if (type->type == MONO_TYPE_VAR) {
2640 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2644 } else if (type->type == MONO_TYPE_MVAR) {
2645 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2650 g_assert_not_reached ();
2656 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2658 if (mono_type_is_reference (type))
2660 if (!cfg->generic_sharing_context)
2662 /*FIXME the probably needs better handle under partial sharing*/
2663 return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2667 * mini_method_get_rgctx:
2669 * Return the RGCTX which needs to be passed to M when it is called.
2672 mini_method_get_rgctx (MonoMethod *m)
2674 if (mini_method_get_context (m)->method_inst)
2675 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2677 return mono_class_vtable (mono_domain_get (), m->klass);
2681 * mini_type_is_vtype:
2683 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2684 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2687 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2689 t = mini_native_type_replace_type (t);
2691 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2695 mini_class_is_generic_sharable (MonoClass *klass)
2697 if (klass->generic_class && is_async_state_machine_class (klass))
2700 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2705 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2707 return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2710 #if defined(ENABLE_GSHAREDVT)
2712 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2717 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2723 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2729 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2735 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2741 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2747 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2753 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2758 #endif /* !MONOTOUCH */